<template>
    <div class="p-4">
        <div class="dropbox p-5 mb-4 bg-light text-secondary rounded text-center position-relative"
             @dragenter.prevent="onDragEnter"
             @dragover.prevent="onDragOver"
             @drop.prevent="onDrop"
             :class="{ 'bg-secondary text-white': isDragging }">
            <div id="drop">
                <span>
                    <img class="logo mb-3" :src="asset('images/logo.png')" alt="Your Logo" v-if="false"><br>
                    Drag and drop your PDF file here
                </span>
            </div>

            <div v-if="filesProcessed" class="alert alert-success mt-3 mb-0" role="alert">
                <strong>{{ fileName }}</strong> content extracted. <br/>
                <div class="row m-b-10">
                    <div class="col">
                         <span class="text-complete pointer requestModal text-underline" data-type="previewExtractedTable">Preview</span>
                    </div>
                </div>
            </div>

            <div class="d-flex justify-content-center mt-3">
                <label for="pdf-file-input"
                    class="btn btn-sm btn-outline-complete rounded-0 pointer flex-fill mx-1 text-center mb-0">
                    Browse files
                </label>

                <button type="button"
                        class="btn btn-sm btn-outline-complete rounded-0 pointer flex-fill mx-1"
                        v-if="isPurchaseOrderWithTablesPDF"
                        @click="exportToCSV"
                        :disabled="isExporting">
                    {{ isExporting ? 'Exporting...' : 'Export Extracted Content (csv)' }}
                </button>

                <button type="button"
                        class="btn btn-sm btn-outline-complete rounded-0 pointer flex-fill mx-1"
                        v-if="isPurchaseOrderWithTablesPDF"
                        @click="importToSystem"
                        :disabled="isImporting">
                    {{ isImporting ? 'Uploading...' : 'Continue Upload' }}
                </button>
            </div>

            <input type="file" id="pdf-file-input" @change="onFileChange" accept="application/pdf" style="display: none;" />
        </div>

        <modal-component class="animate__animated animate__fast animate__fadeIn" styleType="fill-in" type="previewExtractedTable" size="large">
            <div class="row p-t-25 text-left">
                <div class="col bg-white padding-40 b-rad-lg">
                    <div class="modal-header">
                        <h2>Preview Extracted Content</h2>
                    </div>
                    <div id="html-result" v-if="tables.length > 0">
                        <div v-for="(table, tIndex) in tables" :key="tIndex" class="table-wrapper">
                            <table border="1">
                                <tbody>
                                    <tr v-for="(row, rIndex) in table" :key="rIndex">
                                        <template v-for="(cell, cIndex) in row" :key="cIndex">
                                            <td
                                                v-if="!cell.hidden"
                                                :colspan="cell.colspan"
                                                :rowspan="cell.rowspan">
                                                {{ cell.text }}
                                            </td>
                                        </template>
                                    </tr>
                                </tbody>
                            </table>
                        </div>
                    </div>
                </div>
            </div>
        </modal-component>
    </div>
</template>

<script setup lang="ts">
import { ref, reactive, computed } from 'vue';
import { useRequest } from '@/composables/useRequest';
import { useQueueStore } from '@/stores/queue';

const props = defineProps<{
    section: string;
    bookingId: number;
}>();

const emit = defineEmits(['updatedList']);

const { submit } = useRequest();
const queueStore = useQueueStore();

const isDragging = ref(false);
const tables = ref<any[]>([]);
const nonTableData = ref<any[]>([]);
const allTablesForExportImport = ref<any[]>([]);
const isExporting = ref(false);
const isImporting = ref(false);
const filesProcessed = ref(false);
const fileName = ref('');
const mergeTableRemoveFirstLine = ref(false);

const parameters = reactive({
    products: [] as any[],
    productsMetadata: [] as any[]
});

const isPurchaseOrderWithTablesPDF = computed(() => allTablesForExportImport.value.length > 0);

const asset = (path: string) => (window as any).Vapor.asset(path);

const onDragEnter = () => { isDragging.value = true; };
const onDragOver = (e: DragEvent) => {
    isDragging.value = true;
    if (e.dataTransfer) e.dataTransfer.dropEffect = 'copy';
};
const onDrop = (e: DragEvent) => {
    isDragging.value = false;
    const files = e.dataTransfer?.files;
    if (files?.length) {
        processFile(files[0]);
    }
};
const onFileChange = (e: Event) => {
    const target = e.target as HTMLInputElement;
    const files = target.files;
    if (files?.length) {
        processFile(files[0]);
    }
};

