import { Request, Response } from 'express';
import db from '../../database/models/index.js';
const { FinancePayment, FnF, Application, Resignation, User, Outlet, FnFLineItem, TerminationRequest, FffClearance, AuditLog, RequestParticipant, Dealer } = db;
import { AuthRequest } from '../../types/express.types.js';
import { FNF_STATUS, AUDIT_ACTIONS, FNF_DEPARTMENTS, RESIGNATION_STAGES, TERMINATION_STAGES, ROLES } from '../../common/config/constants.js';
import { ResignationWorkflowService } from '../../services/ResignationWorkflowService.js';
import { TerminationWorkflowService } from '../../services/TerminationWorkflowService.js';
import { normalizeFnFStatus, normalizeClearanceStatus } from '../../common/utils/offboardingStatus.js';
import { safeAuditLogCreate } from '../../services/applicationAuditLog.service.js';
import { writeWorkflowActivityWorknote } from '../../common/utils/workflowWorknote.js';
import { resolveEntityUuidByType } from '../../common/utils/requestResolver.js';
import { NomenclatureService } from '../../common/utils/nomenclature.js';
import { NotificationService } from '../../services/NotificationService.js';
import { getFrontendBaseUrl } from '../../common/utils/frontendUrl.js';
import { v4 as uuidv4 } from 'uuid';

const portalBase = getFrontendBaseUrl();

const LINE_ITEM_DESCRIPTION_PREFIX = {
    DEPARTMENT_CLAIM: '[DEPARTMENT_CLAIM]',
    FINANCE_VALIDATED: '[FINANCE_VALIDATED]'
} as const;

const DEPARTMENT_CLAIM_DESCRIPTION = `${LINE_ITEM_DESCRIPTION_PREFIX.DEPARTMENT_CLAIM} Department Clearance - Manual Update`;

const withPrefix = (description: string, prefix: string) => {
    if (!description) return prefix;
    return description.startsWith(prefix) ? description : `${prefix} ${description}`;
};

const isDepartmentClaimLineItem = (item: any) =>
    typeof item?.description === 'string' && item.description.startsWith(LINE_ITEM_DESCRIPTION_PREFIX.DEPARTMENT_CLAIM);

const isFinanceValidatedLineItem = (item: any) =>
    typeof item?.description === 'string' && item.description.startsWith(LINE_ITEM_DESCRIPTION_PREFIX.FINANCE_VALIDATED);

const getActiveLineItems = (lineItems: any[]) =>
    (lineItems || []).filter((item: any) => item.isActive !== false);

const ensureFinanceDraftsFromDepartmentClaims = async (fnfId: string, userId: string | null = null) => {
    const allLineItems = await FnFLineItem.findAll({
        where: { fnfId },
        order: [['createdAt', 'ASC']]
    });

    const activeDepartmentClaims = allLineItems.filter((item: any) =>
        item.isActive !== false &&
        (item.sourceType === 'DepartmentClaim' || isDepartmentClaimLineItem(item))
    );

    for (const claim of activeDepartmentClaims) {
        const claimRootId = (claim as any).parentLineItemId || claim.id;
        const hasFinanceLineForClaim = allLineItems.some((item: any) =>
            (item.sourceType === 'FinanceValidated' || isFinanceValidatedLineItem(item)) &&
            ((item as any).parentLineItemId === claimRootId || item.department === claim.department)
        );

        if (hasFinanceLineForClaim) continue;

        const claimAmount = Math.abs(Number((claim as any).claimAmount ?? claim.amount) || 0);
        await FnFLineItem.create({
            fnfId,
            itemType: claim.itemType,
            description: withPrefix('Auto-seeded from department claim', LINE_ITEM_DESCRIPTION_PREFIX.FINANCE_VALIDATED),
            department: claim.department,
            amount: claimAmount,
            addedBy: userId,
            sourceType: 'FinanceValidated',
            version: 1,
            isActive: true,
            parentLineItemId: claimRootId,
            claimAmount,
            validatedAmount: claimAmount,
            varianceAmount: 0,
            financeDecision: 'Accepted',
            varianceReason: null
        });
    }
};

export const getDepartments = async (req: AuthRequest, res: Response) => {
    try {
        res.json({ success: true, departments: FNF_DEPARTMENTS });
    } catch (error) {
        res.status(500).json({ success: false, message: 'Error fetching departments' });
    }
};

