import fs from 'fs';
import path from 'path';

const outPath = path.resolve('SOLICITUD_PATENTE_OEPM_FARMAFINDER.pdf');

const pages = [
  [
    { type: 'title', text: 'SOLICITUD DE PATENTE' },
    { type: 'center', text: 'Oficina Española de Patentes y Marcas (OEPM)' },
    { type: 'spacer', lines: 2 },
    {
      type: 'center',
      text: 'Título de la invención:',
    },
    {
      type: 'center',
      text: 'Sistema y procedimiento implementados por ordenador para la identificación de necesidades',
    },
    {
      type: 'center',
      text: 'terapéuticas mediante escaneo de tarjeta sanitaria individual, contraste con stock farmacéutico',
    },
    {
      type: 'center',
      text: 'geolocalizado y generación de acciones de suministro.',
    },
    { type: 'spacer', lines: 2 },
    { type: 'box', lines: [
      'Solicitante: Antoni Nuñez Romeu',
      'NIF/CIF: 45858029P',
      'Domicilio: C/ Font Vella 12, 1, Terrassa, Barcelona, 08221',
      'Inventor o inventores: Antoni Nuñez Romeu',
    ]},
    { type: 'spacer', lines: 2 },
    { type: 'centerSmall', text: 'Memoria descriptiva, reivindicaciones, resumen y referencia a dibujos' },
  ],
  [
    { type: 'heading', text: '1. Campo técnico de la invención' },
    { type: 'paragraph', text: 'La invención se encuadra en los sistemas informáticos aplicados al sector sanitario y farmacéutico, en particular en soluciones de captura de identificadores sanitarios, comparación automatizada de disponibilidad de medicamentos y asistencia digital a la dispensación y suministro.' },
    { type: 'heading', text: '2. Antecedentes de la invención' },
    { type: 'paragraph', text: 'Las soluciones actuales de búsqueda de medicamentos y farmacias permiten localizar productos y mostrar stock aproximado, pero normalmente operan a partir de una búsqueda manual por nombre de medicamento o principio activo. También existen sistemas de geolocalización y de gestión de inventario, pero suelen estar desacoplados del contexto sanitario del usuario y no integran, en una única cadena técnica, la identificación mediante tarjeta sanitaria individual, la inferencia de necesidades terapéuticas y la comparación en tiempo real con disponibilidad farmacéutica local.' },
    { type: 'paragraph', text: 'Además, cuando no existe stock en la farmacia más próxima, el usuario debe iniciar manualmente nuevos procesos de búsqueda o desplazamiento, sin que el sistema proponga de forma automatizada acciones técnicas de reserva, pedido o derivación basadas en la disponibilidad real.' },
    { type: 'heading', text: '3. Problema técnico a resolver' },
    { type: 'paragraph', text: 'La invención resuelve el problema técnico de reducir el tiempo y la fricción entre la identificación de una necesidad terapéutica y la localización de una farmacia que disponga del medicamento adecuado, integrando:' },
    { type: 'bullet', text: 'lectura segura de identificadores sanitarios,' },
    { type: 'bullet', text: 'obtención de referencias de medicamento asociadas,' },
    { type: 'bullet', text: 'comparación automatizada con inventarios de farmacias,' },
    { type: 'bullet', text: 'priorización por proximidad y disponibilidad,' },
    { type: 'bullet', text: 'generación de acciones técnicas de suministro cuando no exista stock inmediato.' },
    { type: 'heading', text: '4. Resumen de la invención' },
    { type: 'paragraph', text: 'La invención propone un sistema y procedimiento implementados por ordenador que operan sobre un terminal móvil o dispositivo de lectura. El sistema captura la información de una tarjeta sanitaria individual mediante escaneo, valida la información mediante un módulo de verificación, asocia el resultado al perfil del usuario autenticado y obtiene una lista de medicamentos o necesidades terapéuticas relevantes. Posteriormente, un motor de contraste consulta un repositorio de stock de farmacias geolocalizadas y determina la coincidencia entre la necesidad detectada y la disponibilidad real en cada establecimiento. Si existe stock, el sistema prioriza las farmacias adecuadas y presenta una ruta de acceso o reserva. Si no existe stock, el sistema genera automáticamente una acción de aviso, pedido, reserva o derivación, conservando trazabilidad técnica del evento. La invención no se limita a una búsqueda manual, sino que integra captura, validación, georreferenciación, consulta de stock y respuesta automática en una única arquitectura técnica.' },
  ],
  [
    { type: 'heading', text: '5. Breve descripción de los dibujos' },
    { type: 'paragraph', text: 'Figura 1. Diagrama de bloques general del sistema.' },
    { type: 'paragraph', text: 'Figura 2. Flujo de captura y validación del escaneo de la TSI.' },
    { type: 'paragraph', text: 'Figura 3. Flujo de contraste entre necesidad terapéutica y stock de farmacias.' },
    { type: 'paragraph', text: 'Figura 4. Flujo de acción cuando no existe stock disponible.' },
    { type: 'heading', text: '6. Descripción detallada de la invención' },
    { type: 'subheading', text: '6.1 Arquitectura general' },
    { type: 'paragraph', text: 'El sistema comprende al menos los siguientes módulos:' },
    { type: 'number', text: 'un módulo de captura de imagen o lectura óptica para escanear la tarjeta sanitaria individual;' },
    { type: 'number', text: 'un módulo de extracción de datos para identificar los campos relevantes de la tarjeta;' },
    { type: 'number', text: 'un módulo de verificación de identidad y autorización, vinculado al usuario autenticado;' },
    { type: 'number', text: 'un módulo de obtención de necesidades terapéuticas o medicamentos asociados;' },
    { type: 'number', text: 'un módulo de geolocalización para obtener la posición del usuario o una posición de referencia;' },
    { type: 'number', text: 'un módulo de consulta de inventario para recuperar stock, precio y horario de farmacias;' },
    { type: 'number', text: 'un módulo de contraste y priorización para ordenar farmacias según disponibilidad y cercanía;' },
    { type: 'number', text: 'un módulo de generación de acciones para crear reserva, aviso, pedido o derivación;' },
    { type: 'number', text: 'un módulo de trazabilidad y auditoría.' },
    { type: 'subheading', text: '6.2 Funcionamiento' },
    { type: 'paragraph', text: 'En una realización preferida, el usuario abre la aplicación y solicita el escaneo de su tarjeta sanitaria individual. El terminal captura la imagen o el código de la tarjeta y el módulo de extracción identifica los datos técnicos necesarios para enlazar el contexto sanitario del usuario con un conjunto de medicamentos o referencias de tratamiento.' },
    { type: 'paragraph', text: 'El sistema valida que la operación se ejecuta sobre un usuario autenticado y autorizado. A continuación, el motor de contraste consulta el inventario de farmacias cercanas, recuperando para cada farmacia al menos su ubicación, horario, stock y, opcionalmente, precio.' },
  ],
  [
    { type: 'subheading', text: '6.2 Funcionamiento (continuación)' },
    { type: 'paragraph', text: 'El módulo de priorización calcula una orden de resultados en base a criterios técnicos tales como existencia de stock, nivel de stock, distancia geográfica, horario de apertura y capacidad de reserva o solicitud de pedido.' },
    { type: 'paragraph', text: 'Cuando existe disponibilidad, el sistema muestra una lista priorizada de farmacias y puede iniciar una reserva o una indicación de recogida. Cuando no existe disponibilidad, el sistema no se limita a informar de la falta de stock, sino que genera una acción técnica adicional, por ejemplo alerta a la farmacia seleccionada, solicitud de pedido a distribución o proveedor, derivación automática a otra farmacia con stock o registro de una lista de espera o interés de suministro.' },
    { type: 'subheading', text: '6.3 Tratamiento de datos y seguridad' },
    { type: 'paragraph', text: 'La invención prevé que la información derivada del escaneo de la TSI se trate con medidas de minimización de datos, control de acceso, cifrado en tránsito y registro de eventos. El sistema no expone innecesariamente los datos de la tarjeta sanitaria y solo conserva los elementos imprescindibles para la operación descrita.' },
    { type: 'subheading', text: '6.4 Integración con la plataforma FarmaFinder' },
    { type: 'paragraph', text: 'En una implementación concreta, el sistema puede integrarse con una plataforma que ya disponga de catálogo de farmacias, geolocalización, stock por medicamento, autenticación de usuario, notificaciones push e histórico de acciones y preferencias.' },
    { type: 'paragraph', text: 'La integración permite que el resultado del escaneo de la TSI no se limite a una consulta pasiva, sino que se convierta en un disparador de decisiones técnicas sobre disponibilidad y suministro.' },
    { type: 'heading', text: '7. Ejemplo de realización' },
    { type: 'number', text: 'El usuario inicia sesión en la aplicación.' },
    { type: 'number', text: 'El usuario escanea su TSI con la cámara del terminal.' },
    { type: 'number', text: 'El sistema extrae el identificador necesario y lo vincula al perfil autorizado.' },
    { type: 'number', text: 'El motor terapéutico asocia una necesidad de medicamento o tratamiento.' },
  ],
  [
    { type: 'heading', text: '7. Ejemplo de realización (continuación)' },
    { type: 'number', text: 'El sistema consulta farmacias cercanas con stock del medicamento.' },
    { type: 'number', text: 'Si hay stock, ordena las farmacias por proximidad y disponibilidad.' },
    { type: 'number', text: 'Si no hay stock, genera una reserva, una alerta o una solicitud de pedido.' },
    { type: 'heading', text: '8. Reivindicaciones' },
    { type: 'claim', text: 'Reivindicación 1. Sistema implementado por ordenador para identificar una necesidad terapéutica a partir del escaneo de una tarjeta sanitaria individual, caracterizado porque comprende medios de captura para obtener datos de la tarjeta sanitaria individual; medios de verificación para asociar dichos datos a un usuario autenticado; medios de obtención de una referencia de medicamento o necesidad terapéutica; medios de consulta de inventario para recuperar stock de farmacias geolocalizadas; medios de contraste para comparar la referencia de medicamento o necesidad terapéutica con el stock disponible; y medios de generación de acciones para producir una reserva, aviso, pedido o derivación cuando el stock disponible sea insuficiente.' },
    { type: 'claim', text: 'Reivindicación 2. Sistema según la reivindicación 1, en el que los medios de consulta de inventario ordenan las farmacias según una combinación de stock disponible, proximidad geográfica y horario de apertura.' },
    { type: 'claim', text: 'Reivindicación 3. Sistema según cualquiera de las reivindicaciones anteriores, en el que los datos de la tarjeta sanitaria individual son tratados mediante un módulo de minimización y cifrado para limitar su almacenamiento a los campos técnicamente necesarios.' },
    { type: 'claim', text: 'Reivindicación 4. Procedimiento implementado por ordenador para asistir en la localización y suministro de medicamentos, caracterizado porque comprende escanear una tarjeta sanitaria individual; verificar la autorización del usuario; derivar una necesidad terapéutica o referencia de medicamento; consultar stock de farmacias geolocalizadas; comparar la necesidad con el stock disponible; y generar una acción técnica de reserva, aviso, pedido o derivación cuando no exista disponibilidad suficiente.' },
    { type: 'claim', text: 'Reivindicación 5. Dispositivo móvil, terminal o sistema de lectura que comprende una cámara o lector óptico y que está configurado para ejecutar el sistema de cualquiera de las reivindicaciones anteriores.' },
  ],
  [
    { type: 'heading', text: '9. Aplicación industrial' },
    { type: 'paragraph', text: 'La invención es susceptible de aplicación industrial en plataformas de asistencia farmacéutica, sistemas de gestión de inventario, servicios de reserva o pedido de medicamentos y terminales de consulta sanitaria.' },
    { type: 'heading', text: '10. Resumen' },
    { type: 'paragraph', text: 'La presente invención se refiere a un sistema y procedimiento implementados por ordenador que permiten, a partir del escaneo de una tarjeta sanitaria individual mediante un terminal móvil o dispositivo equivalente, asociar de forma segura un contexto de paciente a una necesidad terapéutica, obtener una referencia de medicamentos relevantes, comparar dicha necesidad con el stock disponible en farmacias geolocalizadas y generar, en caso de falta de disponibilidad, una acción de reserva, aviso, solicitud de pedido o derivación a una farmacia alternativa. El sistema integra captura de datos, verificación de identidad, geolocalización, consulta de disponibilidad, gestión de stock y generación de eventos de suministro en una única cadena técnica de procesamiento.' },
    { type: 'heading', text: '11. Anexo de dibujos' },
    { type: 'paragraph', text: 'Las figuras indicadas en la presente memoria tienen carácter esquemático y se incorporan a efectos ilustrativos de la arquitectura, del flujo de captura, del contraste de stock y de la generación de acciones. En una presentación definitiva, dichas figuras podrán acompañarse como láminas separadas numeradas de forma consecutiva.' },
    { type: 'heading', text: '12. Firma del solicitante' },
    { type: 'paragraph', text: 'En Terrassa, a 22 de junio de 2026.' },
    { type: 'paragraph', text: 'Fdo.: Antoni Nuñez Romeu' },
    { type: 'paragraph', text: 'DNI/NIF: 45858029P' },
    { type: 'heading', text: '13. Notas para presentación en OEPM' },
    { type: 'bullet', text: 'La solicitud debe presentarse como una única invención o un único concepto inventivo general.' },
    { type: 'bullet', text: 'La descripción, reivindicaciones y dibujos deben ser coherentes entre sí.' },
    { type: 'bullet', text: 'La protección en patente debe apoyarse en un efecto técnico concreto y no en una mera regla comercial o método abstracto.' },
    { type: 'bullet', text: 'Esta redacción evita formular una reivindicación independiente de "programa de ordenador como tal" y se centra en un sistema y un procedimiento implementados por ordenador con interacción técnica sobre captura, contraste de inventario y generación de acciones.' },
    { type: 'bullet', text: 'Antes de presentar la solicitud conviene una búsqueda de anterioridades y una revisión por agente de propiedad industrial.' },
  ],
];

