import db from '../database/models/index.js';
import { Op } from 'sequelize';
const { User, TerminationScnResponse, TerminationHearingRecord, Dealer, FnF, FffClearance } = db;
import { TERMINATION_STAGES, ROLES, FNF_DEPARTMENTS, REQUEST_TYPES } from '../common/config/constants.js';
import { getTerminationStatusForStage } from '../common/utils/offboardingStatus.js';
import { NotificationService } from './NotificationService.js';
import ExternalMocksService from '../common/utils/externalMocks.service.js';
import logger from '../common/utils/logger.js';
import { NomenclatureService } from '../common/utils/nomenclature.js';
import { writeWorkflowActivityWorknote } from '../common/utils/workflowWorknote.js';
import { getOffboardingAuditAction, formatOffboardingAction } from '../common/utils/offboardingWorkflow.utils.js';
import { ParticipantService } from './ParticipantService.js';
import { syncSlaOnStageTransition } from '../common/utils/slaWorkflowSync.js';
import { getFrontendBaseUrl } from '../common/utils/frontendUrl.js';

export class TerminationWorkflowService {
    /**
     * Standardized method to transition a termination request status
     */
    static async transitionTermination(termination: any, targetStage: string, userId: string | null = null, metadata: any = {}) {
        const { action, remarks, status, transaction } = metadata;
        const sourceStage = termination.currentStage;
        const wasOnHold = String(termination.status || '').toLowerCase() === 'on hold';

        const updateData: any = {
            currentStage: targetStage,
            status: status || getTerminationStatusForStage(targetStage),
            progressPercentage: this.calculateProgress(targetStage),
            updatedAt: new Date()
        };

        // 1. Resolve Actor
        const actor = userId ? await User.findByPk(userId) : null;

        // 2. Prepare Timeline Entry
        const timelineEntry = {
            stage: sourceStage, // Correctly Associate remark with the stage where action happened
            targetStage: targetStage,
            timestamp: new Date(),
            user: actor ? actor.fullName : 'System',
            role: actor ? actor.roleCode : null,
            action: action || `Approved to ${targetStage}`,
            remarks: remarks || ''
        };

        const updatedTimeline = [...(termination.timeline || []), timelineEntry];

        // 3. Perform Consolidated Update
        await termination.update({
            ...updateData,
            timeline: updatedTimeline
        }, transaction ? { transaction } : undefined);

        await syncSlaOnStageTransition({
            entityType: 'termination',
            entityId: termination.id,
            fromStage: sourceStage,
            toStage: targetStage
        });

        if (wasOnHold) {
            const { SLAService } = await import('./SLAService.js');
            await SLAService.resumeEntityTracks('termination', termination.id);
        }

        // 4. Create Audit Log using standardized mapper
        const { actionType } = metadata;
        const auditAction = getOffboardingAuditAction(actionType || action || 'Approved', REQUEST_TYPES.TERMINATION);

        await db.TerminationAudit.create({
            userId: userId,
            terminationRequestId: termination.id,
            action: formatOffboardingAction(auditAction),
            remarks: remarks || '',
            details: { status: updateData.status, stage: sourceStage, targetStage: formatOffboardingAction(targetStage) }
        }, transaction ? { transaction } : undefined);

        // 5. Create Worknote for standardized communication trail
        if (remarks && userId) {
            try {
                // Prepend action to remarks for better context in Work Notes
                const actionPrefix = action ? `${formatOffboardingAction(action)}: ` : '';
                await writeWorkflowActivityWorknote({
                    requestId: termination.id,
                    requestType: 'termination',
                    userId: userId,
                    noteText: `${actionPrefix}${remarks}`,
                    noteType: (action && action.toLowerCase().includes('send back')) ? 'workflow' : 'internal'
                });
            } catch (wnErr) {
                logger.error('[TerminationWorkflowService] failed to write worknote:', wnErr);
            }
        }

        // 4. Send Notifications
        const user = await User.findOne({ 
            where: { 
                [Op.or]: [
                    { id: termination.dealerId },
                    { dealerId: termination.dealerId }
                ]
            },
            attributes: ['id', 'email', 'fullName', 'mobileNumber']
        });

        if (user) {
            const portalBase = getFrontendBaseUrl();
            const dealerPortalLink = `${portalBase}/termination/${termination.id}`;
            const isScnIssued = targetStage === TERMINATION_STAGES.SCN_ISSUED;

            const deadlineRaw = metadata.scnDeadline ?? metadata.deadline ?? termination.proposedLwd;
            let deadlineStr = '';
            try {
                if (deadlineRaw instanceof Date) {
                    deadlineStr = deadlineRaw.toLocaleDateString('en-IN', { dateStyle: 'medium' });
                } else if (deadlineRaw) {
                    deadlineStr = String(deadlineRaw);
                } else {
                    deadlineStr = new Date(Date.now() + 7 * 86400000).toLocaleDateString('en-IN', {
                        dateStyle: 'medium'
                    });
                }
            } catch {
                deadlineStr = String(deadlineRaw || '');
            }

            if (isScnIssued) {
                await NotificationService.notify(user.id, user.email, {
                    title: `URGENT: Show Cause Notice issued — ${termination.requestId}`,
                    message: `A Show Cause Notice has been issued for your termination request.`,
                    channels: ['email', 'whatsapp', 'system'],
                    templateCode: 'TERMINATION_SCN_ISSUED',
                    placeholders: {
                        dealerName: user.fullName || 'Dealer',
                        terminationId: termination.requestId,
                        deadline: deadlineStr,
                        link: dealerPortalLink,
                        remarks: remarks || '',
                        ctaLabel: 'Submit response',
                        phone: user?.mobileNumber || user?.phone || ''
                    }
                });
            }

            const { notifyStakeholdersOnTransition } = await import('../common/utils/workflow-email-notifications.js');

            await notifyStakeholdersOnTransition(
                termination.id,
                REQUEST_TYPES.TERMINATION,
                targetStage,
                {
                    code: termination.requestId,
                    dealerName: user.fullName || 'Dealer',
                    dealerId: user.id,
                    actionUserFullName: actor ? actor.fullName : 'System',
                    action: action || `Approved to ${targetStage}`,
                    remarks: remarks || 'N/A',
                    link: dealerPortalLink
                }
            );

            // 5. Deactivate User Account on final completion stages (SRS 1.1.5 / 2.3.5)
            // We deactivate at Legal Letter stage to ensure access is revoked as soon as the formal letter is issued
            if (targetStage === TERMINATION_STAGES.TERMINATED || targetStage === TERMINATION_STAGES.LEGAL_LETTER) {
                logger.info(`[TerminationWorkflowService] Revoking portal access for user ${user.email} (Stage: ${targetStage})`);
                await user.update({
                    status: 'inactive',
                    isActive: false
                });
            }
        } else {
            logger.warn(`[TerminationWorkflowService] No user account found with dealerId ${termination.dealerId}`);
        }
        
        return termination;
    }