export const uploadFnFDocument = async (req: AuthRequest, res: Response) => {
    try {
        const { id } = req.params;
        const fileUrl = req.file ? `/uploads/documents/${req.file.filename}` : req.body.fileUrl;

        if (!fileUrl) {
            return res.status(400).json({ success: false, message: 'No file uploaded' });
        }

        const documentName = (req.body?.documentName || '').toString().trim();
        if (!documentName) {
            return res.status(400).json({
                success: false,
                message: 'Document name is required.'
            });
        }

        const documentType = (req.body?.documentType || '').toString().trim() || null;

        const fnf = await FnF.findByPk(id);
        if (!fnf) {
            return res.status(404).json({ success: false, message: 'F&F settlement not found' });
        }

        const newEntry = {
            id: uuidv4(),
            name: documentName,
            documentType,
            originalFileName: req.file?.originalname || null,
            supportingDocument: fileUrl,
            department: 'Finance', // Default to Finance for generic F&F docs
            clearedAt: new Date().toISOString(),
            uploadedBy: req.user?.id || null
        };

        const updatedClearances = [
            ...(fnf.clearanceDocuments || []),
            newEntry
        ];

        await fnf.update({
            clearanceDocuments: updatedClearances
        });

        try {
            await db.FnFAudit.create({
                userId: req.user?.id || null,
                fnfId: String(id),
                action: AUDIT_ACTIONS.DOCUMENT_UPLOADED,
                remarks: `Document "${newEntry.name}" uploaded`,
                details: {
                    documentName: newEntry.name,
                    documentType: newEntry.documentType,
                    originalFileName: newEntry.originalFileName,
                    department: newEntry.department
                }
            });
        } catch (auditErr) {
            console.error('[uploadFnFDocument] Non-fatal audit failure:', auditErr);
        }

        res.json({ success: true, document: newEntry });
    } catch (error) {
        console.error('Error uploading F&F document:', error);
        res.status(500).json({ success: false, message: 'Error uploading F&F document' });
    }
};

export const getOnboardingPayments = async (req: AuthRequest, res: Response) => {
    try {
        const page = parseInt(req.query.page as string) || 1;
        const limit = parseInt(req.query.limit as string) || 10;
        const offset = (page - 1) * limit;

        const { count, rows: payments } = await FinancePayment.findAndCountAll({
            include: [{
                model: Application,
                as: 'application',
                attributes: ['applicantName', 'applicationId']
            }],
            order: [['createdAt', 'ASC']],
            limit,
            offset
        });
        res.json({ 
            success: true, 
            payments,
            meta: {
                total: count,
                totalPages: Math.ceil(count / limit),
                currentPage: page,
                limit
            }
        });
    } catch (error) {
        console.error('Get onboarding payments error:', error);
        res.status(500).json({ success: false, message: 'Error fetching payments' });
    }
};

export const updatePayment = async (req: AuthRequest, res: Response) => {
    try {
        const { id } = req.params;
        const { paidDate, amount, transactionReference, status, remarks } = req.body;
        
        const payment = await FinancePayment.findByPk(id);
        if (!payment) return res.status(404).json({ success: false, message: 'Payment not found' });

        const previousPaymentSnapshot = {
            paymentStatus: payment.paymentStatus,
            paymentType: payment.paymentType,
            amount: payment.amount,
            transactionId: payment.transactionId,
        };

        const isVerifying = status === 'Paid' && payment.paymentStatus !== 'Paid';

        await payment.update({
            paymentDate: paidDate || payment.paymentDate,
            amount: amount || payment.amount,
            transactionId: transactionReference || payment.transactionId,
            paymentStatus: status || payment.paymentStatus,
            remarks: remarks || payment.remarks,
            verifiedBy: isVerifying ? req.user?.id : payment.verifiedBy,
            verificationDate: isVerifying ? new Date() : payment.verificationDate,
            updatedAt: new Date()
        });

        // Re-fetch with verifier details for frontend
        const updatedPayment = await FinancePayment.findByPk(id, {
            include: [
                { model: Application, as: 'application', attributes: ['applicantName', 'applicationId'] },
                { model: User, as: 'verifier', attributes: ['fullName'] }
            ]
        });

        const p = updatedPayment || payment;
        await safeAuditLogCreate({
            userId: req.user?.id || null,
            action: AUDIT_ACTIONS.PAYMENT_UPDATED,
            entityType: 'application',
            entityId: payment.applicationId,
            oldData: { paymentId: payment.id, ...previousPaymentSnapshot },
            newData: {
                paymentId: payment.id,
                paymentType: p.paymentType,
                paymentStatus: p.paymentStatus,
                financeVerified: !!isVerifying,
                amount: p.amount,
                transactionId: p.transactionId,
                remarks: p.remarks,
            },
        });

        // SRS §11.1.3.1 — Notify DD-Admin and DD-Lead when payment is verified
        if (isVerifying && status === 'Paid') {
            const notifyRoles = [ROLES.DD_ADMIN, ROLES.DD_LEAD];

            
            for (const role of notifyRoles) {
                const roleUsers = await User.findAll({ where: { roleCode: role } });
                for (const u of roleUsers) {
                    NotificationService.notify(u.id, u.email, {
                        title: `Payment Verified: ${p.application?.applicationId || 'New Dealer'}`,
                        message: `Finance has verified the ${p.paymentType || 'Security Deposit'} for ${p.application?.applicantName || 'Dealer'}.`,
                        channels: ['system', 'email'],
                        templateCode: 'ONBOARDING_PAYMENT_VERIFIED',
                        placeholders: {
                            applicationId: p.application?.applicationId || 'N/A',
                            dealerName: p.application?.applicantName || 'Dealer',
                            paymentType: p.paymentType || 'Security Deposit',
                            amount: p.amount,
                            link: `${portalBase}/applications/${p.applicationId}`
                        }
                    }).catch((e: any) => console.error('[Finance] Payment verification notify failed:', e));
                }
            }
        }

        res.json({ success: true, message: 'Payment updated successfully', data: updatedPayment });
    } catch (error) {
        console.error('Update payment error:', error);
        res.status(500).json({ success: false, message: 'Error updating payment' });
    }
};

