/** Sends Supabase-generated OTPs using Kavenegar Lookup; no database access. */
import {signedSmsHook,failure,unavailable,limitedText,type SmsOutcome} from './sms-webhook.ts';

type Config={hookSecrets:string;apiKey:string;template:string;allowedPhone:string};
const acceptedStatuses=new Set([1,2,4,5,10]);

export function kavenegarPhone(value:unknown):string|null{
 if(typeof value!=='string'||!/^\+?[1-9]\d{7,14}$/.test(value))return null;
 const digits=value.replace(/^\+/,'');
 return /^989\d{9}$/.test(digits)?'0'+digits.slice(2):'00'+digits;
}

function normalizedRecipient(value:unknown):string|null{
 if(typeof value!=='string'||!/^\+?\d{8,17}$/.test(value))return null;
 if(/^09\d{9}$/.test(value))return value;
 if(/^9\d{9}$/.test(value))return '0'+value;
 return kavenegarPhone(value.startsWith('00')?value.slice(2):value);
}

/** Acceptance is distinct from handset delivery; never expose provider response text. */
export function kavenegarResult(raw:unknown,expectedPhone?:string):SmsOutcome{
 if(!raw||typeof raw!=='object'||Array.isArray(raw))return unavailable();
 const data=raw as {return?:{status?:unknown};entries?:unknown};
 const status=data.return?.status;
 if(status===411)return failure(400,'شماره موبایل برای ارسال پیامک معتبر نیست.');
 if(status===451)return failure(429,'محدودیت ارسال پیامک رسیده است. لطفاً کمی بعد دوباره تلاش کنید.');
 if(status!==200||!Array.isArray(data.entries)||data.entries.length!==1)return unavailable();
 const entry=data.entries[0];
 if(!entry||typeof entry!=='object'||Array.isArray(entry))return unavailable();
 const id=entry.messageid;
 if(typeof id!=='number'&&typeof id!=='string')return unavailable();
 if(typeof id==='number'&&!Number.isSafeInteger(id))return unavailable();
 if(!/^[1-9]\d{0,29}$/.test(String(id))||!acceptedStatuses.has(entry.status))return unavailable();
 if(expectedPhone&&normalizedRecipient(entry.receptor)!==expectedPhone)return unavailable();
 return {ok:true};
}

export function kavenegarSmsHook(config:Config){
 const allowedPhone=kavenegarPhone(config.allowedPhone);
 async function deliver(phone:string,otp:string):Promise<SmsOutcome>{
  try{
   // The provider places API keys in the URL path. Do not log URLs, errors or responses.
   const url=`https://api.kavenegar.com/v1/${encodeURIComponent(config.apiKey)}/verify/lookup.json`;
   const fields=new URLSearchParams({receptor:phone,token:otp,template:config.template,type:'sms'});
   const result=await fetch(url,{method:'POST',redirect:'error',headers:{'Content-Type':'application/x-www-form-urlencoded','Accept':'application/json'},body:fields.toString(),signal:AbortSignal.timeout(3500)});
   const raw=await limitedText(result.body,8192);
   let data:unknown;try{data=JSON.parse(raw)}catch{return unavailable()}
   const outcome=kavenegarResult(data,phone);
   return result.ok?outcome:(outcome.ok?unavailable():outcome);
  }catch{return unavailable()}
 }
 return signedSmsHook({
  hookSecrets:config.hookSecrets,
  configured:!!allowedPhone&&!!config.apiKey&&config.apiKey.length<=512&&!/[\s\u0000-\u001f\u007f]/.test(config.apiKey)&&/^[A-Za-z0-9-]{1,128}$/.test(config.template),
  normalizePhone:value=>{const phone=kavenegarPhone(value);return phone===allowedPhone?phone:null},
  send:deliver
 });
}