    /**
     * Creates the FnF settlement record — ONLY call from explicit Push to F&F (`manualTrigger: true`).
     */
    static async initiateFnF(
        termination: any,
        userId: string,
        transaction: any,
        options: { manualTrigger?: boolean } = {}
    ) {
        if (!options.manualTrigger) {
            throw new Error(
                'F&F settlement for termination must be started via Push to F&F (manual trigger only).'
            );
        }
        // 1. Get Dealer User with associated Outlets
        const dealerUser = await User.findOne({
            where: { dealerId: termination.dealerId, roleCode: ROLES.DEALER },
            include: [{ model: db.Outlet, as: 'outlets' }]
        });

        const primaryOutlet = dealerUser?.outlets?.find((o: any) => o.isPrimary) || dealerUser?.outlets?.[0];

        const dealerProfile = await Dealer.findByPk(termination.dealerId);
        if (!dealerProfile) throw new Error('Dealer record not found for termination');

        // 2. Resolve or Create FnF Settlement
        let fnf = await db.FnF.findOne({ where: { terminationRequestId: termination.id } });
        let fnfId = fnf?.id;

        if (!fnf) {
            fnf = await db.FnF.create(
                {
                    settlementId: await NomenclatureService.generateFnFId(),
                    terminationRequestId: termination.id,
                    dealerId: termination.dealerId,
                    outletId: primaryOutlet?.id || null,
                    status: 'Initiated',
                    totalReceivables: 0,
                    totalPayables: 0,
                    netAmount: 0
                },
                transaction ? { transaction } : undefined
            );

            await db.FffClearance.bulkCreate(
                FNF_DEPARTMENTS.map(dept => ({
                    fnfId: fnf.id,
                    department: dept,
                    status: 'Pending'
                })),
                transaction ? { transaction } : undefined
            );

            const { startAllPendingFnfClearanceSlas } = await import('../common/utils/slaFnfSync.js');
            await startAllPendingFnfClearanceSlas(fnf.id);

            await db.FnFAudit.create(
                {
                    userId,
                    fnfId: fnf.id,
                    action: 'INITIATED',
                    remarks: 'F&F settlement created via manual Push to F&F (termination)',
                    details: {
                        source: 'Termination Workflow',
                        terminationRequestId: termination.requestId,
                        manualTrigger: true
                    }
                },
                transaction ? { transaction } : undefined
            );

            fnfId = fnf.id;
        }

        // 3. External SAP Sync
        ExternalMocksService.mockSyncDealerStatusToSap(dealerProfile.dealerCode, 'Inactive')
            .catch(err => console.error('Error syncing termination deactivation to SAP:', err));

        // 4. Assign Participants for F&F (Sub-application chat)
        if (fnfId) {
            await ParticipantService.assignFnFParticipants(fnfId);

            // SRS §1.1.1: Notify DD Admin and Finance via Email & WhatsApp
            try {
                const adminUsers = await User.findAll({
                    where: { roleCode: [ROLES.DD_ADMIN, ROLES.FINANCE] },
                    attributes: ['id', 'email', 'fullName', 'mobileNumber']
                });

                const portalBase = getFrontendBaseUrl();
                for (const u of adminUsers) {
                    const phone = u.mobileNumber || null;
                    await NotificationService.notify(u.id, u.email, {
                        title: `F&F Settlement Initiated: ${termination.requestId}`,
                        message: `Full & Final Settlement has been initiated for ${dealerUser?.fullName || 'Dealer'}.`,
                        channels: phone ? ['system', 'email', 'whatsapp'] : ['system', 'email'],
                        templateCode: 'FNF_INITIATED',
                        placeholders: {
                            dealerName: dealerUser?.fullName || 'Dealer',
                            requestId: termination.requestId,
                            link: `${portalBase}/fnf/${fnf.id}`,
                            phone: phone || ''
                        }
                    });
                }
            } catch (notifyErr) {
                console.error('[TerminationWorkflowService] F&F initiation notification failed:', notifyErr);
            }
        }

        return fnf;
    }

