// Shared SMS provider dispatcher used by server fns + public webhook route.
// Supports multiple BD SMS gateways behind a single `provider` field.

export type SmsSendInput = {
  provider: string;
  baseUrl: string;
  /** TQL Solved: gatewayid · SSL Wireless: sid */
  sid: string;
  /** TQL Solved: password · SSL Wireless: api_token */
  apiToken: string;
  /** TQL Solved: username (email) · others: ignored */
  username?: string;
  phone: string;
  message: string;
  csms_id: string;
};

export type SmsSendResult = {
  ok: boolean;
  status: number;
  body: unknown;
  errorMessage?: string;
};

/** SSL Wireless v3 JSON POST */
async function sendViaSslWireless(o: SmsSendInput): Promise<SmsSendResult> {
  const res = await fetch(o.baseUrl, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({
      api_token: o.apiToken,
      sid: o.sid,
      msisdn: o.phone,
      sms: o.message,
      csms_id: o.csms_id,
    }),
  });
  let body: unknown = null;
  try {
    body = await res.json();
  } catch {
    body = { text: await res.text().catch(() => "") };
  }
  const respBody = body as { status?: string; error_message?: string } | null;
  const ok = res.ok && respBody?.status === "SUCCESS";
  return {
    ok,
    status: res.status,
    body,
    errorMessage: ok ? undefined : respBody?.error_message || `HTTP ${res.status}`,
  };
}

/**
 * TQL Solved (sms.tqlsolved.com) — Laravel SMS broadcasting panel.
 * Endpoint: https://sms.tqlsolved.com/smsapi  (GET or POST)
 * Params:   username (email), password, gatewayid, to (phone), text (message)
 * Success:  response_code === 1005 ("Message sent successfull!")
 * Errors:   1000 missing field · 1001 user not found · 1002 wrong password
 *           1003 gateway not found · 1006 failed · 2000 insufficient balance
 */
const TQL_CODES: Record<number, string> = {
  1000: "All Field is required",
  1001: "Customer email not found",
  1002: "Password is wrong",
  1003: "Gateway not found",
  1005: "Message sent successfully",
  1006: "Message sent failed",
  2000: "Insufficient balance",
};

function buildTqlPayload(o: SmsSendInput) {
  const params = new URLSearchParams();
  params.set("username", (o.username || "").trim());
  params.set("password", o.apiToken.trim());
  params.set("gatewayid", o.sid.trim());
  params.set("to", o.phone.trim());
  params.set("text", o.message);
  return params.toString().replace(/\+/g, "%20");
}

async function parseTqlResponse(res: Response): Promise<SmsSendResult> {
  const text = await res.text().catch(() => "");
  let parsed: { response_code?: number; message?: string } | null = null;
  let body: unknown = text;
  try {
    parsed = JSON.parse(text);
    body = parsed;
  } catch {
    /* keep text */
  }

  const code = parsed?.response_code;
  const ok = res.ok && code === 1005;
  const friendly =
    (code && TQL_CODES[code]) ||
    parsed?.message ||
    (typeof body === "string" ? body.slice(0, 200) : `HTTP ${res.status}`);

  return {
    ok,
    status: res.status,
    body,
    errorMessage: ok ? undefined : friendly,
  };
}

async function sendViaTqlSolved(o: SmsSendInput): Promise<SmsSendResult> {
  const base = o.baseUrl || "https://sms.tqlsolved.com/smsapi";
  const payload = buildTqlPayload(o);

  const postRes = await fetch(base, {
    method: "POST",
    headers: {
      "Content-Type": "application/x-www-form-urlencoded; charset=UTF-8",
    },
    body: payload,
  });
  const postResult = await parseTqlResponse(postRes);
  if (postResult.ok || (postResult.body as { response_code?: number } | null)?.response_code !== 1000) {
    return postResult;
  }

  const getRes = await fetch(`${base}?${payload}`, { method: "GET" });
  return parseTqlResponse(getRes);
}

/** Optional: balance check helper for TQL Solved. */
export async function fetchTqlBalance(
  baseUrl: string,
  username: string,
  password: string,
): Promise<{ ok: boolean; balance?: number; raw: string }> {
  const u = new URL((baseUrl || "https://sms.tqlsolved.com/smsapi").replace(/\/smsapi$/, "/smsbalance"));
  u.searchParams.set("username", username);
  u.searchParams.set("password", password);
  const res = await fetch(u.toString());
  const raw = await res.text().catch(() => "");
  const num = parseFloat(raw);
  return { ok: res.ok && !Number.isNaN(num), balance: Number.isNaN(num) ? undefined : num, raw };
}

export async function dispatchSms(o: SmsSendInput): Promise<SmsSendResult> {
  switch (o.provider) {
    case "tqlsolved":
    case "sendsmsbd":
      return sendViaTqlSolved(o);
    case "ssl_wireless":
    default:
      return sendViaSslWireless(o);
  }
}
