import { createRequire } from 'module';

const require = createRequire(import.meta.url);

// eslint-disable-next-line @typescript-eslint/no-explicit-any
let pdfParse: any;

try {
    pdfParse = require('pdf-parse');
} catch (e) {
    console.error('CRITICAL ERROR: Could not load "pdf-parse". Is it installed?', e);
}

export interface ExtractedData {
    name?: string;
    manufacturer?: string;
    type?: string;
    solidsVolume?: number;
    density?: number;
    yieldTheoretical?: number;
    dftReference?: number;
    yieldFactor?: number;
    wftMin?: number;
    wftMax?: number;
    dftMin?: number;
    dftMax?: number;
    reducer?: string;
    mixingRatioWeight?: string;
    mixingRatioVolume?: string;
    description?: string;
}

const COMMON_MANUFACTURERS = [
    'WEG', 'SHERWIN WILLIAMS', 'SHERWIN-WILLIAMS', 'INTERNATIONAL', 'AKZONOBEL', 'HEMPEL', 'JOTUN', 'RENNER', 'RENNER HERRMANN', 'PPG', 'SUMARÉ', 'SUMARE'
];

const PAINT_TYPES = [
    { key: 'Epóxi', keywords: ['epóxi', 'epoxi', 'epoxy'] },
    { key: 'Poliuretano (PU)', keywords: ['poliuretano', 'polyurethane', 'pu'] },
    { key: 'Rico em Zinco', keywords: ['zinco', 'zinc'] },
    { key: 'Alquídica', keywords: ['alquídica', 'alkyd'] },
    { key: 'Acrílica', keywords: ['acrílica', 'acrylic'] },
    { key: 'Fenólica', keywords: ['fenólica', 'phenolic'] },
    { key: 'Silicone', keywords: ['silicone'] }
];

export async function extractDataFromPdf(buffer: Buffer): Promise<ExtractedData> {
    if (!pdfParse) {
        console.error('pdf-parse library is not loaded. Cannot extract.');
        return {};
    }

    let text = '';

    try {
        console.log('Using pdf-parse v1.1.1 logic...');
        // pdf-parse v1.1.1 returns a Promise resolving to data object { text: string, ... }
        const data = await pdfParse(buffer);
        text = data.text;

        // Log first few chars to debug
        console.log('--- START EXTRACTED TEXT (First 200 chars) ---');
        console.log(text.substring(0, 200));
        console.log('--- END EXTRACTED TEXT ---');

    } catch (error: unknown) {
        const err = error as Error;
        console.error('pdf-parse extraction failed:', err.message, err);
        return {};
    }

    // Attempt 2: OCR logic check
    if (!text || text.trim().length < 20) {
        console.warn('Text extracted is empty or too short. This might be an image PDF.');
        // OCR placeholder - we need image conversion first which is hard without binaries
    }

    if (text) {
        return parseText(text);
    }

    return {};
}

// eslint-disable-next-line @typescript-eslint/no-unused-vars
export async function extractDataWithOCR(_buffer: Buffer): Promise<ExtractedData> {
    // Placeholder - still requires image conversion logic not present here
    console.warn('OCR requested but not implemented (requires PDF to Image conversion)');
    return {};
}

