import type { Template, Schema } from '@pdfme/common';
import type { PdfAssets } from '../shared/pdf';
import { calculateDocument, documentTitles, validateDocument, type BusinessDocument } from './model';
import { inspectLogoDataUrl } from './logo';
import { assertPdfTextSupported } from '../shared/pdf-font';

const FONT = 'NotoSans';
const money = (amount: string, currency: string) => `${currency} ${new Intl.NumberFormat('en-CA', { minimumFractionDigits: 2, maximumFractionDigits: 2 }).format(Number(amount))}`;
const unitPrice = (amount: string, currency: string) => `${currency} ${new Intl.NumberFormat('en-CA', { minimumFractionDigits: 2, maximumFractionDigits: 6 }).format(Number(amount))}`;
export function createDocumentTemplate(data: BusinessDocument, _assets?: PdfAssets): { template: Template; inputs: Record<string, string>[] } {
  const valid = validateDocument(data);
  if (!valid.ok) throw new Error(`Please correct the document before exporting: ${valid.errors[0]?.message}`);
  const width = data.paper === 'A4' ? 210 : 215.9;
  const height = data.paper === 'A4' ? 297 : 279.4;
  const margin = 18; const contentWidth = width - margin * 2;
  const schemas: Schema[] = []; const input: Record<string, string> = {};
  let y = margin;
  const addText = (name: string, value: string, options: { size?: number; color?: string; height?: number; width?: number; gap?: number } = {}) => {
    if (!value.trim()) return;
    const blockHeight = options.height ?? 12;
    schemas.push({ name, type: 'text', position: { x: margin, y }, width: options.width ?? contentWidth, height: blockHeight, fontName: FONT, fontSize: options.size ?? 10, fontColor: options.color ?? '#202020', lineHeight: 1.25, characterSpacing: 0, alignment: 'left', verticalAlignment: 'top', overflow: 'expand', required: false, readOnly: false } as Schema);
    input[name] = value; y += blockHeight + (options.gap ?? 3);
  };
  addText('document_title', documentTitles[data.templateId].toUpperCase(), { size: 24, color: data.accent, height: 13, width: data.logo ? contentWidth - 45 : contentWidth, gap: 5 });
  if (data.logo) {
    const logo = inspectLogoDataUrl(data.logo); const scale = Math.min(35 / logo.width, 18 / logo.height);
    schemas.push({ name: 'company_logo', type: 'image', position: { x: width - margin - logo.width * scale, y: margin }, width: logo.width * scale, height: logo.height * scale, required: false, readOnly: false });
    input.company_logo = data.logo;
  }
  addText('business_name', data.business.name, { size: 15, height: 9 });
  addText('business_contact', data.business.contact, { size: 9, height: 14, color: '#505050', gap: 5 });
  addText('client_details', `PREPARED FOR\n${data.client.name}${data.client.contact ? `\n${data.client.contact}` : ''}`, { height: 22 });
  const dateLabel = data.templateId === 'quotation' ? 'Issued' : data.templateId === 'work-order' ? 'Scheduled' : 'Service date';
  const details = [`${documentTitles[data.templateId]} number: ${data.number}`, `${dateLabel}: ${data.date}`];
  if (data.templateId === 'quotation' && data.validUntil) details.push(`Valid until: ${data.validUntil}`);
  if (data.templateId !== 'quotation' && data.person) details.push(`Assigned to: ${data.person}`);
  if (data.templateId !== 'quotation' && data.location) details.push(`Location: ${data.location}`);
  addText('document_details', details.join('\n'), { size: 9, height: 20, gap: 4 });
  const workLabel = data.templateId === 'service-report' ? 'WORK COMPLETED' : data.templateId === 'work-order' ? 'WORK DESCRIPTION' : 'SCOPE';
  if (data.description) addText('work_description', `${workLabel}\n${data.description}`, { height: 15, gap: 5 });
  const totals = calculateDocument(data);
  if (data.items.length) {
    const priced = data.pricing && totals.pricing;
    const head = priced ? ['Description', 'Qty', 'Unit price', 'Amount'] : ['Description', 'Qty'];
    const rows = data.items.map((item, i) => priced && 'unitPrice' in item ? [item.description, item.quantity, unitPrice(item.unitPrice, data.currency), money(totals.lines[i].total, data.currency)] : [item.description, item.quantity]);
    const borders = { top: 0, right: 0, bottom: 0.15, left: 0 };
    // pdfme 6.1.12 measures table wrapping at the full column width. Keeping
    // horizontal padding at zero makes its measured and painted line widths agree.
    const padding = { top: 3, right: 0, bottom: 3, left: 0 };
    schemas.push({ name: 'line_items', type: 'table', position: { x: margin, y }, width: contentWidth, height: 28, content: '[]', showHead: true, repeatHead: true, head, headWidthPercentages: priced ? [52, 10, 19, 19] : [85, 15], tableStyles: { borderWidth: 0, borderColor: '#d9dfdf' }, headStyles: { fontName: FONT, fontSize: 9, characterSpacing: 0, alignment: 'left', verticalAlignment: 'middle', lineHeight: 1.2, fontColor: '#ffffff', backgroundColor: data.accent, borderColor: data.accent, borderWidth: borders, padding }, bodyStyles: { fontName: FONT, fontSize: 9, characterSpacing: 0, alignment: 'left', verticalAlignment: 'top', lineHeight: 1.25, fontColor: '#202020', backgroundColor: '#ffffff', alternateBackgroundColor: '#f4f6f5', borderColor: '#d9dfdf', borderWidth: borders, padding }, columnStyles: {}, required: false, readOnly: false } as Schema);
    input.line_items = JSON.stringify(rows); y += 33;
  }
  if (totals.pricing) {
    addText('totals', [`Subtotal: ${money(totals.subtotal, totals.currency)}`, `Discount: ${money(totals.discount, totals.currency)}`, `Amount before tax: ${money(totals.taxable, totals.currency)}`, ...totals.taxes.map(t => `${t.name} (${t.rate}%): ${money(t.amount, totals.currency)}`), `TOTAL: ${money(totals.total, totals.currency)}`].join('\n'), { size: 10, height: 29, gap: 6 });
  }
  if (data.templateId === 'service-report') {
    for (const [key, label] of [['findings', 'FINDINGS'], ['recommendations', 'RECOMMENDATIONS'], ['nextSteps', 'NEXT STEPS']] as const) if (data[key]) addText(key, `${label}\n${data[key]}`, { height: 12, gap: 5 });
  }
  if (data.notes) addText('notes', `${data.templateId === 'work-order' ? 'INSTRUCTIONS' : 'NOTES'}\n${data.notes}`, { height: 12, gap: 5 });
  if (data.templateId === 'quotation' && data.terms) addText('terms', `TERMS\n${data.terms}`, { size: 9, color: '#505050', height: 12 });
  return { template: { basePdf: { width, height, padding: [margin, margin, margin, margin] }, schemas: [schemas], pdfmeVersion: '6.1.12' }, inputs: [input] };
}

export async function generateDocumentPdf(data: BusinessDocument, assets: PdfAssets): Promise<Uint8Array> {
  const { template, inputs } = createDocumentTemplate(data, assets);
  await assertPdfTextSupported(Object.entries(inputs[0]).filter(([name]) => name !== 'company_logo').map(([, value]) => value), assets.fontBytes);
  const [{ generate }, { text, table, image }] = await Promise.all([import('@pdfme/generator'), import('@pdfme/schemas')]);
  return generate({ template, inputs, plugins: { text, table, image }, options: { font: { [FONT]: { data: assets.fontBytes.slice().buffer as ArrayBuffer, fallback: true, subset: true } }, lang: 'en' } });
}
