/**
 * Utility to map OCR document data to the "Excel Screenshot Summary" format
 * and ensure uniform detail field results for the CPC-CSD module.
 */

const FIELD_DEFAULTS: any = {
    AADHAAR: ['customer_name', 'aadhar_number', 'name', 'dob', 'gender', 'address'],
    ADHAAR: ['customer_name', 'aadhar_number', 'name', 'dob', 'gender', 'address'],
    CSD_PO: ['customer_name', 'po_number', 'po_amount', 'signature_and_stamp'],
    GENERIC_INVOICE: ['customer_name', 'order_or_auth_number', 'invoice_value', 'invoice_date', 'tax_amount'],
    RETAIL_INVOICE: ['customer_name', 'order_or_auth_number', 'invoice_value', 'invoice_date', 'tax_amount'],
    INVOICE: ['customer_name', 'order_or_auth_number', 'invoice_value', 'invoice_date', 'tax_amount'],
    AUTHORITY_LETTER: [
        'customer_name',
        'letter_number',
        'letter_amount',
        'signature_and_stamp',
        'authorized_person_name',
        'order_or_authorisation_number',
        'invoice_value',
        'govt_signatory_and_stamp_present',
        'authority_grantor_name',
        'valid_until',
        'purpose',
        'date_of_issue'
    ],
    AUTH_LETTER: [
        'customer_name',
        'letter_number',
        'letter_amount',
        'signature_and_stamp',
        'authorized_person_name',
        'order_or_authorisation_number',
        'invoice_value',
        'govt_signatory_and_stamp_present',
        'authority_grantor_name',
        'valid_until',
        'purpose',
        'date_of_issue'
    ]
};

const CRITERIA_MAP: any = {
    // Fallbacks when doc-type–specific text is not applied (UI / reports only)
    aadhaar_number: 'Exact match',
    aadhar_number: 'Exact match',
    name: 'Text match',
    dob: 'Exact after normalization',
    gender: 'Exact (M/Male normalize)',
    address: 'Text match',

    customer_name: 'Text match',
    order_or_auth_number: 'Text match',
    order_or_authorisation_number: 'Text match',
    invoice_value: 'Amount comparison',
    invoice_date: 'Date comparison',
    tax_amount: 'Amount comparison',

    authorized_person_name: 'Text match',
    authority_grantor_name: 'Text match',
    letter_number: 'Text match',
    valid_until: 'Exact date match',
    purpose: 'Text match',
    date_of_issue: 'Exact match',

    mail_extraction: 'Email on document vs expected',

    stamp: 'Signature / stamp vs expected',
    signatory: 'Signature / stamp vs expected',
    govt_signatory_and_stamp_present: 'Signature / stamp vs expected',
    stamp_sign_present: 'Signature / stamp vs expected',
    signature_and_stamp: 'Signature / stamp vs expected',
    po_number: 'Exact match',
    po_amount: 'Amount comparison',
    letter_amount: 'Amount comparison'
};

/** Normalize document type for criteria copy (matches validation service naming). */
function normalizeCriteriaDocType(docType?: string): string {
    const u = String(docType || '').toUpperCase().trim();
    if (u.includes('AADHAAR') || u === 'ADHAAR') return 'AADHAAR';
    if (u.includes('CPC_AUTH') || u.includes('AUTHORITY')) return 'CPC_AUTH';
    if (u.includes('CSD_PO') || u.includes('PURCHASE') || (u.includes('PO') && u.includes('CSD'))) return 'CSD_PO';
    if (u.includes('RETAIL') || u.includes('INVOICE')) return 'RETAIL_INVOICE';
    return u;
}

/** Human-readable accuracy criteria for reports / API field_results (shared with validation). */
export function getCriteriaLabel(field: string, docType?: string): string {
    if (!field) return 'Exact check';
    const f = field.toLowerCase();
    const dt = normalizeCriteriaDocType(docType);

    if ((f === 'order_or_authorisation_number' || f === 'po_number') && dt === 'CSD_PO') {
        return 'Exact match';
    }
    if (f === 'letter_number' && dt === 'CPC_AUTH') {
        return 'Text match';
    }
    if (f === 'aadhaar_number' || f === 'aadhar_number') {
        return 'Exact match';
    }
    if ((f === 'customer_name' || f === 'name' || f === 'authorized_person_name') && (dt === 'CSD_PO' || dt === 'CPC_AUTH' || dt === 'AADHAAR')) {
        return 'Text match';
    }
    if ((f === 'invoice_value' || f === 'po_amount') && dt === 'CSD_PO') {
        return 'Amount comparison';
    }
    if ((f === 'invoice_value' || f === 'letter_amount') && dt === 'CPC_AUTH') {
        return 'Amount comparison';
    }
    if (f === 'govt_signatory_and_stamp_present' || f === 'stamp_sign_present' || f === 'signature_and_stamp') {
        return 'Signature / stamp vs expected';
    }
    if (f === 'mail_extraction') {
        return 'Email on document vs expected';
    }

    const key = Object.keys(CRITERIA_MAP).find((k: string) => f.includes(k.toLowerCase()));
    return CRITERIA_MAP[key || ''] || 'Exact check';
}

