export type AssistantReply={answer:string;mode:'reference'|'openai'|'fallback';sources:{id:string;title:string}[];suggestions:string[]};
export type AssistantConfig={title:string;greeting:string;notice:string;suggestions:string[];support:{url:string|null;phone:string|null}};
export type ChatTurn={id:number;message:string;reply?:AssistantReply;error?:string};
export type ChatHistory={role:'user'|'assistant';content:string}[];
const clip=(text:string)=>Array.from(text).slice(0,1500).join('');

// A browser-side early warning complements the server policy. Obvious secrets
// are never added to bubbles/history or sent to the chat service.
export function obviousChatSecret(text:string):boolean{
 const plain=text.normalize('NFKC').replace(/[۰-۹]/g,d=>String('۰۱۲۳۴۵۶۷۸۹'.indexOf(d))).replace(/[٠-٩]/g,d=>String('٠١٢٣٤٥٦٧٨٩'.indexOf(d))).replace(/[\u200c\u200d]/g,' ');
 return /^(?:0x)?[a-f\d]{64}$/i.test(plain.trim())
  || /(?:private[ _-]?key|کلید\s*خصوصی)\s*(?:من)?\s*[:=]?\s*(?:0x)?[a-f\d]{64}\b/i.test(plain)
  || /(?:رمز(?:\s*(?:عبور|ورود))?|password)(?:\s*من)?\s*[:=]\s*\S{3,}/i.test(plain)
  || /(?:کد\s*(?:ورود|تایید|تأیید|یک\s*بار\s*مصرف)|otp|verification\s*code)[^\d\n]{0,35}\d{4,8}(?!\d)/i.test(plain)
  || /(?:عبارت\s*بازیابی|seed\s*phrase|recovery\s*phrase)(?:\s*من)?\s*[:=]\s*\S+(?:\s+\S+){5,}/i.test(plain);
}

// Only completed turns precede a retry. Neither the greeting nor failed/current
// messages are sent as history, and the source corpus never enters this client.
export function chatHistory(turns:ChatTurn[],beforeId?:number):ChatHistory{
 const before=beforeId===undefined?turns:turns.slice(0,turns.findIndex(t=>t.id===beforeId));
 return before.filter(t=>t.reply).flatMap(t=>[
  {role:'user' as const,content:clip(t.message)},
  {role:'assistant' as const,content:clip(t.reply!.answer)},
 ]).slice(-6);
}
export function parseAssistantReply(raw:unknown):AssistantReply|null{
 if(!raw||typeof raw!=='object')return null;
 const d=raw as AssistantReply;
 if(typeof d.answer!=='string'||!d.answer.trim()||d.answer.length>12000||!['reference','openai','fallback'].includes(d.mode)||!Array.isArray(d.sources)||!Array.isArray(d.suggestions))return null;
 if(d.sources.length>8||d.sources.some(s=>!s||typeof s.id!=='string'||typeof s.title!=='string'||s.id.length>100||s.title.length>1500)||d.suggestions.length>6||d.suggestions.some(s=>typeof s!=='string'||s.length>200))return null;
 return {answer:d.answer,mode:d.mode,sources:d.sources.map(s=>({id:s.id,title:s.title})),suggestions:d.suggestions};
}
export async function requestAssistant(message:string,history:ChatHistory,signal:AbortSignal,fetchImpl:typeof fetch=fetch):Promise<AssistantReply>{
 const response=await fetchImpl('/api/chat',{method:'POST',headers:{'Content-Type':'application/json'},credentials:'omit',cache:'no-store',body:JSON.stringify({message,history}),signal});
 if(!response.ok)throw new Error(response.status===429?'تعداد پرسش‌ها زیاد است؛ کمی صبر کنید و دوباره تلاش کنید.':'پاسخ دریافت نشد. اتصال سرویس را بررسی کنید و دوباره تلاش کنید.');
 const reply=parseAssistantReply(await response.json());
 if(!reply)throw new Error('پاسخ معتبر دریافت نشد. دوباره تلاش کنید.');
 if(reply.mode==='fallback'&&!reply.sources.length)throw new Error('پاسخ مدل موقتاً دریافت نشد. لطفاً دوباره تلاش کنید.');
 return reply;
}
