<script setup>
import { ref, onMounted, onBeforeUnmount, computed } from "vue";
import { jsPDF } from "jspdf";
import GoogleIcon from "@Shared/GoogleIcon.vue";
import Draggable from "@Holos/PDF/Draggable.vue";
import CanvasElement from "@Holos/PDF/Canvas.vue";
import PDFViewport from "@Holos/PDF/PDFViewport.vue";
import TextFormatter from "@Holos/PDF/TextFormatter.vue";
import TableEditorModal from "@Holos/PDF/TableEditorModal.vue";
import autoTable from "jspdf-autotable";

/** Estado Reactivo */
const pages = ref([{ id: 1, elements: [] }]);
const selectedElementId = ref(null);
const documentTitle = ref("Documento sin título");
const currentPage = ref(1);
const pageIdCounter = ref(1);
const isExporting = ref(false);
const currentPageSize = ref("A4");
const activeEditor = ref(null);
const isTableEditing = ref(false);
const isTableModalOpen = ref(false);
const editingTableId = ref(null);

const allElements = computed(() =>
  pages.value.flatMap((page) => page.elements)
);
const totalElements = computed(() => allElements.value.length);
const selectedElement = computed(() =>
  allElements.value.find((el) => el.id === selectedElementId.value)
);

const addPage = () => {
  pages.value.push({ id: ++pageIdCounter.value, elements: [] });
};

const deletePage = (pageIndex) => {
  if (pages.value.length > 1) {
    if (currentPage.value > pageIndex + 1) {
      currentPage.value--;
    } else if (currentPage.value === pageIndex + 1 && currentPage.value > 1) {
      currentPage.value--;
    }
    pages.value.splice(pageIndex, 1);
  }
};

const handleDrop = (dropData) => {
  const data = JSON.parse(
    dropData.originalEvent.dataTransfer.getData("text/plain")
  );
  const newElement = createNewElement({ ...data, ...dropData });
  pages.value[dropData.pageIndex].elements.push(newElement);
  selectElement(newElement.id);
};

const createNewElement = (data) => ({
  id: `el-${Date.now()}-${Math.random().toString(36).substr(2, 9)}`,
  type: data.type,
  pageIndex: data.pageIndex,
  x: data.x,
  y: data.y,
  width: data.type === "table" ? 400 : 250,
  height: data.type === "image" ? 150 : 120,
  content: getDefaultContent(data.type),
});

const getDefaultContent = (type) => {
  if (type === "text") return "<p>Escribe algo...</p>";
  if (type === "table") {
    return `<table class="tiptap-table">
      <thead>
        <tr>
          <th>Encabezado 1</th>
          <th>Encabezado 2</th>
          <th>Encabezado 3</th>
        </tr>
      </thead>
      <tbody>
        <tr>
          <td>Celda 1</td>
          <td>Celda 2</td>
          <td>Celda 3</td>
        </tr>
        <tr>
          <td>Celda 4</td>
          <td>Celda 5</td>
          <td>Celda 6</td>
        </tr>
      </tbody>
    </table>`;
  }
  return null;
};

const selectElement = (elementId) => {
  selectedElementId.value = elementId;
};
const deselectAll = (event) => {
  if (event.target === event.currentTarget) {
    selectedElementId.value = null;
    activeEditor.value = null;
    isTableEditing.value = false;
  }
};
const moveElement = (moveData) => {
  const el = allElements.value.find((e) => e.id === moveData.id);
  if (el) Object.assign(el, moveData);
};
const updateElement = (update) => {
  const el = allElements.value.find((e) => e.id === update.id);
  if (el) Object.assign(el, update);
};
const deleteElement = (elementId) => {
  pages.value.forEach((p) => {
    p.elements = p.elements.filter((el) => el.id !== elementId);
  });
  if (selectedElementId.value === elementId) selectedElementId.value = null;
};
const clearCanvas = () => {
  if (confirm("¿Deseas limpiar todo el documento?")) {
    pages.value = [{ id: 1, elements: [] }];
    selectedElementId.value = null;
    pageIdCounter.value = 1;
    currentPage.value = 1;
  }
};

const handleTableEditing = (editing) => {
  isTableEditing.value = editing;
};

const openTableEditor = (tableId) => {
  editingTableId.value = tableId;
  isTableModalOpen.value = true;
};

const saveTableContent = (newContent) => {
  if (editingTableId.value) {
    const el = allElements.value.find((e) => e.id === editingTableId.value);
    if (el) {
      el.content = newContent;
    }
  }
  closeTableEditor();
};

const closeTableEditor = () => {
  isTableModalOpen.value = false;
  editingTableId.value = null;
};

const editingTable = computed(() => {
  if (!editingTableId.value) return null;
  return allElements.value.find((e) => e.id === editingTableId.value);
});