const processFile = async (file: File) => {
    tables.value = [];
    allTablesForExportImport.value = [];
    filesProcessed.value = false;
    fileName.value = file.name;
    parameters.products = [];
    parameters.productsMetadata = [];

    try {
        await loadDependencies();
    } catch (error) {
        console.error("Failed to load PDF dependencies:", error);
        alert("Critical Error: Could not load PDF libraries.");
        return;
    }

    const reader = new FileReader();
    reader.onload = (e) => {
        const data = e.target?.result;
        if (data instanceof ArrayBuffer) {
            parseContent(data);
        }
    };
    reader.readAsArrayBuffer(file);
};

const loadDependencies = async () => {
    const pdfjsLib = (window as any).pdfjsLib;
    const pdf_table_extractor = (window as any).pdf_table_extractor;

    if (pdfjsLib && pdf_table_extractor) {
        return;
    }
    if (!pdfjsLib) {
        await loadScript((window as any).pdfJsUrl);
        (window as any).pdfjsLib.GlobalWorkerOptions.workerSrc = (window as any).pdfWorkerJsUrl;
    }
    if (!pdf_table_extractor) {
        await loadScript((window as any).pdfTableExtractorJsUrl);
    }
};

const loadScript = (src: string) => {
    return new Promise<void>((resolve, reject) => {
        if (document.querySelector(`script[src="${src}"]`)) {
            resolve();
            return;
        }
        const script = document.createElement('script');
        script.src = src;
        script.onload = () => resolve();
        script.onerror = reject;
        document.head.appendChild(script);
    });
};

const parseContent = (content: ArrayBuffer) => {
    const pdfjsLib = (window as any).pdfjsLib;
    const pdf_table_extractor = (window as any).pdf_table_extractor;

    if (!pdfjsLib || !pdf_table_extractor) {
        console.error('PDF.js or pdf-table-extractor not loaded.');
        alert('Required PDF libraries are missing.');
        return;
    }
    if (!pdfjsLib.GlobalWorkerOptions.workerSrc) {
        pdfjsLib.GlobalWorkerOptions.workerSrc = '/js/pdf.worker.js';
    }

    const loadingTask = pdfjsLib.getDocument(content);

    loadingTask.promise
        .then(async (doc: any) => {
            const result = await pdf_table_extractor(doc);
            processExtractedTables(result);
            await extractNonTableData4(doc, result);
            filesProcessed.value = true;
        })
        .catch((error: any) => {
            console.error("Error extracting tables:", error);
            alert("Error parsing PDF.");
        });
};

const processExtractedTables = (result: any) => {
    let extractedTables: any[] = [];
    let exportData: any[] = [];
    const pages = [...result.pageTables];

    pages.forEach(page_tables => {
        const tablesData = page_tables.tables;
        const merge_alias = page_tables.merge_alias;
        const merges = page_tables.merges;

        if (tablesData.length > 0) {
            let currentTable: any[] = [];

            for (let r = 0; r < tablesData.length; r++) {
                if (mergeTableRemoveFirstLine.value && page_tables.page != 1 && r == 0) {
                    continue;
                }

                let rowCells: any[] = [];
                let rowForExport: any[] = [];

                for (let c = 0; c < tablesData[r].length; c++) {
                    let r_c = [r, c].join('-');

                    if (merge_alias[r_c]) {
                        rowCells.push({ hidden: true });
                        continue;
                    }

                    if (merges[r_c] && merges[r_c].width > 2) {
                        rowCells.push({ hidden: true });
                        continue;
                    }

                    let cell = {
                        text: tablesData[r][c],
                        hidden: false,
                        rowspan: 1,
                        colspan: 1
                    };

                    if (merges[r_c]) {
                        if (merges[r_c].width > 1) cell.colspan = merges[r_c].width;
                        if (merges[r_c].height > 1) cell.rowspan = merges[r_c].height;
                    }

                    rowCells.push(cell);
                    let value = tablesData[r][c];
                    let cleanValue = value.replace(/[\r\n]+/g, ' ').trim();
                    rowForExport.push(cleanValue);
                }

                currentTable.push(rowCells);

                if (rowForExport.length > 1) {
                    const limitedRowForExport = rowForExport.slice(0, 7);
                    const headerRow = exportData[0];
                    const isSameAsHeader = headerRow && limitedRowForExport.every((val, idx) => val === headerRow[idx]);

                    if (!isSameAsHeader) {
                        exportData.push(limitedRowForExport);
                    }
                }
            }
            extractedTables.push(currentTable);
        }
    });

    tables.value = extractedTables;
    allTablesForExportImport.value = exportData;
};

