import db from '../../database/models/index.js';
import { Op } from 'sequelize';
import { sendEmail } from './email.service.js';
import { NotificationService } from '../../services/NotificationService.js';
import {
    APPLICATION_STAGES,
    TERMINATION_STAGES,
    CONSTITUTIONAL_STAGES,
    RELOCATION_STAGES,
    REQUEST_TYPES,
    ROLES 
} from '../config/constants.js';
import { getFrontendBaseUrl } from './frontendUrl.js';

const { RequestParticipant, User, Outlet, District, Dealer } = db;

/** Dealer acknowledgement + internal reviewers after resignation is created. */
export async function notifyResignationSubmittedEmails(resignation: any): Promise<void> {
    const dealerUser = await User.findByPk(resignation.dealerId, {
        attributes: ['id', 'email', 'fullName', 'mobileNumber']
    });
    if (!dealerUser?.email) return;

    const base = getFrontendBaseUrl();
    const resignationCode = resignation.resignationId || resignation.id;
    const lwd =
        resignation.lastOperationalDateSales ||
        resignation.lastOperationalDateServices ||
        'As per application';
    const dealerName = dealerUser.fullName || 'Dealer';
    const dealerPhone = (dealerUser as any).mobileNumber || (dealerUser as any).phone || null;

    // SRS §1.1.1 — submission acknowledgement via email + WhatsApp
    await sendEmail(
        dealerUser.email,
        `We received your resignation request — ${resignationCode}`,
        'RESIGNATION_RECEIVED',
        {
            dealerName,
            resignationId: resignationCode,
            lwd: String(lwd),
            link: `${base}/dealer-resignation/${resignation.id}`,
            ctaLabel: 'View request'
        }
    ).catch((err) => console.error('[notifyResignationSubmittedEmails] dealer ack:', err));

    // WhatsApp acknowledgement to dealer
    if (dealerPhone) {
        await NotificationService.notify(dealerUser.id, dealerUser.email, {
            title: `Resignation request received — ${resignationCode}`,
            message: `Hi ${dealerName}, your resignation request has been received.`,
            channels: ['whatsapp'],
            templateCode: 'RESIGNATION_RECEIVED',
            placeholders: { dealerName, resignationId: resignationCode, lwd: String(lwd), link: `${base}/dealer-resignation/${resignation.id}`, phone: dealerPhone }
        }).catch((err) => console.error('[notifyResignationSubmittedEmails] dealer whatsapp:', err));
    }

    const participants = await RequestParticipant.findAll({
        where: {
            requestId: resignation.id,
            requestType: REQUEST_TYPES.RESIGNATION,
            userId: { [Op.ne]: resignation.dealerId }
        },
        include: [{ model: User, as: 'user', attributes: ['id', 'email', 'fullName', 'mobileNumber'] }]
    });

    const internalLink = `${base}/resignation/${resignation.id}`;
    for (const p of participants) {
        const u = (p as any).user;
        if (!u?.email) continue;
        const uPhone = u.mobileNumber || u.phone || null;
        await NotificationService.notify(u.id, u.email, {
            title: `New resignation request: ${resignationCode}`,
            message: `Submitted by ${dealerName}.`,
            channels: uPhone ? ['email', 'system', 'whatsapp'] : ['email', 'system'],
            templateCode: 'RESIGNATION_SUBMITTED',
            placeholders: {
                dealerName,
                resignationId: resignationCode,
                lwd: String(lwd),
                link: internalLink,
                ctaLabel: 'Review resignation',
                phone: uPhone || ''
            }
        }).catch((err) => console.error('[notifyResignationSubmittedEmails] internal:', err));
    }
}

/** Internal reviewers + dealer WhatsApp after constitutional request is created.
 *  SRS §1.1.1 — WhatsApp is a supported submission notification channel. */