export const updateFnF = async (req: AuthRequest, res: Response) => {
    try {
        const { id } = req.params;
        const { finalSettlementAmount, status, settlementDate, paymentMode, transactionReference, remarks } = req.body;
        
        const fnf = await FnF.findByPk(id);
        if (!fnf) return res.status(404).json({ success: false, message: 'F&F settlement not found' });

        const normalizedStatus = normalizeFnFStatus(status || fnf.status);
        await fnf.update({
            status: normalizedStatus,
            netAmount: finalSettlementAmount || fnf.netAmount,
            settlementAmount: finalSettlementAmount || fnf.settlementAmount,
            settlementDate: settlementDate || fnf.settlementDate,
            paymentMode: paymentMode || fnf.paymentMode,
            transactionReference: transactionReference || fnf.transactionReference,
            remarks: remarks || fnf.remarks,
            updatedAt: new Date()
        });

        await AuditLog.create({
            userId: req.user?.id || null,
            action: AUDIT_ACTIONS.FNF_UPDATED,
            entityType: 'fnf',
            entityId: id,
            newData: { status: normalizedStatus, netAmount: finalSettlementAmount, remarks }
        });

        // If status is being set to Completed, transition parent request via workflow services
        if (normalizedStatus === FNF_STATUS.COMPLETED) {
            if (fnf.resignationId) {
                const resignation = await Resignation.findByPk(fnf.resignationId);
                if (resignation) {
                    await ResignationWorkflowService.transitionResignation(resignation, RESIGNATION_STAGES.COMPLETED, req.user?.id || null, {
                        action: 'F&F Settlement Completed',
                        remarks: remarks || 'F&F marked completed from settlement module.',
                        status: 'Completed'
                    });
                }
            } else if (fnf.terminationRequestId) {
                const termination = await TerminationRequest.findByPk(fnf.terminationRequestId);
                if (termination) {
                    await TerminationWorkflowService.transitionTermination(termination, TERMINATION_STAGES.TERMINATED, req.user?.id || null, {
                        action: 'F&F Settlement Completed',
                        remarks: remarks || 'F&F marked completed from settlement module.',
                        status: 'Terminated'
                    });
                }
            }

            // SRS §4.4.2.7 — F&F Completed: final alerts to DD-Lead, NBH, Legal
            const completionRoles = [ROLES.DD_LEAD, ROLES.NBH, ROLES.LEGAL_ADMIN, ROLES.DD_ADMIN];
            for (const role of completionRoles) {
                const roleUsers = await User.findAll({ where: { roleCode: role } });
                for (const u of roleUsers) {
                    NotificationService.notify(u.id, u.email, {
                        title: `F&F Settlement Completed: ${fnf.fnfId || id}`,
                        message: `Full & Final Settlement has been completed and closed. All departmental clearances confirmed.`,
                        channels: ['system', 'email'],
                        templateCode: 'FNF_SETTLEMENT_APPROVED',
                        placeholders: {
                            fnfId: fnf.fnfId || id,
                            dealerName: 'Dealer', // Can be refined if dealer info is fetched
                            settlementAmount: fnf.settlementAmount || fnf.netAmount,
                            link: `${portalBase}/fnf/${id}`
                        }
                    }).catch((e: any) => console.error('[FnF] Completion notify failed:', e));
                }
            }
        }

        // SRS §4.4.2.6 — Finance approval reached: notify DD-Admin + Legal
        if (normalizedStatus === FNF_STATUS.FINANCE_APPROVAL) {
            const financeApprovalRoles = [ROLES.DD_ADMIN, ROLES.LEGAL_ADMIN];
            for (const role of financeApprovalRoles) {
                const roleUsers = await User.findAll({ where: { roleCode: role } });
                for (const u of roleUsers) {
                    NotificationService.notify(u.id, u.email, {
                        title: `F&F Finance Approval Stage: ${fnf.fnfId || id}`,
                        message: `All departments have submitted their clearances. F&F is now pending Finance approval.`,
                        channels: ['system', 'email'],
                        templateCode: 'FNF_INITIATED',
                        placeholders: {
                            dealerName: '',
                            fnfId: fnf.fnfId || id,
                            link: `${portalBase}/fnf/${id}`,
                            ctaLabel: 'Review Settlement'
                        }
                    }).catch((e: any) => console.error('[FnF] Finance approval notify failed:', e));
                }
            }
        }
        
        res.json({ success: true, message: 'F&F settlement updated successfully', data: fnf });
    } catch (error) {
        console.error('Update F&F error:', error);
        res.status(500).json({ success: false, message: 'Error updating F&F settlement' });
    }
};