const handlePageSizeChange = (sizeData) => {
  currentPageSize.value = sizeData.size;
};

const handleKeydown = (event) => {
  if (event.key === "Delete" && selectedElementId.value)
    deleteElement(selectedElementId.value);
  if (event.key === "Escape") selectedElementId.value = null;
};
onMounted(() => document.addEventListener("keydown", handleKeydown));
onBeforeUnmount(() => document.removeEventListener("keydown", handleKeydown));

// Tamaños de página en mm 
const PDF_SIZES = {
  A4: { width: 210, height: 297, canvasWidth: 794, canvasHeight: 1123 },
  A3: { width: 297, height: 420, canvasWidth: 1123, canvasHeight: 1587 },
  Tabloid: { width: 279.4, height: 431.8, canvasWidth: 1056, canvasHeight: 1632 },
};

// Función para convertir color hex/rgb a array RGB
const parseColor = (colorStr) => {
  if (!colorStr) return null;

  // Si es hex (#RRGGBB)
  if (colorStr.startsWith('#')) {
    const hex = colorStr.replace('#', '');
    return [
      parseInt(hex.substr(0, 2), 16),
      parseInt(hex.substr(2, 2), 16),
      parseInt(hex.substr(4, 2), 16)
    ];
  }

  // Si es rgb(r, g, b)
  const match = colorStr.match(/rgb\((\d+),\s*(\d+),\s*(\d+)\)/);
  if (match) {
    return [parseInt(match[1]), parseInt(match[2]), parseInt(match[3])];
  }

  return null;
};

// Función auxiliar para procesar texto HTML y extraer líneas con estilos
const parseHTMLContent = (html) => {
  const temp = document.createElement('div');
  temp.innerHTML = html;

  const lines = [];

  // Procesar cada párrafo
  const paragraphs = temp.querySelectorAll('p');

  if (paragraphs.length === 0) {
    const text = temp.textContent.trim();
    if (text) {
      return [{
        segments: [{ text, isBold: false, isItalic: false, color: null, fontSize: null }],
        align: 'left',
        isNewParagraph: false
      }];
    }
    return [];
  }

  paragraphs.forEach((p, pIndex) => {
    // Detectar alineación del párrafo
    let align = 'left';
    if (p.style.textAlign) {
      align = p.style.textAlign;
    } else if (p.getAttribute('style')) {
      const styleMatch = p.getAttribute('style').match(/text-align:\s*(left|center|right)/);
      if (styleMatch) {
        align = styleMatch[1];
      }
    }

    // Recolectar segmentos de texto con estilos (inline, sin dividir por saltos)
    const segments = [];

    const processNode = (node, parentStyles = {}) => {
      if (node.nodeType === Node.TEXT_NODE) {
        const text = node.textContent;
        // Dividir por saltos de línea explícitos
        const textLines = text.split('\n');
        textLines.forEach((lineText, idx) => {
          if (lineText.trim()) {
            segments.push({
              text: lineText,
              isBold: parentStyles.isBold || false,
              isItalic: parentStyles.isItalic || false,
              color: parentStyles.color || null,
              fontSize: parentStyles.fontSize || null,
              forceBreak: idx > 0 // Si hay múltiples líneas, forzar salto después de cada una
            });
          }
        });
      } else if (node.nodeType === Node.ELEMENT_NODE) {
        const element = node;

        // Si es un <br>, forzar salto de línea
        if (element.tagName === 'BR') {
          if (segments.length > 0) {
            segments[segments.length - 1].forceBreak = true;
          }
          return;
        }

        const currentStyles = {
          isBold: parentStyles.isBold || element.tagName === 'STRONG' || element.tagName === 'B',
          isItalic: parentStyles.isItalic || element.tagName === 'EM' || element.tagName === 'I',
          color: parseColor(element.style.color) || parentStyles.color,
          fontSize: (element.style.fontSize ? parseInt(element.style.fontSize) : null) || parentStyles.fontSize
        };

        Array.from(element.childNodes).forEach(child => processNode(child, currentStyles));
      }
    };

    Array.from(p.childNodes).forEach(node => processNode(node));

    // Agrupar segmentos en líneas solo si hay salto forzado
    let currentLine = { segments: [], align, isNewParagraph: false };

    segments.forEach((segment, idx) => {
      currentLine.segments.push({
        text: segment.text,
        isBold: segment.isBold,
        isItalic: segment.isItalic,
        color: segment.color,
        fontSize: segment.fontSize
      });

      // Si hay salto forzado o es el último segmento, cerrar línea
      if (segment.forceBreak || idx === segments.length - 1) {
        if (currentLine.segments.length > 0) {
          lines.push(currentLine);
          currentLine = { segments: [], align, isNewParagraph: false };
        }
      }
    });

    // Marcar nuevo párrafo
    if (pIndex < paragraphs.length - 1 && lines.length > 0) {
      lines[lines.length - 1].isNewParagraph = true;
    }
  });

  return lines;
};