export async function notifyConstitutionalSubmittedEmails(request: any, dealerDisplayName: string): Promise<void> {
    const participants = await RequestParticipant.findAll({
        where: {
            requestId: request.id,
            requestType: REQUEST_TYPES.CONSTITUTIONAL,
            userId: { [Op.ne]: request.dealerId }
        },
        include: [{ model: User, as: 'user', attributes: ['id', 'email', 'fullName', 'mobileNumber'] }]
    });

    const base = getFrontendBaseUrl();
    const link = `${base}/constitutional-change/${request.id}`;

    for (const p of participants) {
        const u = (p as any).user;
        if (!u?.email) continue;
        const uPhone = u.mobileNumber || u.phone || null;
        await NotificationService.notify(u.id, u.email, {
            title: `New constitutional change request: ${request.requestId}`,
            message: `${dealerDisplayName} submitted a request.`,
            channels: uPhone ? ['email', 'system', 'whatsapp'] : ['email', 'system'],
            templateCode: 'CONSTITUTIONAL_CHANGE_SUBMITTED',
            placeholders: {
                dealerName: dealerDisplayName,
                changeType: request.changeType || '',
                requestId: request.requestId,
                link,
                ctaLabel: 'Review request',
                phone: uPhone || ''
            }
        }).catch((err) => console.error('[notifyConstitutionalSubmittedEmails]:', err));
    }
}

/** Dealer + ASM when relocation request is submitted. */
export async function notifyRelocationSubmittedEmails(
    request: any,
    submitter: { email: string; fullName?: string | null }
): Promise<void> {
    const base = getFrontendBaseUrl();
    const code = request.requestId || request.id;
    const dealerName = submitter.fullName?.trim() || 'Dealer';

    if (submitter.email) {
        await sendEmail(
            submitter.email,
            `Relocation request received — ${code}`,
            'RELOCATION_RECEIVED',
            {
                dealerName,
                requestId: code,
                link: `${base}/relocation-requests/${request.id}`,
                ctaLabel: 'View request',
                distance: request.distance || '0'
            }
        ).catch((err) => console.error('[notifyRelocationSubmittedEmails] dealer:', err));
    }

    const outlet = await Outlet.findByPk(request.outletId, {
        include: [{ model: District, as: 'district', attributes: ['id', 'asmId'] }]
    });
    const dealerAccount = await User.findByPk(request.dealerId, {
        attributes: ['id'],
        include: [{ model: Dealer, as: 'dealerProfile', attributes: ['asmId'] }]
    });
    const outletLevelAsmId = (dealerAccount as any)?.dealerProfile?.asmId ?? null;
    const asmId = outletLevelAsmId || (outlet as any)?.district?.asmId;
    if (!asmId) return;

    const asm = await User.findByPk(asmId, { attributes: ['id', 'email', 'fullName', 'mobileNumber'] });
    if (!asm?.email) return;

    const asmPhone = (asm as any).mobileNumber || (asm as any).phone || null;
    await NotificationService.notify(asm.id, asm.email, {
        title: `New relocation request: ${code}`,
        message: 'A dealer submitted an outlet relocation request.',
        channels: asmPhone ? ['email', 'system', 'whatsapp'] : ['email', 'system'],
        templateCode: 'RELOCATION_SUBMITTED',
        placeholders: {
            dealerName,
            requestId: code,
            outletCode: outlet?.code || 'N/A',
            link: `${base}/relocation-requests/${request.id}`,
            ctaLabel: 'Review request',
            distance: request.distance || '0',
            phone: asmPhone || ''
        }
    }).catch((err) => console.error('[notifyRelocationSubmittedEmails] ASM:', err));
}

/**
 * Resolves the user IDs of the required 'next actor' based on the workflow stage.
 * Updated: Now awareness of sequential flows (e.g., LOI/LOA) to prevent parallel notifications.
 */