export const getFnFSettlements = async (req: Request, res: Response) => {
    try {
        const page = parseInt(req.query.page as string) || 1;
        const limit = parseInt(req.query.limit as string) || 10;
        const offset = (page - 1) * limit;

        const { count, rows: settlements } = await FnF.findAndCountAll({
            include: [
                { model: Resignation, as: 'resignation', attributes: ['id', 'resignationId'] },
                { model: TerminationRequest, as: 'terminationRequest', attributes: ['id', 'status', 'category'] },
                { model: db.Dealer, as: 'dealer', attributes: ['legalName', 'businessName', 'id'] },
                { model: Outlet, as: 'outlet', include: [{ model: User, as: 'dealer', attributes: ['fullName', 'id'] }] },
                { model: FnFLineItem, as: 'lineItems' },
                { model: FffClearance, as: 'clearances' }
            ],
            order: [['createdAt', 'DESC']],
            limit,
            offset,
            distinct: true
        });
        res.json({ 
            success: true, 
            settlements,
            meta: {
                total: count,
                totalPages: Math.ceil(count / limit),
                currentPage: page,
                limit
            }
        });
    } catch (error) {
        res.status(500).json({ success: false, message: 'Error fetching settlements' });
    }
};

export const getFnFById = async (req: Request, res: Response) => {
    try {
        const rawId = req.params.id;
        const id = Array.isArray(rawId) ? rawId[0] : rawId;

        // Resolve UUID if human-readable ID (FNF-*) is passed
        const { resolvedId } = await resolveEntityUuidByType(db as any, id, 'fnf');

        const includeConfig = [
            { model: Resignation, as: 'resignation', include: [{ model: db.Outlet, as: 'outlet' }] },
            { model: TerminationRequest, as: 'terminationRequest' },
            { 
                model: Outlet, 
                as: 'outlet', 
                include: [{ 
                    model: User, 
                    as: 'dealer',
                    include: [{ 
                        model: Dealer, 
                        as: 'dealerProfile',
                        include: [
                            { model: db.DealerCode, as: 'dealerCode' },
                            { model: db.DealerBankDetail, as: 'bankDetails' }
                        ]
                    }]
                }] 
            },
            {
                model: Dealer,
                as: 'dealer',
                include: [
                    { model: db.DealerCode, as: 'dealerCode' },
                    { model: db.DealerBankDetail, as: 'bankDetails' }
                ]
            },
            { model: FnFLineItem, as: 'lineItems' },
            { model: FffClearance, as: 'clearances', include: [{ model: User, as: 'clearanceOfficer', attributes: ['fullName'] }] },
            { 
                model: RequestParticipant, 
                as: 'participants',
                separate: true,
                include: [{ model: User, as: 'user', attributes: ['id', ['fullName', 'name'], 'email', ['roleCode', 'role']] }]
            }
        ];

        const fnf = await FnF.findByPk(resolvedId, {
            include: includeConfig as any
        });
        if (!fnf) return res.status(404).json({ success: false, message: 'F&F not found' });

        // Ensure participants exist (fixes legacy / missing participants silently)
        if (!fnf.participants || (fnf as any).participants.length === 0) {
            const { ParticipantService } = await import('../../services/ParticipantService.js');
            await ParticipantService.assignFnFParticipants(resolvedId);
        }

        await ensureFinanceDraftsFromDepartmentClaims(resolvedId, null);

        const fnfWithDrafts = await FnF.findByPk(resolvedId, {
            include: includeConfig as any
        });
        
        if (!fnfWithDrafts) return res.status(404).json({ success: false, message: 'F&F not found after sync' });
        res.json({ success: true, fnf: fnfWithDrafts });
    } catch (error) {
        console.error('Error fetching F&F:', error);
        res.status(500).json({ success: false, message: 'Error fetching F&F' });
    }
};