const exportPDF = () => {
  isExporting.value = true;
  try {
    const pageConfig = PDF_SIZES[currentPageSize.value] || PDF_SIZES.A4;

    // Crear documento PDF
    const pdf = new jsPDF({
      orientation: 'portrait',
      unit: 'mm',
      format: [pageConfig.width, pageConfig.height]
    });

    // Factor de escala de canvas a PDF (mm)
    const scaleX = pageConfig.width / pageConfig.canvasWidth;
    const scaleY = pageConfig.height / pageConfig.canvasHeight;

    pages.value.forEach((page, pageIndex) => {
      if (pageIndex > 0) {
        pdf.addPage([pageConfig.width, pageConfig.height]);
      }

      page.elements.forEach((element) => {
        const x = element.x * scaleX;
        const y = element.y * scaleY;
        const width = element.width * scaleX;
        const height = element.height * scaleY;

        if (element.type === 'text' && element.content) {
          const lines = parseHTMLContent(element.content);
          let currentY = y + 5;
          const lineHeight = 4.5;

          lines.forEach((line) => {
            // Construir el texto completo de la línea combinando segmentos
            let fullLineText = '';
            let currentX = x + 1;

            // Calcular posición inicial según alineación
            if (line.align === 'center') {
              currentX = x + (width / 2);
            } else if (line.align === 'right') {
              currentX = x + width - 1;
            }

            // Si hay múltiples segmentos con diferentes estilos, dibujar cada uno
            if (line.segments.length === 1 && !line.segments[0].color && !line.segments[0].isBold && !line.segments[0].isItalic) {
              // Caso simple: un solo segmento sin estilos especiales
              const segment = line.segments[0];
              pdf.setFontSize(segment.fontSize || 12);
              pdf.setFont('helvetica', 'normal');
              pdf.setTextColor(0, 0, 0);

              const textLines = pdf.splitTextToSize(segment.text, width - 2);
              textLines.forEach((txtLine) => {
                pdf.text(txtLine, currentX, currentY, { align: line.align });
                currentY += lineHeight;
              });
            } else {
              // Caso complejo: múltiples segmentos o con estilos
              // Primero, calcular el ancho total de la línea
              let totalWidth = 0;
              const segmentWidths = [];

              line.segments.forEach((segment) => {
                pdf.setFontSize(segment.fontSize || 12);
                let fontStyle = 'normal';
                if (segment.isBold && segment.isItalic) fontStyle = 'bolditalic';
                else if (segment.isBold) fontStyle = 'bold';
                else if (segment.isItalic) fontStyle = 'italic';
                pdf.setFont('helvetica', fontStyle);

                const segWidth = pdf.getTextWidth(segment.text);
                segmentWidths.push(segWidth);
                totalWidth += segWidth;
              });

              // Ajustar posición inicial según alineación
              let startX = x + 1;
              if (line.align === 'center') {
                startX = x + (width / 2) - (totalWidth / 2);
              } else if (line.align === 'right') {
                startX = x + width - 1 - totalWidth;
              }

              let segmentX = startX;

              // Dibujar cada segmento
              line.segments.forEach((segment, segIdx) => {
                pdf.setFontSize(segment.fontSize || 12);

                let fontStyle = 'normal';
                if (segment.isBold && segment.isItalic) fontStyle = 'bolditalic';
                else if (segment.isBold) fontStyle = 'bold';
                else if (segment.isItalic) fontStyle = 'italic';
                pdf.setFont('helvetica', fontStyle);

                if (segment.color) {
                  pdf.setTextColor(segment.color[0], segment.color[1], segment.color[2]);
                } else {
                  pdf.setTextColor(0, 0, 0);
                }

                pdf.text(segment.text, segmentX, currentY, { align: 'left' });
                segmentX += segmentWidths[segIdx];
              });

              currentY += lineHeight;
            }

            // Agregar espacio extra si es nuevo párrafo
            if (line.isNewParagraph) {
              currentY += 1.5;
            }
          });

          // Resetear color y fuente
          pdf.setTextColor(0, 0, 0);
          pdf.setFont('helvetica', 'normal');
        }

        if (element.type === 'image' && element.content) {
          try {
            pdf.addImage(element.content, 'PNG', x, y, width, height);
          } catch (e) {
            console.warn('Error al agregar imagen:', e);
          }
        }

        if (element.type === 'table' && element.content) {
          // Parsear tabla HTML de Tiptap
          const temp = document.createElement('div');
          temp.innerHTML = element.content;
          const table = temp.querySelector('table');

          if (table) {
            // Extraer headers
            const headerCells = Array.from(table.querySelectorAll('thead th, thead td'));
            const head = headerCells.length > 0
              ? [headerCells.map(th => th.textContent.trim())]
              : null;

            // Extraer filas del body
            const bodyRows = Array.from(table.querySelectorAll('tbody tr'));
            const body = bodyRows.map(row => {
              const cells = Array.from(row.children);
              return cells.map(cell => cell.textContent.trim());
            });

            // Usar autoTable para renderizar la tabla
            autoTable(pdf, {
              head: head,
              body: body,
              startY: y,
              margin: { left: x },
              tableWidth: width,
              styles: {
                fontSize: 10,
                cellPadding: 2,
                lineColor: [209, 213, 219],
                lineWidth: 0.1,
              },
              headStyles: {
                fillColor: [249, 250, 251],
                textColor: [0, 0, 0],
                fontStyle: 'bold',
              },
              bodyStyles: {
                textColor: [0, 0, 0],
              },
              theme: 'grid',
              tableLineColor: [209, 213, 219],
              tableLineWidth: 0.1,
            });
          }
        }
      });
    });

    pdf.save(`${documentTitle.value || "documento"}.pdf`);
  } catch (e) {
    console.error("Error al exportar PDF:", e);
    alert("Hubo un error al generar el PDF.");
  } finally {
    isExporting.value = false;
  }
};

