import Docxtemplater from 'docxtemplater';
import { getPizZip } from '@/lib/pizzipClient';
import type { DataRecord } from './templateTypes';
import { RenderError } from './templateTypes';

export { RenderError };

export interface FillOptions {
  preserveLineBreaks?: boolean;
}

function mapDocxtemplaterErrors(err: unknown): RenderError {
  const e = err as { message?: string; properties?: { errors?: Array<{ name?: string; explanation?: string }> } };
  const details =
    e.properties?.errors?.map((x) => ({
      tag: x.name,
      explanation: x.explanation,
    })) ?? [];
  return new RenderError(e.message ?? 'Template render failed', details);
}

/**
 * Merge draft data into a .docx using docxtemplater.
 */
export async function fillTemplate(
  templateBuffer: ArrayBuffer,
  data: DataRecord,
  options: FillOptions = {},
): Promise<Blob> {
  const PizZip = await getPizZip();
  const zip = new PizZip(templateBuffer);
  const doc = new Docxtemplater(zip, {
    paragraphLoop: true,
    linebreaks: options.preserveLineBreaks ?? true,
  });
  try {
    doc.setData(data);
    doc.render();
  } catch (err) {
    throw mapDocxtemplaterErrors(err);
  }
  const out = doc.getZip().generate({
    type: 'arraybuffer',
    compression: 'DEFLATE',
  });
  return new Blob([out], {
    type: 'application/vnd.openxmlformats-officedocument.wordprocessingml.document',
  });
}
