import type { ScreenplayElement } from '../screenplay/types';
import type { ScreenplayExporter, ExportOptions, ExportResult } from './types';
import { CONTENT_TYPES, EXTENSIONS } from './types';
import { getTemplate } from '../screenplay/format';

const LINES_PER_PAGE = 55;

interface PageElement {
  text: string;
  type: string;
  bold: boolean;
  align: 'left' | 'center' | 'right';
  indentLeft: number;
  indentRight: number;
}

export class PdfExporter implements ScreenplayExporter {
  public readonly supportedFormats: readonly ['pdf'] = ['pdf'];

  public export(elements: ScreenplayElement[], options: ExportOptions): ExportResult {
    const template = getTemplate(options.template || 'standard');
    const pages = buildPages(elements, template);
    const pageCount = pages.length;
    const html = renderHtml(pages, template, options, pageCount);

    const filename = (options.title || 'screenplay').replace(/[^a-zA-Z0-9]/g, '_');

    return {
      format: 'pdf',
      contentType: CONTENT_TYPES.pdf,
      extension: EXTENSIONS.pdf,
      data: html,
      filename: filename + EXTENSIONS.pdf,
      pageCount,
    };
  }
}

function buildPages(elements: ScreenplayElement[], template: ReturnType<typeof getTemplate>): PageElement[][] {
  const allElements: PageElement[] = [];

  for (const el of elements) {
    const style = template.elementStyles[el.type];
    const lines = el.content.trim().split('\n');

    for (const line of lines) {
      if (line.trim() === '' && el.type !== 'action') continue;

      const text = style.uppercase ? line.trim().toUpperCase() : line.trim();
      allElements.push({
        text,
        type: el.type,
        bold: style.bold,
        align: style.textAlign,
        indentLeft: style.indentStart,
        indentRight: style.indentEnd,
      });
    }

    if (style.marginBottom > 0) {
      allElements.push({
        text: '',
        type: 'spacing',
        bold: false,
        align: 'left',
        indentLeft: 0,
        indentRight: 0,
      });
    }
  }

  const pages: PageElement[][] = [];
  let currentPage: PageElement[] = [];

  for (const el of allElements) {
    if (currentPage.length >= LINES_PER_PAGE) {
      pages.push(currentPage);
      currentPage = [];
    }
    currentPage.push(el);
  }

  if (currentPage.length > 0) {
    pages.push(currentPage);
  }

  return pages;
}

function renderHtml(
  pages: PageElement[][],
  template: ReturnType<typeof getTemplate>,
  options: ExportOptions,
  totalPages: number
): string {
  const gutterLeft = options.gutterMargin || 0;
  const INCH_TO_MM = 25.4;

  let bodyContent = '';

  if (options.includeCoverPage) {
    bodyContent += renderCoverPage(options);
  }

  for (let p = 0; p < pages.length; p++) {
    const page = pages[p];
    if (!page) continue;

    let pageContent = '';

    for (const el of page) {
      const indentLeft = (el.indentLeft + gutterLeft) * INCH_TO_MM;
      const indentRight = el.indentRight * INCH_TO_MM;
      const fontWeight = el.bold || el.type === 'sceneHeading' ? 'bold' : 'normal';

      pageContent += `<div style="text-align: ${el.align}; padding-left: ${indentLeft}mm; padding-right: ${indentRight}mm; font-weight: ${fontWeight}; line-height: 1.15;">${escapeHtml(el.text)}</div>\n`;
    }

    bodyContent += `<div class="page" style="page-break-after: ${p < totalPages - 1 ? 'always' : 'avoid'};">\n`;
    bodyContent += pageContent;
    bodyContent += `<div style="text-align: right; padding-top: 10mm; font-size: 10pt;">${p + 1}</div>\n`;
    bodyContent += '</div>\n';
  }

  return `<!DOCTYPE html>
<html>
<head>
<meta charset="utf-8">
<title>${escapeHtml(options.title || 'Screenplay')}</title>
<style>
@page {
  size: ${template.pageWidth}in ${template.pageHeight}in;
  margin: ${template.topMargin}in ${template.rightMargin}in ${template.bottomMargin}in ${template.leftMargin + gutterLeft}in;
}
body {
  font-family: ${template.fontFamily};
  font-size: ${template.fontSize}pt;
  margin: 0;
  padding: 0;
  color: #000;
  background: #fff;
}
@media print {
  body { -webkit-print-color-adjust: exact; }
}
</style>
</head>
<body>
${bodyContent}
</body>
</html>`;
}

function renderCoverPage(options: ExportOptions): string {
  let cover = '<div class="page" style="page-break-after: always; text-align: center; padding-top: 3in;">\n';
  cover += `<div style="font-size: 14pt; font-weight: bold; margin-bottom: 0.5in;">${escapeHtml(options.title || 'Untitled')}</div>\n`;

  if (options.author) {
    cover += '<div style="margin-bottom: 0.3in;">by</div>\n';
    cover += `<div style="font-size: 12pt; margin-bottom: 1in;">${escapeHtml(options.author)}</div>\n`;
  }

  if (options.contact) {
    cover += `<div style="font-size: 10pt;">${escapeHtml(options.contact)}</div>\n`;
  }

  if (options.datetime) {
    cover += `<div style="font-size: 10pt; margin-top: 0.3in;">${escapeHtml(options.datetime)}</div>\n`;
  }

  if (options.pageNumber) {
    cover += `<div style="font-size: 10pt; margin-top: 0.3in;">Draft ${options.pageNumber}</div>\n`;
  }

  cover += '</div>\n';
  return cover;
}

function escapeHtml(s: string): string {
  return s
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;');
}
