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

interface Shot {
  dataUrl: string;
  w: number;
  h: number;
}

registerFeature({
  id: 'scan-to-pdf',
  title: 'Scan to PDF',
  desc: 'Capture pages with your camera and build a PDF.',
  icon: 'camera',
  category: 'organize',
  run() {
    const shots: Shot[] = [];
    let stream: MediaStream | null = null;

    const m = featureModal('Scan to PDF', 'Capture from your camera — the photos never leave your device.', 'camera', 560);

    const video = h('video.scan-video', { autoplay: true, playsinline: true, muted: true }) as HTMLVideoElement;
    const stage = h('div.scan-stage', video);
    const gallery = h('div.scan-gallery');
    const status = h('p.hint', 'Starting camera…');

    const renderGallery = () => {
      gallery.replaceChildren(
        ...shots.map((s, i) =>
          h('div.scan-thumb',
            h('img', { src: s.dataUrl }),
            h('button.scan-thumb-x', { title: 'Remove', onclick: () => { shots.splice(i, 1); renderGallery(); updatePrimary(); } }, '×'),
          ),
        ),
      );
    };

    const capture = () => {
      if (!video.videoWidth) { toast('Camera not ready yet.', { type: 'error' }); return; }
      const c = document.createElement('canvas');
      c.width = video.videoWidth; c.height = video.videoHeight;
      c.getContext('2d')!.drawImage(video, 0, 0);
      shots.push({ dataUrl: c.toDataURL('image/jpeg', 0.85), w: c.width, h: c.height });
      renderGallery();
      updatePrimary();
    };

    const captureBtn = h('button.btn btn-primary', { onclick: capture }, icon('camera', 16), 'Capture page');
    const uploadBtn = h('button.btn btn-ghost', { onclick: addPhotos }, icon('image', 16), 'Add photos');

    async function addPhotos() {
      const files = await pickFiles('image/*', true);
      for (const f of files) {
        const bytes = await readBytes(f);
        const url = URL.createObjectURL(new Blob([bufferOf(bytes)], { type: f.type }));
        await new Promise<void>((res) => {
          const img = new Image();
          img.onload = () => {
            const c = document.createElement('canvas');
            c.width = img.naturalWidth; c.height = img.naturalHeight;
            c.getContext('2d')!.drawImage(img, 0, 0);
            shots.push({ dataUrl: c.toDataURL('image/jpeg', 0.85), w: c.width, h: c.height });
            URL.revokeObjectURL(url); res();
          };
          img.onerror = () => { URL.revokeObjectURL(url); res(); };
          img.src = url;
        });
      }
      renderGallery();
      updatePrimary();
    }

    async function startCamera() {
      try {
        stream = await navigator.mediaDevices.getUserMedia({ video: { facingMode: 'environment' }, audio: false });
        video.srcObject = stream;
        status.textContent = 'Point at a page and press Capture. Add as many as you like.';
      } catch {
        stage.replaceChildren(h('div.scan-nocam', icon('camera', 30), h('p', 'No camera available — add photos from your device instead.')));
        status.textContent = 'Add photos to build your PDF.';
      }
    }

    m.body.append(stage, h('div.scan-controls', captureBtn, uploadBtn), status, gallery);

    const primary = h('button.btn btn-primary', { onclick: build }, icon('download', 16), 'Create PDF') as HTMLButtonElement;
    m.footer.append(h('button.btn btn-soft', { onclick: () => m.close() }, 'Cancel'), primary);
    const updatePrimary = () => { primary.disabled = shots.length === 0; };
    updatePrimary();

    async function build() {
      if (!shots.length) return;
      m.setBusy(true, 'Building PDF…');
      try {
        const doc = await PDFDocument.create();
        for (const s of shots) {
          const bytes = Uint8Array.from(atob(s.dataUrl.split(',')[1]), (ch) => ch.charCodeAt(0));
          const img = await doc.embedJpg(bytes);
          const page = doc.addPage([s.w, s.h]);
          page.drawImage(img, { x: 0, y: 0, width: s.w, height: s.h });
        }
        const out = await doc.save({ useObjectStreams: true });
        cleanup();
        m.close();
        deliver(out, 'scan.pdf');
      } catch (e) {
        m.setBusy(false);
        toast('Could not build the PDF.', { type: 'error' });
        console.error(e);
      }
    }

    function cleanup() { stream?.getTracks().forEach((t) => t.stop()); stream = null; }
    m.onClose(cleanup);
    startCamera();
  },
});