const extractNonTableData4 = async (doc: any, result: any) => {
    nonTableData.value = [];

    for (let i = 1; i <= doc.numPages; i++) {
        const page = await doc.getPage(i);
        const content = await page.getTextContent();
        const pageStrItems = content.items;
        const pageTableData = result.pageTables.find((pt: any) => pt.page === i);
        const tableBoxes: any[] = [];

        if (pageTableData?.tables?.length) {
            pageTableData.tables.forEach((table: any) => {
                let dataRowCount = 0;
                table.forEach((row: any) => {
                    const hasData = Array.isArray(row)
                        ? row.some(cell => cell.trim().length > 0)
                        : String(row).trim().length > 0;
                    if (hasData) dataRowCount++;
                });

                if (dataRowCount > 1) {
                    let xMin = Infinity, xMax = -Infinity, yMin = Infinity, yMax = -Infinity;

                    table.forEach((row: any, rIdx: number) => {
                        if (dataRowCount === 1 && rIdx !== 0) return;

                        if (Array.isArray(row)) {
                            row.forEach(cell => {
                                const lines = String(cell).split('\n').map(l => l.trim()).filter(Boolean);
                                lines.forEach(line => {
                                    const matched = pageStrItems.find((item: any) => item.str.includes(line));
                                    if (matched) {
                                        const x = matched.transform[4];
                                        const y = matched.transform[5];
                                        const w = matched.width || 0;
                                        xMin = Math.min(xMin, x);
                                        xMax = Math.max(xMax, x + w);
                                        yMin = Math.min(yMin, y);
                                        yMax = Math.max(yMax, y);
                                    }
                                });
                            });
                        } else if (typeof row === 'string') {
                            const lines = row.split('\n').map(l => l.trim()).filter(Boolean);
                            lines.forEach(line => {
                                const matched = pageStrItems.find((item: any) => item.str.includes(line));
                                if (matched) {
                                    const x = matched.transform[4];
                                    const y = matched.transform[5];
                                    const w = matched.width || 0;
                                    xMin = Math.min(xMin, x);
                                    xMax = Math.max(xMax, x + w);
                                    yMin = Math.min(yMin, y);
                                    yMax = Math.max(yMax, y);
                                }
                            });
                        }
                    });

                    if (xMin < Infinity) {
                        tableBoxes.push({ xMin, xMax, yMin, yMax });
                    }
                }
            });
        }

        const filteredItems = pageStrItems.filter((item: any) => {
            const x = item.transform[4];
            const y = item.transform[5];
            const str = item.str.trim();
            if (!str) return false;

            const isInTable = tableBoxes.some(box =>
                x >= box.xMin && x <= box.xMax &&
                y >= box.yMin && y <= box.yMax
            );

            return !isInTable;
        });

        const lines: Record<string, any[]> = {};
        const tolerance = 5;

        filteredItems.forEach((item: any) => {
            const y = item.transform[5];
            const x = item.transform[4];
            let added = false;

            for (const lineY in lines) {
                if (Math.abs(parseFloat(lineY) - y) < tolerance) {
                    lines[lineY].push({ str: item.str, x });
                    added = true;
                    break;
                }
            }

            if (!added) {
                lines[y] = [{ str: item.str, x }];
            }
        });

        const sortedLineKeys = Object.keys(lines)
            .sort((a, b) => parseFloat(b) - parseFloat(a));

        const readableContent = sortedLineKeys.map(key => {
            const lineItems = lines[key].sort((a: any, b: any) => a.x - b.x);
            return lineItems.map((i: any) => i.str).join(' ');
        });

        if (readableContent.length) {
            nonTableData.value.push({
                page: i,
                content: readableContent
            });
        }
    }
};