export function parseText(text: string): ExtractedData {
    const result: ExtractedData = {};
    const cleanText = text.replace(/\s+/g, ' ').trim();
    // Keep case for some checks, lower for others
    const lowerText = cleanText.toLowerCase();

    // 1. Solids Volume
    // "Sólidos por Volume", "Vol. Sólidos", "Volume Solids", "Solids by Volume"
    // Handle variants like "72 ± 2" or "72 +/- 2" or just "72"
    const solidsMatch = cleanText.match(/(?:Sólidos\s*(?:por|em)?\s*Vol\.?|Volume\s*(?:de)?\s*Sólidos|Solids\s*(?:by)?\s*Vol\.?|Sólidos\s*Volumétricos)[^0-9\n]*?(\d+(?:[.,]\d+)?)/i);
    if (solidsMatch && solidsMatch[1]) {
        result.solidsVolume = parseFloat(solidsMatch[1].replace(',', '.'));
    }

    // 2. Yield (Rendimento)
    // "Rendimento Teórico", "Rendimento", "Theoretical Spreading Rate"
    // Look for unit m2/L, m²/L, m2/l
    const yieldMatch = cleanText.match(/(?:Rendimento(?:\s*Teórico)?|Theoretical\s*Spreading\s*Rate)[^0-9\n]*?(\d+(?:[.,]\d+)?)\s*(?:m[²2]\/L|m2\/l)/i);
    if (yieldMatch && yieldMatch[1]) {
        result.yieldTheoretical = parseFloat(yieldMatch[1].replace(',', '.'));
    }

    // 2.1 Dry Film Thickness (DFT) Reference (Espessura)
    // "Espessura Seca", "DFT", "EPS"
    // Look for unit µm, microns
    const dftMatch = cleanText.match(/(?:Espessura\s*(?:de)?\s*(?:Camada|Filme)?\s*Sec[oa]|Dry\s*Film\s*Thickness|DFT|EPS)[^0-9\n]*?(\d+(?:[.,]\d+)?)\s*(?:µm|microns|micra|micrometros|micrômetros)/i);
    if (dftMatch && dftMatch[1]) {
        result.dftReference = parseFloat(dftMatch[1].replace(',', '.'));
    }

    // 2.2 Yield Factor Calculation
    if (result.solidsVolume) {
        result.yieldFactor = parseFloat((result.solidsVolume * 10).toFixed(2));
    } else if (result.yieldTheoretical && result.dftReference) {
        result.yieldFactor = parseFloat((result.yieldTheoretical * result.dftReference).toFixed(2));
    }

    // 3. Density
    const densityMatch = cleanText.match(/(?:Densidade|Massa\s*Específica|Specific\s*Gravity|Peso\s*Específico)[^0-9\n]*?(\d+(?:[.,]\d+)?)/i);
    if (densityMatch && densityMatch[1]) {
        // Sanity check: Density usually between 0.8 and 2.5 g/cm3 for paints
        const val = parseFloat(densityMatch[1].replace(',', '.'));
        if (val > 0.5 && val < 3.0) {
            result.density = val;
        }
    }

    // 4. WFT and DFT Ranges
    // Range formats: "100 a 200", "100 - 200", "100 to 200"

    // WFT
    const wftRangeMatch = cleanText.match(/(?:Espessura\s*Úmida|Wet\s*Film\s*Thickness|WFT)[^0-9\n]*?(\d+(?:[.,]\d+)?)\s*(?:a|-|to)\s*(\d+(?:[.,]\d+)?)/i);
    if (wftRangeMatch) {
        result.wftMin = parseFloat(wftRangeMatch[1].replace(',', '.'));
        result.wftMax = parseFloat(wftRangeMatch[2].replace(',', '.'));
    }

    // DFT Range (if not single ref)
    const dftRangeMatch = cleanText.match(/(?:Espessura\s*Seca|Dry\s*Film\s*Thickness|DFT|EPS)[^0-9\n]*?(\d+(?:[.,]\d+)?)\s*(?:a|-|to)\s*(\d+(?:[.,]\d+)?)/i);
    if (dftRangeMatch) {
        const min = parseFloat(dftRangeMatch[1].replace(',', '.'));
        const max = parseFloat(dftRangeMatch[2].replace(',', '.'));
        // If we found a reference DFT earlier, verify if it fits here or if this is better
        result.dftMin = min;
        result.dftMax = max;
        if (!result.dftReference) {
            result.dftReference = (min + max) / 2; // Average as ref if missing
        }
    }

    // 5. Reducer
    // "Diluente:", "Redutor:", "Thinner"
    const reducerMatch = cleanText.match(/(?:Diluente|Redutor|Thinner)[\s.:]*([A-Za-z0-9.\-\s]+?)(?:(?=\s[A-Z])|$)/i);
    if (reducerMatch && reducerMatch[1] && reducerMatch[1].length > 3) {
        result.reducer = reducerMatch[1].trim();
    }

    // 6. Mixing Ratio
    // Search for "A : B" patterns or "Component A ... Component B"
    const ratioMatch = cleanText.match(/(?:Relação\s*de\s*Mistura|Mixing\s*Ratio)[^0-9]*?(\d+)\s*[:/]\s*(\d+)/i);
    if (ratioMatch) {
        result.mixingRatioVolume = `${ratioMatch[1]} : ${ratioMatch[2]}`;
    } else {
        // Fallback for separated components listing
        const compA = cleanText.match(/Comp(?:onente)?\.?\s*A\s*[^0-9]*?(\d+(?:[.,]\d+)?)/i);
        const compB = cleanText.match(/Comp(?:onente)?\.?\s*B\s*[^0-9]*?(\d+(?:[.,]\d+)?)/i);
        if (compA && compB) {
            result.mixingRatioVolume = `${compA[1].replace(/[.,]0+$/, '')} : ${compB[1].replace(/[.,]0+$/, '')}`;
        }
    }

    // 7. Manufacturer
    for (const manufacturer of COMMON_MANUFACTURERS) {
        if (cleanText.toUpperCase().includes(manufacturer)) {
            result.manufacturer = manufacturer;
            break;
        }
    }

    // 8. Type
    for (const type of PAINT_TYPES) {
        if (type.keywords.some(k => lowerText.includes(k))) {
            result.type = type.key;
            break;
        }
    }

    // 9. Name
    // Heuristic: Often in the first 200 chars, defined by "PRODUTO:" or just uppercase line
    const nameMatch = cleanText.match(/(?:PRODUTO|NOME|NAME)\s*[:.]?\s*([A-Za-z0-9\-\s]+?)(?:\s+(?:REFERÊNCIA|DESCRIÇÃO|CÓDIGO)|$)/i);
    if (nameMatch && nameMatch[1]) {
        result.name = nameMatch[1].trim();
    } else {
        // Use the first non-trivial line if logic fails, usually filename is passed by frontend anyway
    }

    return result;
}