const availableElements = [
  { type: "text", icon: "text_fields", title: "Texto" },
  { type: "image", icon: "image", title: "Imagen" },
  { type: "table", icon: "table_chart", title: "Tabla" },
];
</script>

<template>
  <div class="flex flex-col lg:flex-row h-screen bg-gray-50">
    <div class="w-full lg:w-64 bg-white border-r border-gray-200 flex flex-col">
      <div class="p-3 lg:p-4 border-b">
        <div class="flex items-center gap-2 mb-3">
          <GoogleIcon name="text_snippet" class="text-blue-600 text-lg" />
          <h2 class="font-semibold text-gray-900 text-sm">Diseñador</h2>
        </div>
        <input
          v-model="documentTitle"
          class="w-full px-2 py-1 text-xs border rounded mb-3"
          placeholder="Título del documento"
        />
        <button
          @click="exportPDF"
          :disabled="isExporting"
          class="w-full flex items-center justify-center gap-2 px-3 py-2 text-sm rounded transition-colors bg-red-600 hover:bg-red-700 text-white"
        >
          <GoogleIcon name="picture_as_pdf" class="text-sm" />{{
            isExporting ? "Generando..." : "Exportar PDF"
          }}
        </button>
      </div>
      <div class="p-3 lg:p-4 flex-1 overflow-y-auto">
        <h3
          class="text-xs font-semibold text-gray-500 uppercase tracking-wider mb-3"
        >
          Elementos
        </h3>
        <div class="grid grid-cols-1 gap-2">
          <Draggable
            v-for="el in availableElements"
            :key="el.type"
            v-bind="el"
          />
        </div>
        <div class="pt-4 mt-4 border-t">
          <button
            v-if="totalElements > 0"
            @click="clearCanvas"
            class="w-full flex items-center justify-center gap-1 px-2 py-1 text-xs text-red-600 hover:bg-red-50 rounded"
          >
            <GoogleIcon name="delete" class="text-sm" />Limpiar Todo
          </button>
        </div>
      </div>
    </div>
    <div class="flex-1 flex flex-col min-h-0">
      <TextFormatter
        :editor="activeEditor"
        :selected-element="selectedElement"
        :is-table-editing="isTableEditing"
      />
      <PDFViewport
        :pages="pages"
        :current-page="currentPage"
        @page-change="(p) => (currentPage = p)"
        @add-page="addPage"
        @delete-page="deletePage"
        @drop="handleDrop"
        @click="deselectAll"
        @page-size-change="handlePageSizeChange"
      >
        <template #elements="{ page, dimensions }">
          <CanvasElement
            v-for="element in page.elements"
            :key="element.id"
            :element="element"
            :is-selected="selectedElementId === element.id"
            :page-dimensions="dimensions"
            @select="selectElement"
            @delete="deleteElement"
            @update="updateElement"
            @move="moveElement"
            @editor-active="(editor) => (activeEditor = editor)"
            @table-editing="handleTableEditing"
            @edit-table="openTableEditor"
          />
        </template>
      </PDFViewport>
    </div>

    <!-- Modal de edición de tabla -->
    <TableEditorModal
      v-if="isTableModalOpen && editingTable"
      :model-value="editingTable.content"
      @save="saveTableContent"
      @cancel="closeTableEditor"
    />
  </div>
</template>