    /**
     * Maps termination stages to progress percentage
     */
    static calculateProgress(stage: string): number {
        const progress: Record<string, number> = {
            [TERMINATION_STAGES.SUBMITTED]: 10,
            [TERMINATION_STAGES.RBM_REVIEW]: 20,
            [TERMINATION_STAGES.ZBH_REVIEW]: 30,
            [TERMINATION_STAGES.DD_LEAD_REVIEW]: 40,
            [TERMINATION_STAGES.LEGAL_VERIFICATION]: 45,
            [TERMINATION_STAGES.DD_HEAD_REVIEW]: 50,
            [TERMINATION_STAGES.NBH_EVALUATION]: 60,
            [TERMINATION_STAGES.SCN_ISSUED]: 70,
            [TERMINATION_STAGES.PERSONAL_HEARING]: 75,
            [TERMINATION_STAGES.NBH_FINAL_APPROVAL]: 80,
            [TERMINATION_STAGES.CCO_APPROVAL]: 85,
            [TERMINATION_STAGES.CEO_APPROVAL]: 90,
            [TERMINATION_STAGES.LEGAL_LETTER]: 95,
            [TERMINATION_STAGES.TERMINATED]: 100,
            [TERMINATION_STAGES.REJECTED]: 100
        };
        return progress[stage] || 0;
    }

