// Stage 3: render the structured manuscript as a Word document in standard
// manuscript format — double-spaced, 12pt serif, chapters on new pages.
const fs = require('fs');
const {
  Document, Packer, Paragraph, TextRun, PageBreak, Footer, Header,
  AlignmentType, PageNumber, LineRuleType, HeadingLevel, FootnoteReferenceRun,
  convertInchesToTwip,
} = require('docx');

const data = JSON.parse(fs.readFileSync('/tmp/doc.json', 'utf8'));
const blocks = data.blocks;
const TOC = data.toc;

const FONT = 'Times New Roman';
const SIZE = 24;             // half-points => 12pt
const DOUBLE = { line: 480, lineRule: LineRuleType.AUTO };   // 240 = single
const SINGLE = { line: 240, lineRule: LineRuleType.AUTO };

// ---- footnotes: docx numbers them 1..n; map anchor pid -> footnote id ------
const footnotes = {};
const noteByPid = new Map();
let noteId = 1;
for (const b of blocks) {
  if (b.type !== 'footnote') continue;
  footnotes[noteId] = {
    children: [new Paragraph({
      spacing: SINGLE,
      children: [new TextRun({ text: ' ' + b.text, font: FONT, size: 20 })],
    })],
  };
  if (!noteByPid.has(b.anchor)) noteByPid.set(b.anchor, []);
  noteByPid.get(b.anchor).push(noteId);
  noteId += 1;
}

const run = (text, opts = {}) =>
  new TextRun({ text, font: FONT, size: SIZE, ...opts });

// Split a paragraph at its '*' markers so a real footnote reference can sit
// exactly where the author put the asterisk.
function bodyParagraph(b) {
  const ids = noteByPid.get(b.pid) || [];
  const children = [];
  if (ids.length && b.text.includes('*')) {
    const parts = b.text.split('*');
    parts.forEach((part, i) => {
      if (part) children.push(run(part));
      if (i < parts.length - 1) {
        const id = ids.shift();
        if (id) children.push(new FootnoteReferenceRun(id));
        else children.push(run('*'));
      }
    });
  } else {
    children.push(run(b.text));
  }
  // any footnote we couldn't place inline goes at the end of the paragraph
  for (const id of ids) children.push(new FootnoteReferenceRun(id));
  return new Paragraph({
    children,
    spacing: { ...DOUBLE, after: 0 },
    indent: { firstLine: convertInchesToTwip(0.5) },
    alignment: AlignmentType.LEFT,
  });
}

const children = [];

// ------------------------------------------------------------ title page
children.push(
  new Paragraph({ spacing: { before: convertInchesToTwip(2.5) } }),
  new Paragraph({
    alignment: AlignmentType.CENTER, spacing: DOUBLE,
    children: [run('THE CHINA AFFAIR', { bold: true })],
  }),
  new Paragraph({
    alignment: AlignmentType.CENTER, spacing: DOUBLE, children: [run('by')],
  }),
  new Paragraph({
    alignment: AlignmentType.CENTER, spacing: DOUBLE,
    children: [run('Ernest Walton')],
  }),
  new Paragraph({
    alignment: AlignmentType.CENTER,
    spacing: { ...DOUBLE, before: convertInchesToTwip(2.0) },
    children: [run('420 East 23rd Street')],
  }),
  new Paragraph({
    alignment: AlignmentType.CENTER, spacing: SINGLE,
    children: [run('New York, New York 10010')],
  }),
  new Paragraph({
    alignment: AlignmentType.CENTER,
    spacing: { ...SINGLE, before: convertInchesToTwip(0.6) },
    children: [run('© Ernest Walton 1982')],
  }),
  new Paragraph({ children: [new PageBreak()] }),
);

