import axios from "axios";
import prisma from "../utils/prisma";

function b(v: string|undefined, name: string): string {
  if (!v) throw new Error(`Variable d'environnement manquante: ${name}`);
  return v;
}

const QS_HOST  = b(process.env.QS_HOST, "QS_HOST");
const QS_PATH  = b(process.env.QS_PATH, "QS_PATH");
const QS_USER  = b(process.env.QS_USER, "QS_USER");
const QS_PSWD  = b(process.env.QS_PSWD, "QS_PSWD");
const QS_SENDER = b(process.env.QS_SENDER ?? process.env.SMS_SENDER_ID, "QS_SENDER/SMS_SENDER_ID");
const QS_DR    = process.env.QS_DR ?? "0";
const QS_CAT   = process.env.QS_MSG_CATEGORY ?? "4.5";
const QS_CT    = process.env.QS_CONTENT_TYPE ?? "3.7";
const QS_CH    = process.env.QS_CHANNEL ?? "2.1";

const SOAP_HOST = b(process.env.SOAP_HOST, "SOAP_HOST");
const SOAP_PATH = b(process.env.SOAP_PATH, "SOAP_PATH");

export type OrangeSendParams = {
  recipient: string;   // E.164: 2126XXXXXXX
  content: string;
  senderId?: string;   // override
  userId?: string;     // journalisation
};

/** Normalise un numéro marocain au format 212XXXXXXXXX */
export function normalizeMorocco(msisdn: string): string {
  let x = msisdn.trim().replace(/[^\d]/g, "");
  if (x.startsWith("0") && x.length === 10) x = "212" + x.slice(1);
  if (x.startsWith("212") && x.length === 12) return x;
  throw new Error(`Numéro invalide: ${msisdn}`);
}

/** Envoi QS (GET) */
export async function sendOrangeQS(p: OrangeSendParams) {
  const recipient = normalizeMorocco(p.recipient);
  const sender = p.senderId ?? QS_SENDER;

  const url = `${QS_HOST}${QS_PATH}`;
  const params = {
    recipient,
    msg: p.content,
    user: QS_USER,
    pswd: QS_PSWD,
    dr: QS_DR,
    msgCategory: QS_CAT,
    contentType: QS_CT,
    sender,
    channel: QS_CH,
  };

  let statusCode: number|undefined, statusText: string|undefined, responseBody: any, errorMessage: string|undefined;

  try {
    const res = await axios.get(url, { params, timeout: 15000 });
    statusCode = res.status;
    statusText = res.statusText;
    responseBody = typeof res.data === "string" ? res.data : JSON.stringify(res.data);
    return { ok: true, statusCode, statusText, responseBody };
  } catch (e: any) {
    statusCode = e?.response?.status;
    statusText = e?.response?.statusText;
    responseBody = e?.response?.data;
    errorMessage = e?.message;
    return { ok: false, statusCode, statusText, responseBody, errorMessage };
  } finally {
    await prisma.smsLog.create({
      data: {
        gateway: "orange-qs",
        senderId: sender,
        recipient,
        content: p.content,
        statusCode: statusCode ?? null,
        statusText: statusText ?? null,
        requestUrl: `${url}`,
        requestBody: JSON.stringify(params),
        responseBody: typeof responseBody === "string" ? responseBody : JSON.stringify(responseBody ?? ""),
        errorMessage: errorMessage ?? null,
        userId: p.userId ?? null,
        meta: {},
      },
    });
  }
}

/** Envoi SOAP (POST XML) */
export async function sendOrangeSOAP(p: OrangeSendParams) {
  const recipient = normalizeMorocco(p.recipient);
  const sender = p.senderId ?? QS_SENDER;

  const url = `${SOAP_HOST}${SOAP_PATH}`;
  const xml =
`<soapenv:Envelope xmlns:soapenv="http://schemas.xmlsoap.org/soap/envelope/" xmlns:sms="http://com/comviva/ngage/ws/sms" xmlns:sms1="http://sms.soap.ngage.comviva.com">
   <soapenv:Header><sms:TransactionID></sms:TransactionID></soapenv:Header>
   <soapenv:Body>
      <sms:SMSSubmitRequest>
         <sms:req>
            <sms1:CampaignName>CCIS Transactionnel</sms1:CampaignName>
            <sms1:CampaignDesc></sms1:CampaignDesc>
            <sms1:Sender>
               <sms1:Username>${QS_USER}</sms1:Username>
               <sms1:Password>${QS_PSWD}</sms1:Password>
               <sms1:Address>${sender}</sms1:Address>
            </sms1:Sender>
            <sms1:ProtocolId></sms1:ProtocolId>
            <sms1:CampaignCategory>4.5</sms1:CampaignCategory>
            <sms1:PromotionalCategory></sms1:PromotionalCategory>
            <sms1:ContentType>3.7</sms1:ContentType>
            <sms1:CallBackURL></sms1:CallBackURL>
            <sms1:ScheduledDeliveryDateTime></sms1:ScheduledDeliveryDateTime>
            <sms1:ValidityPeriodDateTime></sms1:ValidityPeriodDateTime>
            <sms1:DeliveryReport>0</sms1:DeliveryReport>
            <sms1:JobType>
               <sms1:Simple>
                  <sms1:MsgDetails><sms1:ShortMessage>${escapeXml(p.content)}</sms1:ShortMessage></sms1:MsgDetails>
                  <sms1:Recipient><sms1:Number>${recipient}</sms1:Number></sms1:Recipient>
               </sms1:Simple>
            </sms1:JobType>
            <sms1:FixedTPS></sms1:FixedTPS>
         </sms:req>
      </sms:SMSSubmitRequest>
   </soapenv:Body>
</soapenv:Envelope>`;

  function escapeXml(t: string) {
    return t.replace(/&/g,"&amp;").replace(/</g,"&lt;").replace(/>/g,"&gt;");
  }

  let statusCode: number|undefined, statusText: string|undefined, responseBody: any, errorMessage: string|undefined;

  try {
    const res = await axios.post(url, xml, {
      headers: { "Content-Type": "text/xml;charset=UTF-8" },
      timeout: 20000,
    });
    statusCode = res.status;
    statusText = res.statusText;
    responseBody = typeof res.data === "string" ? res.data : JSON.stringify(res.data);
    return { ok: true, statusCode, statusText, responseBody };
  } catch (e: any) {
    statusCode = e?.response?.status;
    statusText = e?.response?.statusText;
    responseBody = e?.response?.data;
    errorMessage = e?.message;
    return { ok: false, statusCode, statusText, responseBody, errorMessage };
  } finally {
    await prisma.smsLog.create({
      data: {
        gateway: "orange-soap",
        senderId: sender,
        recipient,
        content: p.content,
        statusCode: statusCode ?? null,
        statusText: statusText ?? null,
        requestUrl: url,
        requestBody: xml,
        responseBody: typeof responseBody === "string" ? responseBody : JSON.stringify(responseBody ?? ""),
        errorMessage: errorMessage ?? null,
        userId: p.userId ?? null,
        meta: {},
      },
    });
  }
}