/** Normalize match % from persisted validation row (snake or camel). */
function matchPctFromResult(found: Record<string, unknown> | null | undefined): number | null {
    if (!found || typeof found !== 'object') return null;
    const row = found as { match_percentage?: unknown; matchPercentage?: unknown };
    const v = row.match_percentage != null ? row.match_percentage : row.matchPercentage;
    if (v == null || v === '') return null;
    const n = Number(v);
    if (!Number.isFinite(n)) return null;
    return Math.round(n);
}

export class CpcHistoryService {
    /**
     * Transforms a document into a detailed field result array.
     * Ensures that if a field was expected but not extracted, it still shows up as a fail.
     */
    static getDetailedFieldResults(doc: any) {
        const rawDocTypeUpper = String(doc.documentType || doc.document_type || '').trim();
        const rawType = rawDocTypeUpper.toLowerCase().replace(/_/g, ' ');

        // Normalize type for internal lookup
        let type = 'UNKNOWN';
        if (rawType.includes('aadhaar') || rawType.includes('adhaar')) type = 'AADHAAR';
        else if (rawType.includes('authority') || rawType.includes('auth') || rawType.includes('cpc letter')) type = 'AUTHORITY_LETTER';
        else if (rawType.includes('invoice')) type = 'GENERIC_INVOICE';
        else if (rawType.includes('purchase order') || rawType.includes('csd_po') || rawType.includes('po'))
            type = 'CSD_PO'; 

        const hardcodedKeys = FIELD_DEFAULTS[type] || [];

        // Read expected/extracted values from ALL possible variant keys
        const expectedObj = doc.msdPayload || doc.msd_payload || {};
        const extractedObj = doc.extractedFields || doc.extracted_fields || {};

        const payloadKeys = Object.keys(expectedObj);
        const expectedKeys = payloadKeys.length > 0 ? payloadKeys : hardcodedKeys;

        const rawFr = doc.fieldResults ?? doc.field_results;
        const existingResults = Array.isArray(rawFr) ? rawFr : [];

        const finalResults = expectedKeys.map((key: string) => {
            const found = existingResults.find((r: any) => r.field?.toLowerCase() === key.toLowerCase());

            const msdVal = expectedObj[key] || (found ? found.expected : '-');
            const ocrVal = extractedObj[key] || (found ? (found.extracted || found.actual) : '-');

            if (found) {
                const mp = matchPctFromResult(found);
                const mpNum = mp != null ? mp : 0;
                const st = String((found as { status?: string }).status || '');
                const pass =
                    (found as { pass?: boolean }).pass === true ||
                    st === 'SUCCESSFUL' ||
                    st === 'MATCH';
                return {
                    ...found,
                    field: key,
                    expected: String(msdVal),
                    extracted: String(ocrVal),
                    status: st || (found as { status?: string }).status,
                    match_percentage: mpNum,
                    matchPercentage: mpNum,
                    accuracy:
                        (found as { accuracy?: string }).accuracy ||
                        (mp != null ? `${mp}%` : `${mpNum}%`),
                    criteria: (found as { criteria?: string }).criteria || getCriteriaLabel(key, rawDocTypeUpper),
                    pass,
                    message:
                        (found as { reason?: string }).reason ||
                        (found as { message?: string }).message ||
                        (pass ? 'Matched' : 'Mismatch detected')
                };
            }
            return {
                field: key,
                expected: String(msdVal),
                extracted: String(ocrVal),
                match_percentage: 0,
                matchPercentage: 0,
                accuracy: '0%',
                criteria: getCriteriaLabel(key, rawDocTypeUpper),
                pass: false,
                status: 'MISSING',
                message: 'Not found'
            };
        });

        return finalResults;
    }