const PAGE_W = 595.28;
const PAGE_H = 841.89;
const MARGIN_L = 56;
const MARGIN_R = 56;
const MARGIN_T = 58;
const MARGIN_B = 52;
const CONTENT_W = PAGE_W - MARGIN_L - MARGIN_R;
const FONT = 'Times-Roman';
const FONT_BOLD = 'Times-Bold';
const FONT_ITALIC = 'Times-Italic';

function esc(s) {
  return String(s)
    .replace(/\\/g, '\\\\')
    .replace(/\(/g, '\\(')
    .replace(/\)/g, '\\)');
}

function toLatin1(s) {
  return Buffer.from(s, 'latin1').toString('latin1');
}

function wrapText(text, size) {
  const avg = size * 0.5;
  const max = Math.max(20, Math.floor(CONTENT_W / avg));
  const words = String(text).split(/\s+/);
  const lines = [];
  let line = '';
  for (const word of words) {
    const candidate = line ? `${line} ${word}` : word;
    if (candidate.length > max && line) {
      lines.push(line);
      line = word;
    } else {
      line = candidate;
    }
  }
  if (line) lines.push(line);
  return lines;
}

function makePdf() {
  const objects = [''];
  const pagesObjNums = [];
  const contentObjNums = [];
  const fontObjNums = { regular: 0, bold: 0, italic: 0 };

  function addObject(body) {
    objects.push(body);
    return objects.length - 1;
  }

  fontObjNums.regular = addObject('<< /Type /Font /Subtype /Type1 /BaseFont /Times-Roman /Encoding /WinAnsiEncoding >>');
  fontObjNums.bold = addObject('<< /Type /Font /Subtype /Type1 /BaseFont /Times-Bold /Encoding /WinAnsiEncoding >>');
  fontObjNums.italic = addObject('<< /Type /Font /Subtype /Type1 /BaseFont /Times-Italic /Encoding /WinAnsiEncoding >>');

  function pageContent(lines, pageNo) {
    const ops = [];
    let y = PAGE_H - MARGIN_T;
    let numberCounter = 1;

    const write = (txt, x, size, font = FONT) => {
      const clean = toLatin1(txt);
      ops.push(`BT /${font === FONT_BOLD ? 'F2' : font === FONT_ITALIC ? 'F3' : 'F1'} ${size} Tf ${x} ${y} Td (${esc(clean)}) Tj ET`);
      y -= size * 1.28;
    };

    const separator = () => {
      y -= 4;
      ops.push(`0.2 w ${MARGIN_L} ${y} m ${PAGE_W - MARGIN_R} ${y} l S`);
      y -= 10;
    };

    const box = (lines) => {
      const lineH = 14;
      const h = lines.length * lineH + 12;
      ops.push(`0.8 w ${MARGIN_L} ${y - h + 8} ${CONTENT_W} ${h} re S`);
      y -= 4;
      for (const line of lines) {
        write(line, MARGIN_L + 10, 11);
      }
      y -= 4;
    };

    const ensureSpace = (needed) => {
      if (y - needed < MARGIN_B) {
        return false;
      }
      return true;
    };

    if (pageNo === 1) {
      write('SOLICITUD DE PATENTE', MARGIN_L + 85, 18, FONT_BOLD);
      y -= 6;
      write('Oficina Española de Patentes y Marcas (OEPM)', MARGIN_L + 55, 12, FONT);
      y -= 14;
      write('Título de la invención:', MARGIN_L + 120, 12, FONT_BOLD);
      const titleLines = wrapText('Sistema y procedimiento implementados por ordenador para la identificación de necesidades terapéuticas mediante escaneo de tarjeta sanitaria individual, contraste con stock farmacéutico geolocalizado y generación de acciones de suministro.', 12);
      for (const line of titleLines) write(line, MARGIN_L + 10, 12);
      y -= 8;
      box([
        'Solicitante: Antoni Nuñez Romeu',
        'NIF/CIF: 45858029P',
        'Domicilio: C/ Font Vella 12, 1, Terrassa, Barcelona, 08221',
        'Inventor o inventores: Antoni Nuñez Romeu',
      ]);
      y -= 8;
      write('Memoria descriptiva, reivindicaciones, resumen y referencia a dibujos', MARGIN_L + 68, 10, FONT_ITALIC);
    } else {
      const content = lines;
      for (const item of content) {
        if (item.type === 'heading') {
          if (!ensureSpace(28)) break;
          y -= 2;
          write(item.text, MARGIN_L, 13, FONT_BOLD);
          separator();
          continue;
        }
        if (item.type === 'subheading') {
          if (!ensureSpace(20)) break;
          write(item.text, MARGIN_L, 11.5, FONT_BOLD);
          continue;
        }
        if (item.type === 'paragraph') {
          const wrapped = wrapText(item.text, 11.5);
          const needed = wrapped.length * 15;
          if (!ensureSpace(needed + 8)) break;
          for (const line of wrapped) write(line, MARGIN_L, 11.5);
          y -= 2;
          continue;
        }
        if (item.type === 'bullet') {
          const wrapped = wrapText(item.text, 11.2);
          if (!ensureSpace(wrapped.length * 14 + 8)) break;
          let first = true;
          for (const line of wrapped) {
            write((first ? '• ' : '  ') + line, MARGIN_L + 8, 11.2);
            first = false;
          }
          continue;
        }
        if (item.type === 'number') {
          const wrapped = wrapText(item.text, 11.2);
          if (!ensureSpace(wrapped.length * 14 + 8)) break;
          let first = true;
          for (const line of wrapped) {
            write((first ? `${numberCounter}. ` : '   ') + line, MARGIN_L + 8, 11.2);
            first = false;
          }
          numberCounter += 1;
          continue;
        }
        if (item.type === 'claim') {
          const wrapped = wrapText(item.text, 11.2);
          const needed = wrapped.length * 15 + 8;
          if (!ensureSpace(needed)) break;
          for (const line of wrapped) write(line, MARGIN_L, 11.2);
          y -= 2;
          continue;
        }
        if (item.type === 'center') {
          const wrapped = wrapText(item.text, 12);
          if (!ensureSpace(wrapped.length * 14)) break;
          for (const line of wrapped) write(line, MARGIN_L + 70, 12);
          continue;
        }
        if (item.type === 'centerSmall') {
          const wrapped = wrapText(item.text, 10);
          if (!ensureSpace(wrapped.length * 12)) break;
          for (const line of wrapped) write(line, MARGIN_L + 78, 10);
          continue;
        }
        if (item.type === 'title') {
          continue;
        }
        if (item.type === 'spacer') {
          y -= (item.lines || 1) * 12;
          continue;
        }
      }
    }

    ops.push(`BT /F1 9 Tf ${PAGE_W - 100} ${24} Td (Pagina ${pageNo}) Tj ET`);
    return ops.join('\n');
  }

  // Create page objects and content streams first
  for (let i = 0; i < pages.length; i++) {
    const content = pageContent(pages[i], i + 1);
    const stream = `<< /Length ${Buffer.byteLength(content, 'latin1')} >>\nstream\n${content}\nendstream`;
    contentObjNums.push(addObject(stream));
  }

  const pagesTreeObj = addObject('');

  for (let i = 0; i < pages.length; i++) {
    const pageObj = addObject(`<< /Type /Page /Parent ${pagesTreeObj} 0 R /MediaBox [0 0 ${PAGE_W} ${PAGE_H}] /Resources << /Font << /F1 ${fontObjNums.regular} 0 R /F2 ${fontObjNums.bold} 0 R /F3 ${fontObjNums.italic} 0 R >> >> /Contents ${contentObjNums[i]} 0 R >>`);
    pagesObjNums.push(pageObj);
  }

  objects[pagesTreeObj] = `<< /Type /Pages /Kids [${pagesObjNums.map(n => `${n} 0 R`).join(' ')}] /Count ${pagesObjNums.length} >>`;

  const catalogObj = addObject(`<< /Type /Catalog /Pages ${pagesTreeObj} 0 R >>`);

  let pdf = '%PDF-1.4\n';
  const offsets = [0];
  for (let i = 1; i < objects.length; i++) {
    offsets[i] = Buffer.byteLength(pdf, 'latin1');
    pdf += `${i} 0 obj\n${objects[i]}\nendobj\n`;
  }
  const xrefPos = Buffer.byteLength(pdf, 'latin1');
  pdf += `xref\n0 ${objects.length}\n`;
  pdf += '0000000000 65535 f \n';
  for (let i = 1; i < objects.length; i++) {
    pdf += `${String(offsets[i]).padStart(10, '0')} 00000 n \n`;
  }
  pdf += `trailer << /Size ${objects.length} /Root ${catalogObj} 0 R >>\nstartxref\n${xrefPos}\n%%EOF\n`;
  fs.writeFileSync(outPath, Buffer.from(pdf, 'latin1'));
}

makePdf();
console.log(`Wrote ${outPath}`);