// ------------------------------------------------------------- epigraph
children.push(
  new Paragraph({ spacing: { before: convertInchesToTwip(2.2) } }),
  new Paragraph({
    spacing: DOUBLE,
    indent: { left: convertInchesToTwip(1.2), right: convertInchesToTwip(0.8) },
    children: [run('We must respect the past, remembering that once it was all that was humanly possible.')],
  }),
  new Paragraph({
    spacing: DOUBLE, alignment: AlignmentType.RIGHT,
    indent: { right: convertInchesToTwip(1.2) },
    children: [run('George Santayana')],
  }),
  new Paragraph({ children: [new PageBreak()] }),
);

// -------------------------------------------------------- table of contents
children.push(new Paragraph({
  alignment: AlignmentType.CENTER,
  spacing: { after: 480 },
  children: [run('TABLE OF CONTENTS', { bold: true })],
}));
const titleCase = (s) => s.replace(/[A-Za-zÀ-ÿ']+/g, (w) =>
  w[0].toUpperCase() + w.slice(1).toLowerCase());
for (const [label, title] of TOC) {
  children.push(new Paragraph({
    spacing: SINGLE, indent: { left: convertInchesToTwip(1.0) },
    children: [run(`${label} — ${titleCase(title)}`)],
  }));
}
children.push(new Paragraph({
  spacing: { before: 240 }, indent: { left: convertInchesToTwip(1.0) },
  children: [run('Appendix — How A Zeppelin Flies (not included)')],
}));
children.push(new Paragraph({ children: [new PageBreak()] }));

// ------------------------------------------------------------- manuscript
let first = true;
for (const b of blocks) {
  if (b.type === 'heading') {
    if (!first) children.push(new Paragraph({ children: [new PageBreak()] }));
    first = false;
    children.push(
      new Paragraph({ spacing: { before: convertInchesToTwip(1.0) } }),
      new Paragraph({
        alignment: AlignmentType.CENTER, spacing: DOUBLE,
        heading: HeadingLevel.HEADING_1,
        children: [run(b.label, { bold: true })],
      }),
      new Paragraph({
        alignment: AlignmentType.CENTER, spacing: { ...DOUBLE, after: 240 },
        children: [run(b.title, { bold: true })],
      }),
    );
  } else if (b.type === 'para') {
    children.push(bodyParagraph(b));
  } else if (b.type === 'quote') {
    // prose quotation: reflowed, indented, single-spaced
    children.push(new Paragraph({
      spacing: { ...SINGLE, before: 240, after: 240 },
      indent: { left: convertInchesToTwip(1.0), right: convertInchesToTwip(0.5) },
      children: [run(b.text || b.lines.join(' '))],
    }));
  } else if (b.type === 'verse') {
    b.lines.forEach((ln, i) => children.push(new Paragraph({
      alignment: AlignmentType.CENTER,
      spacing: { ...SINGLE, before: i === 0 ? 240 : 0,
                 after: i === b.lines.length - 1 ? 240 : 0 },
      children: [run(ln)],
    })));
  }
}

const doc = new Document({
  creator: 'Ernest Walton',
  title: 'The China Affair',
  footnotes,
  styles: {
    default: {
      document: { run: { font: FONT, size: SIZE } },
      heading1: { run: { font: FONT, size: SIZE, bold: true, color: '000000' } },
    },
  },
  sections: [{
    properties: {
      page: {
        size: { width: 12240, height: 15840 },        // US Letter
        margin: {
          top: convertInchesToTwip(1), bottom: convertInchesToTwip(1),
          left: convertInchesToTwip(1.25), right: convertInchesToTwip(1.25),
        },
      },
      titlePage: true,
    },
    headers: {
      default: new Header({
        children: [new Paragraph({
          alignment: AlignmentType.RIGHT,
          children: [new TextRun({
            font: FONT, size: 20,
            children: ['Walton / The China Affair / ', PageNumber.CURRENT],
          })],
        })],
      }),
      first: new Header({ children: [new Paragraph('')] }),
    },
    children,
  }],
});

Packer.toBuffer(doc).then((buf) => {
  fs.writeFileSync(require('path').join(__dirname, '..', 'manuscript',
    'The China Affair - Ernest Walton.docx'), buf);
  console.log('wrote docx;', children.length, 'paragraphs,', noteId - 1, 'footnotes');
});