    /**
     * Generates the "Excel Screenshot Summary" row for a document.
     */
    static getSummaryRow(doc: any, idx: number) {
        const rawType = String(doc.documentType || doc.document_type || '')
            .toLowerCase()
            .trim()
            .replace(/_/g, ' ');
        const results = this.getDetailedFieldResults(doc);
        const findRes = (key: string) => results.find((r: any) => r.field.toLowerCase() === key.toLowerCase()) || null;


        const booking_type = doc.claimId?.startsWith('CPC') ? 'CPC' : 'CSD';
        const booking_number = doc.bookingId || doc.claimId || 'N/A';

        const mapGroup = (fieldKey: string, altKeys: string[] = []) => {
            const res = findRes(fieldKey) || (altKeys.length > 0 ? results.find((r: any) => altKeys.some(ak => r.field.toLowerCase() === ak.toLowerCase())) : null);

            if (!res) return { msd: 'N.A.', ocr: 'N.A.', accuracy_pct: 'N.A.', criteria: 'N.A.', is_match: 'N.A.', isNA: true };
            return {
                msd: res.expected,
                ocr: res.extracted,
                accuracy_pct: res.accuracy,
                criteria: res.criteria,
                is_match: res.pass ? 'Yes' : 'No',
                isNA: false
            };
        };

        let f1, f2, f3, f4, f5;
        const na = { msd: 'N.A.', ocr: 'N.A.', accuracy_pct: 'N.A.', criteria: 'N.A.', is_match: 'N.A.', isNA: true };

        if (rawType.includes('aadhaar') || rawType.includes('adhaar')) {
            f1 = mapGroup('customer_name', ['name', 'authorized_person_name']);
            f2 = na;
            f3 = mapGroup('aadhar_number', ['aadhaar_number']);
            f4 = na;
            f5 = na; 
        } else if (rawType.includes('authority') || rawType.includes('auth') || rawType.includes('cpc letter')) {
            f1 = mapGroup('customer_name', ['authorized_person_name', 'name']);
            f2 = mapGroup('letter_number', [
                'order_or_auth_number',
                'letter_no',
                'order_or_authorisation_number'
            ]);
            f3 = na;
            f4 = mapGroup('letter_amount', ['invoice_value', 'amount']);
            f5 = mapGroup('signature_and_stamp', ['govt_signatory_and_stamp_present', 'stamp', 'signatory', 'stamp_sign_present']);
        } else if (rawType.includes('purchase order') || rawType.includes('csd_po') || rawType.includes('po')) {
            f1 = mapGroup('customer_name');
            f2 = mapGroup('po_number', ['order_or_authorisation_number', 'order_or_auth_number']);
            f3 = na;
            f4 = mapGroup('po_amount', ['invoice_value', 'amount']);
            f5 = mapGroup('signature_and_stamp', ['govt_signatory_and_stamp_present', 'stamp', 'signatory', 'stamp_sign_present']);
        } else if (rawType.includes('invoice')) {
            f1 = mapGroup('customer_name');
            f2 = mapGroup('order_or_auth_number', ['order_or_authorisation_number']);
            f3 = na;
            f4 = mapGroup('invoice_value', ['tax_amount']);
            f5 = mapGroup('govt_signatory_and_stamp_present', ['stamp', 'signatory', 'stamp_sign_present']);
        } else {
            f1 = mapGroup('customer_name', ['name', 'authorized_person_name']);
            f2 = mapGroup('order_or_auth_number', ['aadhaar_number', 'order_or_authorisation_number']);
            f3 = na;
            f4 = mapGroup('invoice_value', ['amount']);
            f5 = mapGroup('govt_signatory_and_stamp_present', ['stamp', 'signatory', 'stamp_sign_present']);
        }

        const vs = String(doc.validationStatus || '').toUpperCase();
        const final_validation =
            vs === 'SUCCESSFUL' || vs === 'MATCH' || vs === 'APPROVED' ? 'Successful' : 'Unsuccessful';

        return {
            booking_type,
            booking_number,
            document_count: idx + 1,
            document_name: rawType.toUpperCase(),
            f1, f2, f3, f4, f5, 
            customer_name_group: f1,
            po_or_auth_number_group: f2,
            aadhaar_number_group: f3,
            amount_group: f4,
            stamp_group: f5,
            field_results: results,
            final_validation,
            createdAt: doc.createdAt
        };
    }
}