export const addLineItem = async (req: AuthRequest, res: Response) => {
    try {
        const { id } = req.params;
        const { itemType, description, department, amount } = req.body;
        const fnf = await FnF.findByPk(id);
        if (!fnf) return res.status(404).json({ success: false, message: 'F&F settlement not found' });

        if (fnf.status === FNF_STATUS.COMPLETED) {
            return res.status(400).json({ success: false, message: 'Cannot add line items after settlement completion' });
        }

        const lineItem = await FnFLineItem.create({
            fnfId: id,
            itemType,
            description: withPrefix(description, LINE_ITEM_DESCRIPTION_PREFIX.FINANCE_VALIDATED),
            department,
            amount: Math.abs(Number(amount) || 0),
            addedBy: req.user?.id,
            sourceType: 'FinanceValidated',
            version: 1,
            isActive: true,
            validatedAmount: Math.abs(Number(amount) || 0),
            financeDecision: 'Accepted',
            varianceAmount: 0
        });

        // Update FnF progress and department statuses
        await calculateFnFLogic(id as string, req.user?.id);

        await AuditLog.create({
            userId: req.user?.id || null,
            action: AUDIT_ACTIONS.FNF_UPDATED,
            entityType: 'fnf',
            entityId: id,
            newData: { action: 'ADD_LINE_ITEM', department, amount, description }
        });

        res.json({ success: true, lineItem });
    } catch (error) {
        res.status(500).json({ success: false, message: 'Error adding line item' });
    }
};

export const updateLineItem = async (req: AuthRequest, res: Response) => {
    try {
        const { itemId } = req.params;
        const { description, department, amount } = req.body;
        const lineItem = await FnFLineItem.findByPk(itemId);
        if (!lineItem) return res.status(404).json({ success: false, message: 'Line item not found' });

        const fnf = await FnF.findByPk(lineItem.fnfId);
        if (!fnf) return res.status(404).json({ success: false, message: 'F&F settlement not found' });

        if (fnf.status === FNF_STATUS.COMPLETED) {
            return res.status(400).json({ success: false, message: 'Cannot update line items after settlement completion' });
        }

        if (isDepartmentClaimLineItem(lineItem)) {
            return res.status(400).json({
                success: false,
                message: 'Department claim lines are immutable in Finance edit flow. Use department clearance update.'
            });
        }

        const nextAmount = Math.abs(Number(amount) || 0);
        const nextDescription = withPrefix(description || lineItem.description, LINE_ITEM_DESCRIPTION_PREFIX.FINANCE_VALIDATED);
        const nextDepartment = department || lineItem.department;
        const prevValidated = Math.abs(Number((lineItem as any).validatedAmount ?? lineItem.amount) || 0);
        const claimAmount = Math.abs(Number((lineItem as any).claimAmount) || 0) || null;
        const varianceAmount = claimAmount !== null ? claimAmount - nextAmount : 0;
        const financeDecision = varianceAmount === 0 ? 'Accepted' : 'Partially Accepted';
        const varianceReason = varianceAmount === 0 ? null : 'Adjusted during finance reconciliation';

        await lineItem.update({ isActive: false });

        const updatedLineItem = await FnFLineItem.create({
            fnfId: lineItem.fnfId,
            itemType: lineItem.itemType,
            description: nextDescription,
            department: nextDepartment,
            amount: nextAmount,
            addedBy: req.user?.id || lineItem.addedBy,
            sourceType: 'FinanceValidated',
            version: Number((lineItem as any).version || 1) + 1,
            isActive: true,
            parentLineItemId: (lineItem as any).parentLineItemId || lineItem.id,
            claimAmount,
            validatedAmount: nextAmount,
            varianceAmount,
            financeDecision,
            varianceReason
        });

        await AuditLog.create({
            userId: req.user?.id || null,
            action: AUDIT_ACTIONS.FNF_UPDATED,
            entityType: 'fnf',
            entityId: lineItem.fnfId,
            newData: {
                action: 'FINANCE_VALIDATION_VERSION_CREATED',
                previousLineItemId: lineItem.id,
                newLineItemId: updatedLineItem.id,
                previousValidatedAmount: prevValidated,
                validatedAmount: nextAmount,
                claimAmount,
                varianceAmount,
                financeDecision,
                varianceReason
            }
        });

        // Update FnF progress and department statuses
        // Update FnF progress and department statuses
        await calculateFnFLogic(lineItem.fnfId, req.user?.id);

        return res.json({ success: true, lineItem: updatedLineItem });
    } catch (error) {
        res.status(500).json({ success: false, message: 'Error updating line item' });
    }
};

