import { Request, Response } from 'express';
import { Op } from 'sequelize';
import db from '../../database/models/index.js';
const { FddAssignment, FddReport, Application } = db;
import { AuthRequest } from '../../types/express.types.js';
import { AUDIT_ACTIONS, APPLICATION_STATUS, APPLICATION_STAGES, ROLES } from '../../common/config/constants.js';
import { WorkflowService } from '../../services/WorkflowService.js';
import { pickApplicationAuditContext, safeAuditLogCreate } from '../../services/applicationAuditLog.service.js';
import { NotificationService } from '../../services/NotificationService.js';
import { formatDueDateDaysFromNow, DEFAULT_FDD_DOCUMENT_CHECKLIST } from '../../constants/onboarding-email-defaults.js';
import { getFrontendBaseUrl, getProspectPortalUrl } from '../../common/utils/frontendUrl.js';

export const getAssignment = async (req: Request, res: Response) => {
    try {
        const { applicationId } = req.params;
        const targetId = applicationId as string;

        // Resolve application first to get UUID
        const isUUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(targetId);
        const application = await Application.findOne({
            where: isUUID ? { [Op.or]: [{ id: targetId }, { applicationId: targetId }] } : { applicationId: targetId }
        });

        if (!application) {
            return res.status(404).json({ success: false, message: 'Application not found' });
        }

        const assignment = await FddAssignment.findOne({
            where: { applicationId: application.id },
            include: [{ 
                model: FddReport, 
                as: 'reports',
                include: [
                    { model: db.User, as: 'submitter', attributes: ['fullName'] },
                    { model: db.User, as: 'verifier', attributes: ['fullName'] }
                ]
            }]
        });
        res.json({ success: true, data: assignment });
    } catch (error) {
        console.error('Get FDD assignment error:', error);
        res.status(500).json({ success: false, message: 'Error fetching FDD assignment' });
    }
};

export const assignAgency = async (req: AuthRequest, res: Response) => {
    try {
        const { applicationId, assignedToAgency } = req.body;
        const targetId = applicationId as string;

        // Resolve application first to get UUID
        const isUUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(targetId);
        const application = await Application.findOne({
            where: isUUID ? { [Op.or]: [{ id: targetId }, { applicationId: targetId }] } : { applicationId: targetId }
        });

        if (!application) {
            return res.status(404).json({ success: false, message: 'Application not found' });
        }

        const assignment = await FddAssignment.create({
            applicationId: application.id,
            assignedToAgency, // Agency User ID
            status: 'Assigned'
        });

        // Bridge: Transition application to active FDD stage
        await WorkflowService.transitionApplication(application, APPLICATION_STATUS.FDD_VERIFICATION, req.user?.id || null, {
            reason: 'FDD Agency assigned. Initiating financial due diligence.',
            stage: APPLICATION_STAGES.FDD,
            progressPercentage: 70
        });

        await safeAuditLogCreate({
            userId: req.user?.id,
            action: AUDIT_ACTIONS.FDD_ASSIGNED,
            entityType: 'fdd_assignment',
            entityId: assignment.id,
            newData: { assignedToAgency, applicationId: application.id },
        });
        await safeAuditLogCreate({
            userId: req.user?.id,
            action: AUDIT_ACTIONS.FDD_ASSIGNED,
            entityType: 'application',
            entityId: application.id,
            newData: {
                assignmentId: assignment.id,
                assignedToAgency,
                note: 'FDD agency assigned; application moved to FDD verification.',
                context: pickApplicationAuditContext(application),
            },
        });

        // SRS §6.15.3.1 — Notify assigned FDD agency user of their assignment
        const fddUser = await db.User.findByPk(assignedToAgency);
        if (fddUser) {
            const phone = (fddUser as any).mobileNumber || null;
            NotificationService.notify(fddUser.id, fddUser.email, {
                title: `FDD Assignment: ${application.applicationId}`,
                message: `You have been assigned to conduct Financial Due Diligence for application ${application.applicationId}.`,
                channels: phone ? ['system', 'email', 'whatsapp'] : ['system', 'email'],
                templateCode: 'USER_ASSIGNED',
                placeholders: {
                    userName: fddUser.fullName || 'Team',
                    applicantName: application.applicantName || '',
                    applicationId: application.applicationId,
                    dealerName: application.applicantName || '',
                    participantType: 'FDD Partner',
                    link: `${getFrontendBaseUrl()}/applications/${application.id}`,
                    ctaLabel: 'View Assignment',
                    phone: phone || ''
                }
            }).catch((e: any) => console.error('[FDD] Agency notify failed:', e));
        }

        const portalBaseFdd = getFrontendBaseUrl();
        if (application.email) {
            const applicantAcct = await db.User.findOne({
                where: { email: application.email },
                attributes: ['id', 'mobileNumber']
            });
            const fddPartnerName = fddUser ? (fddUser as any).fullName || 'Assigned FDD partner' : 'Royal Enfield FDD team';
            await NotificationService.notify(applicantAcct?.id ?? null, application.email, {
                title: `FDD documents required — ${application.applicationId}`,
                message: 'Please upload the financial documents requested for due diligence.',
                channels: ['email'],
                templateCode: 'FDD_DOCUMENT_REQUEST',
                placeholders: {
                    applicantName: application.applicantName || 'Applicant',
                    applicationId: application.applicationId,
                    fddPartnerName,
                    dueDate: formatDueDateDaysFromNow(14),
                    documentChecklist: DEFAULT_FDD_DOCUMENT_CHECKLIST,
                    link: getProspectPortalUrl(application.id),
                    ctaLabel: 'Upload FDD documents'
                }
            }).catch((e: any) => console.error('[FDD] Applicant document request email failed:', e));
        }

        res.status(201).json({ success: true, message: 'FDD Agency assigned', data: assignment });
    } catch (error) {
        console.error('Assign FDD agency error:', error);
        res.status(500).json({ success: false, message: 'Error assigning agency' });
    }
};

