import { PDFDocument, StandardFonts, rgb } from '@cantoo/pdf-lib';
import { registerFeature } from '../registry';
import { featureModal, pdfSource, footerButtons, deliver, type LoadedFile } from '../common';
import { bufferOf, baseName } from '../../core/util';
import { field, numberInput, select, segmented } from '../../ui/controls';
import { toast } from '../../ui/toast';
import { h } from '../../core/dom';

type Position = 'bc' | 'br' | 'bl' | 'tc' | 'tr' | 'tl';
type Format = 'plain' | 'slash' | 'full';

registerFeature({
  id: 'page-numbers',
  title: 'Add page numbers',
  desc: 'Stamp page numbers onto every page.',
  icon: 'numbers',
  category: 'organize',
  run(ctx) {
    let file: LoadedFile | null = null;
    let position: Position = 'bc';
    let format: Format = 'plain';
    let startNumber = 1;
    let fontSize = 11;
    let margin = 28;

    const m = featureModal('Add page numbers', 'Stamp page numbers onto every page — nothing is uploaded.', 'numbers', 560);

    m.body.append(
      pdfSource(ctx, { multiple: false, onChange: (f) => { file = f[0] ?? null; primary.disabled = !file; } }),
      field(
        'Position',
        segmented({
          options: [
            { value: 'bc', label: 'Bottom center' },
            { value: 'br', label: 'Bottom right' },
            { value: 'bl', label: 'Bottom left' },
            { value: 'tc', label: 'Top center' },
            { value: 'tr', label: 'Top right' },
            { value: 'tl', label: 'Top left' },
          ],
          value: position,
          onchange: (v) => { position = v as Position; },
        }),
      ),
      field(
        'Format',
        select({
          options: [
            { value: 'plain', label: '1' },
            { value: 'slash', label: '1 / N' },
            { value: 'full', label: 'Page 1 of N' },
          ],
          value: format,
          onchange: (v) => { format = v as Format; },
        }),
      ),
      h('div.row-2',
        field('Start number', numberInput({ value: startNumber, min: 0, step: 1, onchange: (v) => { if (Number.isFinite(v)) startNumber = Math.round(v); } })),
        field('Font size', numberInput({ value: fontSize, min: 4, max: 96, step: 1, onchange: (v) => { if (Number.isFinite(v)) fontSize = v; } })),
      ),
      field('Margin (points)', numberInput({ value: margin, min: 0, max: 200, step: 1, onchange: (v) => { if (Number.isFinite(v)) margin = v; } })),
    );

    const label = (n: number, total: number): string => {
      if (format === 'slash') return `${n} / ${total}`;
      if (format === 'full') return `Page ${n} of ${total}`;
      return String(n);
    };

    const { primary } = footerButtons(m, 'Add numbers & download', async () => {
      if (!file) return;
      m.setBusy(true, 'Numbering pages…');
      try {
        const doc = await PDFDocument.load(bufferOf(file.bytes), { ignoreEncryption: true });
        const font = await doc.embedFont(StandardFonts.Helvetica);
        const pages = doc.getPages();
        const total = pages.length;
        const color = rgb(0.2, 0.2, 0.25);

        pages.forEach((page, i) => {
          const text = label(startNumber + i, total);
          const { width, height } = page.getSize();
          const textWidth = font.widthOfTextAtSize(text, fontSize);
          const isTop = position === 'tc' || position === 'tr' || position === 'tl';
          const isCenter = position === 'bc' || position === 'tc';
          const isRight = position === 'br' || position === 'tr';

          let x: number;
          if (isCenter) x = (width - textWidth) / 2;
          else if (isRight) x = width - margin - textWidth;
          else x = margin;

          // y is the text baseline (bottom-left origin)
          const y = isTop ? height - margin - fontSize : margin;

          page.drawText(text, { x, y, size: fontSize, font, color });
        });

        const bytes = await doc.save({ useObjectStreams: true });
        m.close();
        deliver(bytes, baseName(file.name) + '-numbered.pdf');
      } catch (e) {
        m.setBusy(false);
        toast('Couldn’t add page numbers — the file may be damaged.', { type: 'error' });
        console.error(e);
      }
    }, 'numbers');
    primary.disabled = true;
  },
});