export const deleteLineItem = async (req: AuthRequest, res: Response) => {
    try {
        const { itemId } = req.params;
        const lineItem = await FnFLineItem.findByPk(itemId);
        if (!lineItem) return res.status(404).json({ success: false, message: 'Line item not found' });

        if (isDepartmentClaimLineItem(lineItem)) {
            return res.status(400).json({
                success: false,
                message: 'Department claim lines cannot be deleted from Finance edit flow.'
            });
        }
        
        const fnfId = lineItem.fnfId;
        await lineItem.update({ isActive: false });

        // Update FnF progress and department statuses
        // Update FnF progress and department statuses
        await calculateFnFLogic(fnfId, req.user?.id);

        await AuditLog.create({
            userId: req.user?.id || null,
            action: AUDIT_ACTIONS.FNF_UPDATED,
            entityType: 'fnf',
            entityId: fnfId,
            newData: { action: 'DELETE_LINE_ITEM', department: lineItem.department, amount: lineItem.amount, softDeleted: true }
        });

        res.json({ success: true, message: 'Line item deleted' });
    } catch (error) {
        res.status(500).json({ success: false, message: 'Error deleting line item' });
    }
};

// Helper to calculate and update FnF progress
const calculateFnFLogic = async (id: string, userId: string | null = null) => {
    const fnf = await FnF.findByPk(id, {
        include: [{ model: FnFLineItem, as: 'lineItems' }, { model: FffClearance, as: 'clearances' }]
    });
    if (!fnf) return null;

    await ensureFinanceDraftsFromDepartmentClaims(id, userId);

    const refreshedFnf = await FnF.findByPk(id, {
        include: [{ model: FnFLineItem, as: 'lineItems' }, { model: FffClearance, as: 'clearances' }]
    });
    if (!refreshedFnf) return null;

    const lineItems = getActiveLineItems((refreshedFnf as any).lineItems || []);
    const clearances = (refreshedFnf as any).clearances || [];
    
    let totalReceivables = 0;
    let totalPayables = 0;
    let totalDeductions = 0;

    const hasFinanceValidatedLines = lineItems.some((item: any) => isFinanceValidatedLineItem(item));
    const calculationLineItems = hasFinanceValidatedLines
        ? lineItems.filter((item: any) => isFinanceValidatedLineItem(item))
        : lineItems;

    calculationLineItems.forEach((item: any) => {
        const amt = Math.abs(parseFloat(item.amount) || 0);
        if (item.itemType === 'Receivable' || item.itemType === 'Recovery') totalReceivables += amt;
        else if (item.itemType === 'Payable') totalPayables += amt;
        else if (item.itemType === 'Deduction') totalDeductions += amt;
    });

    const netAmount = totalPayables - totalReceivables - totalDeductions;
    const allCleared = clearances.length > 0 && clearances.every((c: any) => 
        ['Cleared', 'NOC Submitted', 'Dues Pending', 'N/A'].includes(c.status)
    );

    // Calculate progress percentage based on clearances
    let progressPercentage = 0;
    if (clearances.length > 0) {
        const clearedCount = clearances.filter((c: any) => 
            ['Cleared', 'NOC Submitted', 'Dues Pending', 'N/A'].includes(c.status)
        ).length;
        progressPercentage = Math.round((clearedCount / clearances.length) * 100);
    }

    // Sync individual department clearance statuses based on dues
    for (const clearance of clearances) {
        // Only update if it's already been processed (not Pending)
        if (clearance.status === 'Pending') continue;

        const deptDues = calculationLineItems.filter((li: any) => li.department === clearance.department);
        const totalDeptAmount = deptDues.reduce((sum: number, li: any) => sum + (parseFloat(li.amount) || 0), 0);

        const targetStatus = totalDeptAmount > 0 ? 'Dues Pending' : 'NOC Submitted';
        if (clearance.status !== targetStatus) {
            await clearance.update({ status: targetStatus });
        }
    }

    // Determine Overall F&F Status
    let newStatus = normalizeFnFStatus(refreshedFnf.status);
    if (refreshedFnf.status === FNF_STATUS.INITIATED && progressPercentage > 0) {
        newStatus = FNF_STATUS.DD_CLEARANCE;
    }
    if (allCleared && refreshedFnf.status !== FNF_STATUS.COMPLETED) {
        newStatus = FNF_STATUS.FINANCE_APPROVAL;
    }

    await refreshedFnf.update({
        totalReceivables, totalPayables, totalDeductions, netAmount,
        status: newStatus,
        progressPercentage
    });

    // If status moved to Completed, also update parent resignation/termination
    if (newStatus === FNF_STATUS.COMPLETED || newStatus === 'Completed') {
        if (refreshedFnf.resignationId) {
            const resignation = await Resignation.findByPk(refreshedFnf.resignationId);
            if (resignation) {
                await ResignationWorkflowService.transitionResignation(resignation, RESIGNATION_STAGES.COMPLETED, userId, {
                    action: 'F&F Settlement Completed',
                    remarks: 'Full & Final settlement process finalized. Transitioning resignation to Completed.',
                    status: 'Completed'
                });
            }
        } else if (refreshedFnf.terminationRequestId) {
            const terminationRequest = await TerminationRequest.findByPk(refreshedFnf.terminationRequestId);
            if (terminationRequest) {
                await TerminationWorkflowService.transitionTermination(terminationRequest, TERMINATION_STAGES.TERMINATED, userId, {
                    action: 'F&F Settlement Completed',
                    remarks: 'Full & Final settlement process finalized. Transitioning termination to Terminated.',
                    status: 'Terminated'
                });
            }
        }
    }

    return refreshedFnf;
};