const escapeCSV = (value: any) => {
    if (value === null || value === undefined) return '';
    const str = value.toString();
    if (str.includes(',') || str.includes('"') || str.includes('\n')) {
        return `"${str.replace(/"/g, '""')}"`;
    }
    return str;
};

const exportToCSV = () => {
    if (isExporting.value) return;
    isExporting.value = true;

    parameters.products = [];
    parameters.productsMetadata = [];
    for (let index = 0; index < allTablesForExportImport.value.length; index++) {
        if (index === 0) continue;

        const rowArray = allTablesForExportImport.value[index];
        const partNumber = rowArray[1] || '';
        let productName = rowArray[2] || '';
        const specification = rowArray[3] || '';
        const quantity = rowArray[4] || '';
        const rawUnitPrice = rowArray[5] || '';
        const unitPrice = rawUnitPrice.match(/\d+\.?\d*/)?.[0] || '';

        productName = productName.replace(/^["'](.*)["']$/, '$1');

        parameters.products.push({
            stockCode: partNumber,
            description: productName + ' | ' + specification,
            quantity: quantity,
            unit_price: unitPrice
        });
    }
    parameters.productsMetadata = nonTableData.value;

    submit(route('api.transaction.po.etl', props.bookingId), 'post', props.section + 'PDFExport', true, true, parameters, {
        successHandler: (response: any, section?: string) => {
            try {
                const BOM = '\uFEFF';
                let csvContent = "stock code,description,quantity,unit price\r\n";
                response.payload.forEach((item: any) => {
                    const formattedRow = [
                        item.stockCode,
                        escapeCSV(item.description),
                        item.quantity,
                        item.unit_price
                    ].join(',');

                    csvContent += formattedRow + "\r\n";
                });

                const blob = new Blob([BOM + csvContent], { type: 'text/csv;charset=utf-8;' });
                const link = document.createElement("a");
                link.href = URL.createObjectURL(blob);
                link.setAttribute("download", "order_details.csv");
                document.body.appendChild(link);
                link.click();
                document.body.removeChild(link);

                parameters.products = response.payload;
                parameters.productsMetadata = [];
            } catch (e) {
                console.error("Export failed:", e);
                alert("Export failed. Please try again.");
            } finally {
                isExporting.value = false;
            }
        },
        errorHandler: (_response: any, statusCode: number, sectionName?: string) => {
            isExporting.value = false;
            isImporting.value = false;
        }
    });
};

const importToSystem = () => {
    if (isImporting.value) return;
    isImporting.value = true;

    if (parameters.products && parameters.products.length === 0) {
        for (let index = 0; index < allTablesForExportImport.value.length; index++) {
            if (index === 0) continue;

            const rowArray = allTablesForExportImport.value[index];
            const partNumber = rowArray[1] || '';
            let productName = rowArray[2] || '';
            const specification = rowArray[3] || '';
            const quantity = rowArray[4] || '';
            const rawUnitPrice = rowArray[5] || '';
            const unitPrice = rawUnitPrice.match(/\d+\.?\d*/)?.[0] || '';

            productName = productName.replace(/^["'](.*)["']$/, '$1');

            parameters.products.push({
                stockCode: partNumber,
                description: productName + ' | ' + specification,
                quantity: quantity,
                unit_price: unitPrice
            });
        }
        parameters.productsMetadata = nonTableData.value;
    }

    submit(route('api.transaction.po.import', props.bookingId), 'post', props.section + 'PDFImport', true, true, parameters, {
        successHandler: (response: any, section?: string) => {
            queueStore.reloadList({ name: props.section });
            emit('updatedList');
            isImporting.value = false;
        },
        errorHandler: (_response: any, statusCode: number, sectionName?: string) => {
            isExporting.value = false;
            isImporting.value = false;
        }
    });
};
</script>

<style scoped>
.dropbox {
    border: 2px dashed #bbb;
    border-radius: 5px;
    padding: 25px;
    text-align: center;
    color: #bbb;
    margin-bottom: 20px;
    transition: background-color 0.2s;
}

.table-wrapper {
    margin-bottom: 20px;
    overflow-x: auto;
}

table {
    width: 100%;
    border-collapse: collapse;
}

td, th {
    border: 1px solid #ddd;
    padding: 8px;
}
</style>