export const uploadReport = async (req: AuthRequest, res: Response) => {
    try {
        const { assignmentId, reportDocumentId, findings, recommendation, applicationId } = req.body;
        let finalAssignmentId = assignmentId;
        
        // Auto-assign logic if assignmentId is missing
        if (!finalAssignmentId && applicationId) {
            const appId = applicationId;
            const isUUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(appId);
            const application = await Application.findOne({
                where: isUUID ? { [Op.or]: [{ id: appId }, { applicationId: appId }] } : { applicationId: appId }
            });

            if (application) {
                const [newAssignment] = await FddAssignment.findOrCreate({
                    where: { applicationId: application.id },
                    defaults: {
                        assignedToAgency: req.user?.id,
                        status: 'Assigned'
                    }
                });
                finalAssignmentId = newAssignment.id;
            }
        }

        if (!finalAssignmentId) {
            return res.status(400).json({ success: false, message: 'Assignment ID or valid Application ID is required' });
        }

        let report = await FddReport.findOne({ where: { assignmentId: finalAssignmentId } });
        
        if (report) {
            await report.update({
                reportDocumentId,
                findings,
                recommendation,
                submittedBy: req.user?.id
            });
        } else {
            report = await FddReport.create({
                assignmentId: finalAssignmentId,
                reportDocumentId,
                findings,
                recommendation,
                submittedBy: req.user?.id
            });
        }

        // Update Assignment Status
        await FddAssignment.update(
            { status: 'Report Submitted' },
            { where: { id: finalAssignmentId } }
        );

        // Fetch application to transition
        const assignment = await FddAssignment.findByPk(finalAssignmentId);
        if (assignment) {
            const application = await Application.findByPk(assignment.applicationId);
            if (application) {
                await WorkflowService.transitionApplication(application, APPLICATION_STATUS.FDD_VERIFICATION, req.user?.id || null, {
                    reason: 'FDD Report uploaded. Pending review to proceed to LOI stage.',
                    forceLog: true // Log even if status is same
                });

                // SRS §6.15.3.1 — Notify Finance + DD-Admin that FDD report is submitted
                const fddReportRoles = [ROLES.FINANCE, ROLES.DD_ADMIN];
                for (const role of fddReportRoles) {
                    const roleUsers = await db.User.findAll({ where: { roleCode: role } });
                    for (const u of roleUsers) {
                        NotificationService.notify(u.id, u.email, {
                            title: `FDD Report Submitted: ${application.applicationId}`,
                            message: `The FDD agency has submitted their financial due diligence report for ${application.applicationId}. Review is required before LOI stage.`,
                            channels: ['system', 'email'],
                            templateCode: 'WORKFLOW_ACTION_REQUIRED',
                            placeholders: {
                                dealerName: application.applicantName || '',
                                requestId: application.applicationId,
                                targetStage: 'FDD Review',
                                link: `${getFrontendBaseUrl()}/applications/${application.id}`,
                                phone: ''
                            }
                        }).catch((e: any) => console.error('[FDD] Finance/Admin notify failed:', e));
                    }
                }
            }
        }

        res.status(201).json({ success: true, message: 'FDD Report uploaded successfully. Pending Admin review.', data: report });
    } catch (error) {
        console.error('Upload FDD report error:', error);
        res.status(500).json({ success: false, message: 'Error uploading report' });
    }
};

export const flagNonResponsive = async (req: AuthRequest, res: Response) => {
    try {
        const { applicationId, remarks } = req.body;
        const targetId = applicationId as string;

        // Resolve application first to get UUID
        const isUUID = /^[0-9a-fA-F]{8}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{4}-[0-9a-fA-F]{12}$/.test(targetId);
        const application = await Application.findOne({
            where: isUUID ? { [Op.or]: [{ id: targetId }, { applicationId: targetId }] } : { applicationId: targetId }
        });

        if (!application) {
            return res.status(404).json({ success: false, message: 'Application not found' });
        }

        const previousStatutory = application.statutoryStatus;
        // 1. Update Application status at model level
        await application.update({ statutoryStatus: 'Flagged' });

        console.log(`[FDDController] Flagging application ${application.id} as non-responsive (FDD)`);
        await safeAuditLogCreate({
            userId: req.user?.id,
            action: AUDIT_ACTIONS.FDD_FLAGGED_NON_RESPONSIVE,
            entityType: 'application',
            entityId: application.id,
            oldData: {
                statutoryStatus: previousStatutory,
                overallStatus: application.overallStatus,
                currentStage: application.currentStage,
            },
            newData: {
                statutoryStatus: 'Flagged',
                remarks: remarks || 'Applicant is non-responsive to FDD queries.',
                context: pickApplicationAuditContext(application),
            },
        });

        res.json({ success: true, message: 'Application flagged successfully' });
    } catch (error) {
        console.error('Flag non-responsive error:', error);
        res.status(500).json({ success: false, message: 'Error highlighting non-responsiveness' });
    }
};
