import {env} from './server';
export const TOKENIZATION_BUCKET='tokenization-documents';
export const MAX_TOKENIZATION_FILE=10*1024*1024;
export class TokenizationFileError extends Error {status:number;constructor(message:string,status=400){super(message);this.status=status}}
export async function boundedBytes(body:ReadableStream<Uint8Array>|null,max=MAX_TOKENIZATION_FILE){
 if(!body)throw new TokenizationFileError('فایلی دریافت نشد.');const reader=body.getReader(),chunks:Uint8Array[]=[];let size=0;
 try{while(true){const {done,value}=await reader.read();if(done)break;size+=value.byteLength;if(size>max){await reader.cancel();throw new TokenizationFileError('حجم فایل بیش از حد مجاز است.',413)}chunks.push(value)}}finally{reader.releaseLock()}
 const bytes=new Uint8Array(size);let offset=0;for(const c of chunks){bytes.set(c,offset);offset+=c.byteLength}return bytes;
}
export function tokenizationFileType(bytes:Uint8Array){
 if(bytes.length<12)return null;
 if([137,80,78,71,13,10,26,10].every((n,i)=>bytes[i]===n))return 'image/png';
 if(bytes[0]===255&&bytes[1]===216&&bytes[2]===255)return 'image/jpeg';
 if(new TextDecoder().decode(bytes.slice(0,5))==='%PDF-')return 'application/pdf';return null;
}
// eslint-disable-next-line no-control-regex -- remove unsafe controls from attachment filenames.
export function safeDocumentName(value:string){return value.split(/[\\/]/).at(-1)?.replace(/[\x00-\x1f\x7f]/g,'').slice(0,180).trim()||'document'}
export async function readTokenizationUpload(request:Request){
 const contentType=request.headers.get('content-type')||'';
 if(!/^multipart\/form-data;\s*boundary=/i.test(contentType)||contentType.length>250)throw new TokenizationFileError('مدرک را از فرم بارگذاری ارسال کنید.',415);
 const max=MAX_TOKENIZATION_FILE+32768;if(Number(request.headers.get('content-length'))>max)throw new TokenizationFileError('حداکثر حجم هر مدرک ۱۰ مگابایت است.',413);
 const bytes=await boundedBytes(request.body,max);let form:FormData;
 try{form=await new Response(bytes,{headers:{'Content-Type':contentType}}).formData()}catch{throw new TokenizationFileError('فرم بارگذاری معتبر نیست.')}
 for(const key of form.keys())if(!['id','version','slot','file'].includes(key)||form.getAll(key).length!==1)throw new TokenizationFileError('فرم بارگذاری معتبر نیست.');
 const file=form.get('file');if(!file||typeof file==='string'||!file.size||file.size>MAX_TOKENIZATION_FILE)throw new TokenizationFileError('فایل خالی یا بزرگ‌تر از ۱۰ مگابایت است.',413);
 const data=new Uint8Array(await file.arrayBuffer()),mime=tokenizationFileType(data);if(!mime||file.type!==mime)throw new TokenizationFileError('فقط فایل معتبر PDF، JPG و PNG پذیرفته می‌شود.',415);
 return {id:form.get('id'),version:Number(form.get('version')),slot:form.get('slot'),name:safeDocumentName(file.name),mime,size:data.length,bytes:data};
}
export function tokenizationStorage(path:string,token:string,init:RequestInit={}){
 return fetch(`${env('SUPABASE_URL').replace(/\/$/,'')}/storage/v1/${path}`,{...init,cache:'no-store',signal:AbortSignal.timeout(30000),headers:new Headers([...new Headers(init.headers),['apikey',env('SUPABASE_PUBLISHABLE_KEY')],['Authorization',`Bearer ${token}`]])});
}
export async function tokenizationDocumentResponse(doc:Record<string,unknown>,token:string){
 if(typeof doc.path!=='string'||!/^[-a-f0-9]{36}\/[-a-f0-9]{36}\/[-a-f0-9]{36}\.(pdf|jpg|png)$/.test(doc.path))throw new TokenizationFileError('مدرک یافت نشد.',404);
 const response=await tokenizationStorage(`object/authenticated/${TOKENIZATION_BUCKET}/${doc.path}`,token);
 if(!response.ok)throw new TokenizationFileError('دریافت مدرک انجام نشد.',response.status===404?404:503);
 const bytes=await boundedBytes(response.body),mime=tokenizationFileType(bytes);if(!mime||mime!==doc.mime)throw new TokenizationFileError('فایل مدرک معتبر نیست.',415);
 return new Response(bytes,{headers:{'Content-Type':mime,'Content-Disposition':`attachment; filename*=UTF-8''${encodeURIComponent(safeDocumentName(typeof doc.name==='string'?doc.name:'document'))}`,'Cache-Control':'private, no-store','X-Content-Type-Options':'nosniff','Content-Security-Policy':"default-src 'none'; sandbox",'Cross-Origin-Resource-Policy':'same-origin'}});
}