export const updateClearance = async (req: AuthRequest, res: Response) => {
    try {
        const rawId = req.params.id;
        const id = Array.isArray(rawId) ? rawId[0] : rawId;
        const { clearanceId } = req.params;
        const body = (req.body || {}) as Record<string, any>;
        const { status, remarks, documentId, supportingDocument, amount, type } = body;
        const clearance = await FffClearance.findOne({ where: { id: clearanceId, fnfId: id } });
        if (!clearance) return res.status(404).json({ success: false, message: 'Clearance record not found' });
        const fnf = await FnF.findByPk(id);
        if (!fnf) return res.status(404).json({ success: false, message: 'F&F settlement not found' });

        if ([FNF_STATUS.FINANCE_APPROVAL, FNF_STATUS.COMPLETED].includes(fnf.status) && ![ROLES.FINANCE, ROLES.SUPER_ADMIN].includes(req.user?.role as any)) {
            return res.status(400).json({
                success: false,
                message: 'Department response window is closed for this case.'
            });
        }

        const uploadedSupportingDocument = req.file ? `/uploads/documents/${req.file.filename}` : undefined;
        const enteredAmount = Math.abs(Number(amount) || 0);
        const clearanceType = String(type || '').toLowerCase();
        const itemType = clearanceType === 'payable'
            ? 'Payable'
            : clearanceType === 'deduction'
                ? 'Deduction'
                : 'Receivable';
        const syntheticDescription = DEPARTMENT_CLAIM_DESCRIPTION;

        // Persist amount/type as immutable department-claim line item.
        const existingSyntheticLine = await FnFLineItem.findOne({
            where: {
                fnfId: id,
                department: clearance.department,
                description: syntheticDescription,
                isActive: true
            }
        });

        if (enteredAmount > 0) {
            if (existingSyntheticLine) {
                await existingSyntheticLine.update({ isActive: false });

                await FnFLineItem.create({
                    fnfId: id,
                    itemType,
                    description: syntheticDescription,
                    department: clearance.department,
                    amount: enteredAmount,
                    addedBy: req.user?.id || null,
                    sourceType: 'DepartmentClaim',
                    version: Number((existingSyntheticLine as any).version || 1) + 1,
                    isActive: true,
                    parentLineItemId: (existingSyntheticLine as any).parentLineItemId || existingSyntheticLine.id,
                    claimAmount: enteredAmount,
                    validatedAmount: null,
                    varianceAmount: 0,
                    financeDecision: null,
                    varianceReason: null
                });
            } else {
                await FnFLineItem.create({
                    fnfId: id,
                    itemType,
                    description: syntheticDescription,
                    department: clearance.department,
                    amount: enteredAmount,
                    addedBy: req.user?.id || null,
                    sourceType: 'DepartmentClaim',
                    version: 1,
                    isActive: true,
                    claimAmount: enteredAmount,
                    validatedAmount: null,
                    varianceAmount: 0,
                    financeDecision: null,
                    varianceReason: null
                });
            }
        } else if (existingSyntheticLine) {
            await existingSyntheticLine.update({ isActive: false });
        }

        const normalizedStatus = normalizeClearanceStatus(status || clearance.status, enteredAmount);
        await clearance.update({
            status: normalizedStatus, 
            remarks: remarks || clearance.remarks, 
            documentId: documentId || clearance.documentId,
            supportingDocument: uploadedSupportingDocument || supportingDocument || clearance.supportingDocument,
            clearedBy: req.user?.id,
            clearedAt: normalizedStatus !== 'Pending' ? new Date() : clearance.clearedAt
        });

        const { syncFnfClearanceSla } = await import('../../common/utils/slaFnfSync.js');
        await syncFnfClearanceSla(String(id), clearance.department, normalizedStatus);

        // Automatically update FnF progress
        console.log(`[SettlementController] Updating clearance for F&F: ${id}`);
        const fnfRecord = await calculateFnFLogic(id as string, req.user?.id);

        // 1. Local F&F Audit (Dedicated Table: fnf_audit_logs)
        try {
            console.log(`[SettlementController] Creating FnFAudit for ${id}`);
            await db.FnFAudit.create({
                userId: req.user?.id || null,
                fnfId: id,
                action: 'CLEARANCE_UPDATED',
                remarks: remarks || 'No remarks',
                details: {
                    department: clearance.department,
                    status: normalizedStatus,
                    amount: enteredAmount,
                    type: itemType
                }
            });
        } catch (auditError) {
            console.error('[SettlementController] Local FnFAudit creation failed:', auditError);
        }

        // 2. Interconnected Mirror (Dedicated Table: resignation_audit_logs or termination_audit_logs)
        if (fnfRecord && (fnfRecord.resignationId || fnfRecord.terminationRequestId)) {
            try {
                const isResignation = !!fnfRecord.resignationId;
                const parentAuditModel = isResignation ? db.ResignationAudit : db.TerminationAudit;
                const parentKey = isResignation ? 'resignationId' : 'terminationRequestId';
                const parentId = fnfRecord.resignationId || fnfRecord.terminationRequestId;

                console.log(`[SettlementController] Creating Parent Audit for ${parentId} (${isResignation ? 'resignation' : 'termination'})`);
                await parentAuditModel.create({
                    userId: req.user?.id || null,
                    [parentKey]: parentId,
                    action: 'STAKEHOLDER_CLEARANCE_UPDATED',
                    remarks: `Automated sync from F&F: ${remarks || 'No remarks'}`,
                    details: {
                        department: clearance.department,
                        status: normalizedStatus,
                        amount: enteredAmount,
                        type: itemType
                    }
                });
            } catch (parentAuditError) {
                console.error('[SettlementController] Parent Audit creation failed:', parentAuditError);
            }
        }

        // 3. F&F Dashboard Chat Trail (Worknotes for the unified stakeholder view)
        try {
            await writeWorkflowActivityWorknote({
                requestId: id,
                requestType: 'fnf',
                userId: req.user?.id || '',
                noteText: `[Auto] Clearance updated for ${clearance.department}: Status: ${normalizedStatus}, Amount: ${enteredAmount} (${itemType})`,
                noteType: 'workflow'
            });
        } catch (worknoteError) {
            console.error('[SettlementController] Worknote recording failed:', worknoteError);
        }

        res.json({ success: true, message: 'Clearance updated successfully', clearance });
    } catch (error) {
        console.error('Update clearance error:', error);
        res.status(500).json({ success: false, message: 'Error updating clearance' });
    }
};

export const calculateFnF = async (req: AuthRequest, res: Response) => {
    try {
        const { id } = req.params;
        const fnf = await calculateFnFLogic(id as string, req.user?.id);
        if (!fnf) return res.status(404).json({ success: false, message: 'F&F not found' });

        res.json({ success: true, fnf });
    } catch (error) {
        console.error('Calculate F&F error:', error);
        res.status(500).json({ success: false, message: 'Error calculating F&F' });
    }
};