export async function resolveNextActors(requestId: string, requestType: string, newStage: string): Promise<string[]> {
    try {
        const participants = await RequestParticipant.findAll({
            where: { requestId, requestType },
            include: [{ model: User, as: 'user' }]
        });

        const actorIds = new Set<string>();

        const stageRoleMap: Record<string, string[]> = {
            // --- Common/Shared Stages ---
            'DD': [ROLES.ASM],
            'ASM': [ROLES.ASM],
            'ASM Review': [ROLES.ASM],
            'RBM': [ROLES.RBM],
            'RBM + DD-ZM Review': [ROLES.RBM, ROLES.DD_ZM],
            'ZM Review': [ROLES.DD_ZM],
            'DD ZM Review': [ROLES.DD_ZM],
            'ZBH': [ROLES.ZBH],
            'ZBH Review': [ROLES.ZBH],
            'DD Lead': [ROLES.DD_LEAD],
            'DD Lead Review': [ROLES.DD_LEAD],
            'DD Head': [ROLES.DD_HEAD],
            'DD Head Review': [ROLES.DD_HEAD],
            'NBH': [ROLES.NBH],
            'NBH Approval': [ROLES.NBH],
            'NBH Evaluation': [ROLES.NBH],
            'NBH Final Approval': [ROLES.NBH],
            'Legal': [ROLES.LEGAL_ADMIN],
            'Legal Review': [ROLES.LEGAL_ADMIN],
            'Legal Clearance': [ROLES.LEGAL_ADMIN],
            'Legal Verification': [ROLES.LEGAL_ADMIN],
            'Finance': [ROLES.FINANCE],
            'CCO Approval': [ROLES.CCO],
            'CEO Final Approval': [ROLES.CEO],

            // --- Onboarding Specific (Sequential Flows) ---
            'Level 1 Interview': [ROLES.DD_ZM, ROLES.RBM],
            'Level 1 Interview Pending': [ROLES.DD_ZM, ROLES.RBM],
            'Interview Level 1': [ROLES.DD_ZM, ROLES.RBM],
            'Level 2 Interview': [ROLES.ZBH, ROLES.DD_LEAD],
            'Level 2 Interview Pending': [ROLES.ZBH, ROLES.DD_LEAD],
            'Interview Level 2': [ROLES.ZBH, ROLES.DD_LEAD],
            'Level 3 Interview': [ROLES.NBH, ROLES.DD_HEAD],
            'Level 3 Interview Pending': [ROLES.NBH, ROLES.DD_HEAD],
            'Interview Level 3': [ROLES.NBH, ROLES.DD_HEAD],
            
            // LOI and LOA follow (DD Head -> NBH) sequence
            'LOI Approval': [ROLES.DD_HEAD, ROLES.NBH],
            'LOI In Progress': [ROLES.DD_HEAD, ROLES.NBH],
            'LOA Approval': [ROLES.DD_HEAD, ROLES.NBH],
            'LOA Pending': [ROLES.DD_HEAD, ROLES.NBH],
            
            'FDD Verification': [ROLES.FDD],
            'FDD_VERIFICATION': [ROLES.FDD],
            'Architecture Team Assigned': [ROLES.ARCHITECTURE],
            'Architecture Document Upload': [ROLES.ARCHITECTURE],

            // --- Relocation/Constitutional Specific ---
            'Submitted': [ROLES.ASM],
            'ZM/RBM Review': [ROLES.DD_ZM, ROLES.RBM],

            // --- Resignation Specific ---
            'DD Admin': [ROLES.DD_ADMIN],
            'Awaiting F&F': [ROLES.DD_LEAD, ROLES.DD_HEAD, ROLES.NBH, ROLES.DD_ADMIN],
            'Spares Clearance': [ROLES.SPARES_MANAGER],
            'Service Clearance': [ROLES.SERVICE_MANAGER],
            'Accounts Clearance': [ROLES.ACCOUNTS_MANAGER],
            'F&F Initiated': [ROLES.DD_ADMIN, ROLES.FINANCE, ROLES.DD_LEAD, ROLES.ZBH, ROLES.RBM],
            // SRS §7.5.2 — Legal acceptance letter upload triggers notification to DD-Admin + ASM
            'Resignation Legal Closure': [ROLES.DD_ADMIN, ROLES.ASM],

            // --- Termination Specific ---
            'Show Cause Notice': [ROLES.LEGAL_ADMIN],
            'Personal Hearing': [ROLES.NBH, ROLES.DD_LEAD, ROLES.ZBH, ROLES.RBM, ROLES.DD_HEAD],
            'Legal - Termination Letter': [ROLES.LEGAL_ADMIN]
        };

        const configRoles = stageRoleMap[newStage] || [];
        let expectedRoles = configRoles;

        // Sequential Logic for LOI/LOA (DD Head -> NBH)
        const sequentialStages = ['LOI Approval', 'LOI In Progress', 'LOA Approval', 'LOA Pending'];
        if (sequentialStages.includes(newStage) && configRoles.includes(ROLES.DD_HEAD) && configRoles.includes(ROLES.NBH)) {
            // Fetch existing approvals for this stage
            const approvals = await (db as any).StageApprovalAction.findAll({
                where: { applicationId: requestId, stageCode: newStage, decision: 'Approved' },
                attributes: ['actorRole']
            });
            const approvedRoles = new Set(approvals.map((a: any) => a.actorRole));

            if (!approvedRoles.has(ROLES.DD_HEAD)) {
                // DD Head hasn't approved yet, so ONLY notify DD Head
                expectedRoles = [ROLES.DD_HEAD];
            } else if (!approvedRoles.has(ROLES.NBH)) {
                // DD Head has approved, but NBH hasn't, so ONLY notify NBH
                expectedRoles = [ROLES.NBH];
            }
        }

        for (const p of participants) {
            const user = (p as any).user;
            if (user && user.roleCode && expectedRoles.includes(user.roleCode)) {
                actorIds.add(user.id);
            }
        }

        return Array.from(actorIds);
    } catch (error) {
        console.error('[resolveNextActors] error:', error);
        return [];
    }
}