    /**
     * Records a dealer's response to SCN and moves to personal hearing stage
     */
    static async handleScnResponse(termination: any, data: any, userId: string) {
        const { responseBody, documents } = data;
        
        await TerminationScnResponse.create({
            terminationRequestId: termination.id,
            submittedBy: userId,
            responseBody,
            documents: documents || []
        });

        return this.transitionTermination(termination, TERMINATION_STAGES.PERSONAL_HEARING, userId, {
            action: 'SCN_SUBMITTED',
            status: 'SCN Response Evaluation Pending',
            remarks: 'Dealer response submitted'
        });
    }

    /**
     * Records a personal hearing outcome and moves to next stage or rejection
     */
    static async handleHearingOutcome(termination: any, data: any, userId: string) {
        const { attendees, summary, recommendation, momDocumentId } = data;
        
        await TerminationHearingRecord.create({
            terminationRequestId: termination.id,
            conductedBy: userId,
            attendees,
            summary,
            recommendation,
            momDocumentId
        });

        const nextStage = recommendation === 'Reject' ? TERMINATION_STAGES.REJECTED : TERMINATION_STAGES.NBH_FINAL_APPROVAL;
        const status = recommendation === 'Reject' ? 'Rejected after Evaluation' : 'NBH Final Approval Pending';

        return this.transitionTermination(termination, nextStage, userId, {
            action: `Hearing Recorded - ${recommendation}`,
            status,
            remarks: summary
        });
    }
    /**
     * Checks if a user is authorized to perform an action based on their role and current stage
     */
    static async canUserAction(termination: any, user: any) {
        if (!user) return false;
        if (user.roleCode === ROLES.SUPER_ADMIN) return true;

        const stageToRole: Record<string, string | string[]> = {
            [TERMINATION_STAGES.SUBMITTED]: ROLES.ASM,
            [TERMINATION_STAGES.RBM_REVIEW]: [ROLES.RBM, ROLES.DD_ZM],
            [TERMINATION_STAGES.ZBH_REVIEW]: ROLES.ZBH,
            [TERMINATION_STAGES.DD_LEAD_REVIEW]: ROLES.DD_LEAD,
            [TERMINATION_STAGES.LEGAL_VERIFICATION]: ROLES.LEGAL_ADMIN,
            [TERMINATION_STAGES.DD_HEAD_REVIEW]: ROLES.DD_HEAD,
            [TERMINATION_STAGES.NBH_EVALUATION]: ROLES.NBH,
            [TERMINATION_STAGES.SCN_ISSUED]: [ROLES.LEGAL_ADMIN, ROLES.DD_ADMIN],
            [TERMINATION_STAGES.PERSONAL_HEARING]: [ROLES.NBH, ROLES.DD_LEAD, ROLES.RBM, ROLES.ZBH, ROLES.DD_HEAD],
            [TERMINATION_STAGES.NBH_FINAL_APPROVAL]: ROLES.NBH,
            [TERMINATION_STAGES.CCO_APPROVAL]: ROLES.CCO,
            [TERMINATION_STAGES.CEO_APPROVAL]: ROLES.CEO,
            [TERMINATION_STAGES.LEGAL_LETTER]: ROLES.LEGAL_ADMIN
        };

        const stageAliases: Record<string, string> = {
            'Personal Hearing': TERMINATION_STAGES.PERSONAL_HEARING,
            'Show Cause Notice': TERMINATION_STAGES.SCN_ISSUED
        };

        const normalizedStage = stageAliases[termination.currentStage] || termination.currentStage;
        const requiredRole = stageToRole[normalizedStage];
        if (Array.isArray(requiredRole)) {
            return requiredRole.includes(user.roleCode);
        }
        return user.roleCode === requiredRole;
    }
}
