import { PDFDocument } from '@cantoo/pdf-lib';
import { registerFeature } from '../registry';
import { featureModal, pdfSource, footerButtons, deliver, type LoadedFile } from '../common';
import { bufferOf, baseName, readBytes } from '../../core/util';
import { field, textInput } from '../../ui/controls';
import { toast } from '../../ui/toast';
import { pickFiles } from '../../ui/dropzone';
import { icon } from '../../ui/icons';
import { h } from '../../core/dom';

registerFeature({
  id: 'sign-cert',
  title: 'Sign with a certificate',
  desc: 'Apply a real PAdES digital signature using your own .p12/.pfx certificate.',
  icon: 'signature',
  category: 'sign',
  run(ctx) {
    let file: LoadedFile | null = null;
    let cert: { name: string; bytes: Uint8Array } | null = null;

    const m = featureModal(
      'Sign with a certificate',
      'Apply a PAdES digital signature — your certificate never leaves this browser.',
      'signature',
      560,
    );

    const reason = textInput({ placeholder: 'e.g. I approve this document' });
    const name = textInput({ placeholder: 'e.g. Jordan Smith' });
    const location = textInput({ placeholder: 'e.g. London, UK' });
    const contact = textInput({ placeholder: 'e.g. jordan@example.com' });

    const certLabel = h('span.source-file-name', 'No certificate selected yet');
    const pickCertBtn = h(
      'button.btn btn-soft',
      {
        onclick: async () => {
          const picked = await pickFiles('.p12,.pfx', false);
          if (!picked.length) return;
          const f = picked[0];
          if (!/\.(p12|pfx)$/i.test(f.name)) {
            toast('Please choose a .p12 or .pfx certificate file.', { type: 'error' });
            return;
          }
          cert = { name: f.name, bytes: await readBytes(f) };
          certLabel.textContent = f.name;
          updateReady();
        },
      },
      icon('upload', 16),
      'Choose certificate (.p12 / .pfx)',
    ) as HTMLButtonElement;

    const passphrase = h('input.input', {
      type: 'password',
      placeholder: 'Certificate passphrase',
      autocomplete: 'off',
    }) as HTMLInputElement;

    const updateReady = () => {
      primary.disabled = !file || !cert;
    };

    m.body.append(
      pdfSource(ctx, {
        multiple: false,
        onChange: (f) => { file = f[0] ?? null; updateReady(); },
      }),
      field('Certificate', h('div.source-file', h('span.source-file-icon', icon('shield', 16)), certLabel, pickCertBtn),
        'Your .p12/.pfx private-key certificate. It stays on your device.'),
      field('Passphrase', passphrase, 'The password protecting the certificate file.'),
      field('Reason (optional)', reason),
      field('Signed by (optional)', name),
      field('Location (optional)', location),
      field('Contact (optional)', contact),
      h('p.hint',
        'A self-signed certificate will show as “unverified” in Acrobat and other readers. ',
        'A certificate issued to you by a trusted CA will sign as trusted. Either way, ',
        'everything happens locally in your browser — nothing is uploaded.'),
    );

    const { primary } = footerButtons(m, 'Sign & download', async () => {
      if (!file || !cert) return;
      m.setBusy(true, 'Signing…');
      try {
        // Load the signing libraries on demand (they are sizeable and rarely used).
        const [{ pdflibAddPlaceholder }, signpdfMod, { P12Signer }] = await Promise.all([
          import('@signpdf/placeholder-pdf-lib'),
          import('@signpdf/signpdf'),
          import('@signpdf/signer-p12'),
        ]);
        const signpdf = signpdfMod.default;
        const pdfDoc = await PDFDocument.load(bufferOf(file.bytes), { ignoreEncryption: true });
        // pdf-lib and @cantoo/pdf-lib share the same runtime shape; the type
        // signature references upstream pdf-lib, so cast the input narrowly.
        pdflibAddPlaceholder({
          pdfDoc,
          reason: reason.value.trim() || 'Signed with YeetPDF',
          contactInfo: contact.value.trim(),
          name: name.value.trim(),
          location: location.value.trim(),
        } as unknown as Parameters<typeof pdflibAddPlaceholder>[0]);
        const withPlaceholder = await pdfDoc.save({ useObjectStreams: false });

        const signer = new P12Signer(cert.bytes, { passphrase: passphrase.value });
        const signed = await signpdf.sign(withPlaceholder, signer);

        m.close();
        deliver(new Uint8Array(signed), baseName(file.name) + '-signed.pdf');
      } catch (e) {
        m.setBusy(false);
        const msg = String((e as Error)?.message ?? e).toLowerCase();
        if (msg.includes('mac') || msg.includes('password') || msg.includes('passphrase') || msg.includes('invalid')) {
          toast('Could not open the certificate — check the passphrase and file.', { type: 'error' });
        } else {
          toast('Signing failed — the certificate or PDF may be invalid.', { type: 'error' });
        }
        console.error(e);
      }
    }, 'signature');
    primary.disabled = true;
  },
});