/**
 * Sends turn-based notifications to the Next Actor(s), the Dealer, and all Participants.
 *
 * Channels per scenario:
 *  - Next actor (action required)  → in-app + email + WhatsApp (SRS §6.14.3)
 *  - ASM on send-back              → in-app + email + WhatsApp (SRS §6.14.3 — pending user actions)
 *  - Dealer on terminal event      → in-app + email + WhatsApp (SRS §2052 — rejection/completion)
 *  - Dealer on interim stage       → in-app only
 *  - Key observers on terminal     → in-app only
 */
export async function notifyStakeholdersOnTransition(
    requestId: string,
    requestType: string,
    targetStage: string,
    metadata: {
        code: string;
        dealerName: string;
        dealerId: string;
        actionUserFullName: string;
        action: string;
        remarks: string;
        link: string;
        changeType?: string;
    }
): Promise<void> {
    try {
        const participants = await RequestParticipant.findAll({
            where: { requestId, requestType },
            include: [{ model: User, as: 'user', attributes: ['id', 'email', 'fullName', 'roleCode', 'mobileNumber'] }]
        });

        const nextActorIds = await resolveNextActors(requestId, requestType, targetStage);

        const isSendBack = /\b(send|sent)\s*back\b/i.test(metadata.action);
        const isRejected = /\b(reject)/i.test(targetStage) || /\b(reject)/i.test(metadata.action);
        const isRevoked = /\b(revok)/i.test(targetStage) || /\b(revok)/i.test(metadata.action);
        const isWithdrawn = /\b(withdraw)/i.test(targetStage) || /\b(withdraw)/i.test(metadata.action);
        const isCompleted = /\b(complete|settled|terminated|fnf)/i.test(targetStage);
        const isTerminalEvent = isRejected || isRevoked || isWithdrawn || isCompleted;
        // Interview scheduling already sends INTERVIEW_SCHEDULED_PANELIST with full details.
        const isInterviewPendingStage = /^Level \d Interview Pending$/i.test(targetStage);

        for (const p of participants) {
            const u = (p as any).user;
            if (!u || !u.id) continue;

            const isNextActor = nextActorIds.includes(u.id);
            const isDealer = u.id === metadata.dealerId;
            const isActingUser = u.fullName === metadata.actionUserFullName;

            // Roles that should receive observer alerts on terminal events or F&F triggers
            const isKeyObserverRole = [
                'DD Lead', 'DD Head', 'NBH', 'DD Admin', 'Super Admin', 
                'SUPER_ADMIN', 'DD_ADMIN', 'Finance', 'FINANCE',
                'ZBH', 'RBM', 'DD-ZM'
            ].includes(u.roleCode || '');
            const isASM = (u.roleCode || '').toUpperCase() === 'ASM';

            // Phone for WhatsApp — directly on include'd user object
            const phone: string | null = (u as any).mobileNumber || null;

            // Skip the person who just acted (they already know)
            if (isActingUser && !isNextActor) continue;

            if (isNextActor) {
                if (isInterviewPendingStage) {
                    // Avoid duplicate mail: scheduleInterview already notifies panelists.
                    continue;
                }
                // ── Next Approver: Action Required — WhatsApp + Email + In-App ──
                // SRS §6.14.3: critical workflow actions (assignment, scheduling) trigger via email & WhatsApp
                const recipientName = (u.fullName || '').trim() || 'Team Member';
                await NotificationService.notify(u.id, u.email, {
                    title: `Action Required: ${metadata.code}`,
                    message: `${metadata.code} has reached "${targetStage}" and requires your review.`,
                    channels: phone ? ['system', 'email', 'whatsapp'] : ['system', 'email'],
                    templateCode: 'WORKFLOW_ACTION_REQUIRED',
                    placeholders: {
                        recipientName,
                        dealerName: metadata.dealerName,
                        requestId: metadata.code,
                        link: metadata.link,
                        targetStage,
                        ctaLabel: 'View application',
                        phone: phone || ''
                    }
                }).catch(e => console.error('[notifyStakeholders] next-actor:', e));

            } else if (isSendBack && isASM) {
                // ── Send Back → notify ASM via WhatsApp + Email + In-App ──
                // SRS §6.14.3: pending user actions trigger email & WhatsApp
                const recipientName = (u.fullName || '').trim() || 'Team Member';
                await NotificationService.notify(u.id, u.email, {
                    title: `Case Returned for Clarification: ${metadata.code}`,
                    message: `${metadata.code} has been sent back. Please review remarks and resubmit.`,
                    channels: phone ? ['system', 'email', 'whatsapp'] : ['system', 'email'],
                    templateCode: 'WORKFLOW_ACTION_REQUIRED',
                    placeholders: {
                        recipientName,
                        dealerName: metadata.dealerName,
                        requestId: metadata.code,
                        link: metadata.link,
                        targetStage,
                        remarks: metadata.remarks || 'No remarks provided',
                        ctaLabel: 'View application',
                        phone: phone || ''
                    }
                }).catch(e => console.error('[notifyStakeholders] send-back-asm:', e));

            } else if (isDealer) {
                // ── Dealer: in-app always; email + WhatsApp only on terminal events ──
                const terminalChannels: Array<'system' | 'email' | 'whatsapp'> = ['system', 'email'];
                if (phone) terminalChannels.push('whatsapp');

                let templateCode = 'WORKFLOW_STATUS_UPDATE_DEALER';
                const placeholders: any = {
                    requestId: metadata.code,
                    link: metadata.link,
                    targetStage,
                    dealerName: metadata.dealerName,
                    phone: phone || ''
                };

                // Override for Termination Final Closure
                if (targetStage === TERMINATION_STAGES.TERMINATED) {
                    templateCode = 'TERMINATION_FINAL_CLOSURE_DEALER';
                    placeholders.terminationDate = new Date().toLocaleDateString('en-IN', { dateStyle: 'medium' });
                }

                // Override for Constitutional Change Completion
                if (targetStage === CONSTITUTIONAL_STAGES.COMPLETED && requestType === REQUEST_TYPES.CONSTITUTIONAL) {
                    templateCode = 'CONSTITUTIONAL_CHANGE_APPROVED';
                    placeholders.proposedConstitution = metadata.changeType || 'Approved Structure';
                }

                // Override for Relocation Completion
                if (targetStage === RELOCATION_STAGES.COMPLETED && requestType === REQUEST_TYPES.RELOCATION) {
                    templateCode = 'RELOCATION_APPROVED';
                    placeholders.newLocation = metadata.remarks || 'Approved Location'; // Remarks usually contain the site address
                }

                await NotificationService.notify(u.id, u.email, {
                    title: isTerminalEvent
                        ? `Application ${isRejected ? 'Rejected' : isRevoked ? 'Revoked' : 'Completed'}: ${metadata.code}`
                        : `Application Update: ${metadata.code}`,
                    message: `Your request is now at "${targetStage}". ${metadata.action}`,
                    channels: isTerminalEvent ? terminalChannels : ['system'],
                    templateCode,
                    placeholders
                }).catch(e => console.error('[notifyStakeholders] dealer:', e));

            } else if (isTerminalEvent && isKeyObserverRole) {
                // ── Key observers (DD Lead, DD Head, NBH, DD Admin) on terminal events ──
                let templateCode = 'WORKFLOW_STATUS_UPDATE_DEALER';
                const placeholders: any = {
                    requestId: metadata.code,
                    link: metadata.link,
                    targetStage,
                    recipientName: u.fullName || 'Team'
                };

                // Override for Internal Notification of Legal Letter
                if (targetStage === TERMINATION_STAGES.LEGAL_LETTER) {
                    templateCode = 'TERMINATION_LETTER_ISSUED';
                }

                await NotificationService.notify(u.id, u.email, {
                    title: `Case Closed: ${metadata.code}`,
                    message: `${metadata.code} has been ${isRejected ? 'rejected' : isRevoked ? 'revoked' : 'completed'} at stage "${targetStage}".`,
                    channels: ['system', 'email'], // Internal teams get email too on closure
                    templateCode,
                    placeholders
                }).catch(e => console.error('[notifyStakeholders] observer:', e));
            }
        }
    } catch (error) {
        console.error('[notifyStakeholdersOnTransition] error:', error);
    }
}
