/**
 * bdapps subscription + OTP client.
 *
 * bdapps itself performs the daily charge (5.56 BDT/day). Our job is only to
 * verify a phone number via OTP and flip the subscriber to REGISTERED.
 *
 * Every function short-circuits in DEMO_MODE so the whole flow is testable
 * without real credentials.
 *
 * Server-only.
 */
import { env, canUseBdapps } from './env';
import { upsertSubscription } from './repo';

const BASE = () => env.bdappsBaseUrl;

export interface RequestOtpResult {
  ok: boolean;
  referenceNo?: string;
  statusCode?: string;
  error?: string; // human-readable Bangla message
}

export interface VerifyOtpResult {
  ok: boolean;
  subscriptionStatus?: string;
  subscriberId?: string;
  statusCode?: string;
  error?: string;
}

export interface StatusResult {
  ok: boolean;
  subscriptionStatus?: 'REGISTERED' | 'UNREGISTERED';
  statusCode?: string;
  error?: string;
}

/** Normalise a local phone (01XXXXXXXXX) to bdapps subscriberId form. */
export function toSubscriberId(phone: string): string {
  const digits = phone.replace(/\D/g, '');
  // 01XXXXXXXXX -> 8801XXXXXXXXX
  const intl = digits.startsWith('880')
    ? digits
    : digits.startsWith('0')
      ? `88${digits}`
      : `880${digits}`;
  return `tel:${intl}`;
}

const OTP_ERRORS: Record<string, string> = {
  E1853: 'অনেকবার চেষ্টা হয়েছে, একটু পরে আবার চেষ্টা করো।',
  E1856: 'নাম্বারটা সঠিক নয়, আবার দেখে দাও।',
  E1857: 'সার্ভারে সমস্যা হচ্ছে, একটু পরে চেষ্টা করো।',
  E1850: 'OTP টা ভুল হয়েছে, আবার দাও।',
  E1851: 'OTP-এর মেয়াদ শেষ, নতুন করে পাঠাও।',
  E1852: 'অনেকবার ভুল হয়েছে, নতুন OTP নাও।',
  E1854: 'ভেরিফাই করা গেল না, আবার চেষ্টা করো।',
  E1855: 'কিছু একটা সমস্যা হয়েছে, আবার চেষ্টা করো।',
};

async function post(pathName: string, body: Record<string, unknown>) {
  const res = await fetch(`${BASE()}${pathName}`, {
    method: 'POST',
    headers: { 'Content-Type': 'application/json' },
    body: JSON.stringify(body),
    cache: 'no-store',
  });
  const text = await res.text();
  try {
    return { httpOk: res.ok, json: JSON.parse(text) as Record<string, any> };
  } catch {
    return { httpOk: res.ok, json: {} as Record<string, any> };
  }
}

/** POST /otp/request */
export async function requestOtp(phone: string): Promise<RequestOtpResult> {
  const subscriberId = toSubscriberId(phone);

  if (!canUseBdapps()) {
    // DEMO: pretend an OTP was sent; any 6-digit will verify later.
    const referenceNo = `demo-${Date.now()}`;
    return { ok: true, referenceNo, statusCode: 'S1000' };
  }

  const { json } = await post('/otp/request', {
    applicationId: env.bdappsAppId,
    password: env.bdappsPassword,
    subscriberId,
  });

  if (json.statusCode === 'S1000' && json.referenceNo) {
    return { ok: true, referenceNo: json.referenceNo, statusCode: json.statusCode };
  }
  return {
    ok: false,
    statusCode: json.statusCode,
    error: OTP_ERRORS[json.statusCode] ?? 'OTP পাঠানো গেল না, আবার চেষ্টা করো।',
  };
}

/** POST /otp/verify */
export async function verifyOtp(
  referenceNo: string,
  otp: string,
  phone?: string,
): Promise<VerifyOtpResult> {
  if (!canUseBdapps()) {
    // DEMO: accept any 6-digit OTP.
    if (!/^\d{6}$/.test(otp)) {
      return { ok: false, error: 'OTP অবশ্যই ৬ ডিজিটের হতে হবে।' };
    }
    const subscriberId = phone ? toSubscriberId(phone) : 'tel:8801700000000';
    upsertSubscription(subscriberId, 'REGISTERED', phone);
    return { ok: true, subscriptionStatus: 'REGISTERED', subscriberId };
  }

  const { json } = await post('/otp/verify', {
    applicationId: env.bdappsAppId,
    password: env.bdappsPassword,
    referenceNo,
    otp,
  });

  if (json.statusCode === 'S1000' && json.subscriptionStatus === 'REGISTERED') {
    // bdapps returns a MASKED subscriberId here; store it as the key AND keep
    // the phone so re-login (which only has the phone) can find this row.
    const subscriberId = json.subscriberId ?? (phone ? toSubscriberId(phone) : undefined);
    if (subscriberId) upsertSubscription(subscriberId, 'REGISTERED', phone);
    return {
      ok: true,
      subscriptionStatus: 'REGISTERED',
      subscriberId,
      statusCode: json.statusCode,
    };
  }
  return {
    ok: false,
    statusCode: json.statusCode,
    error: OTP_ERRORS[json.statusCode] ?? 'OTP ভেরিফাই করা গেল না।',
  };
}

/** POST /subscription/getStatus */
export async function getSubscriptionStatus(subscriberId: string): Promise<StatusResult> {
  if (!canUseBdapps()) {
    // DEMO: always registered.
    return { ok: true, subscriptionStatus: 'REGISTERED', statusCode: 'S1000' };
  }

  const { json } = await post('/subscription/getStatus', {
    applicationId: env.bdappsAppId,
    password: env.bdappsPassword,
    subscriberId,
  });

  if (json.statusCode === 'S1000') {
    const status = json.subscriptionStatus === 'REGISTERED' ? 'REGISTERED' : 'UNREGISTERED';
    upsertSubscription(subscriberId, status);
    return { ok: true, subscriptionStatus: status, statusCode: json.statusCode };
  }
  return { ok: false, statusCode: json.statusCode, error: 'স্ট্যাটাস আনা গেল না।' };
}

/** POST /subscription/send with action:0 (unsubscribe). */
export async function unsubscribeUser(subscriberId: string): Promise<StatusResult> {
  if (!canUseBdapps()) {
    // DEMO: just flip local status, no external call.
    upsertSubscription(subscriberId, 'UNREGISTERED');
    return { ok: true, subscriptionStatus: 'UNREGISTERED', statusCode: 'S1000' };
  }

  const { json } = await post('/subscription/send', {
    applicationId: env.bdappsAppId,
    password: env.bdappsPassword,
    subscriberId,
    action: 0,
  });

  if (json.statusCode === 'S1000') {
    upsertSubscription(subscriberId, 'UNREGISTERED');
    return { ok: true, subscriptionStatus: 'UNREGISTERED', statusCode: json.statusCode };
  }
  return { ok: false, statusCode: json.statusCode, error: 'আনসাবস্ক্রাইব করা গেল না।' };
}
