import { Request, Response } from 'express';
import bcrypt from 'bcryptjs';
import db from '../../database/models/index.js';
const { 
    Dealer, DealerCode, Application, User, AuditLog, Outlet, Region, Zone,
    Resignation, RelocationRequest, ConstitutionalChange, EorChecklist, EorChecklistItem, DealerBankDetail 
} = db;
import { AuthRequest } from '../../types/express.types.js';
import { AUDIT_ACTIONS, APPLICATION_STATUS } from '../../common/config/constants.js';
import { Op } from 'sequelize';
import { WorkflowService } from '../../services/WorkflowService.js';

export const getDealers = async (req: Request, res: Response) => {
    try {
        const where: Record<string, unknown> = {};
        const query = (req.query || {}) as Record<string, any>;
        if (String((req.query as any)?.onboarded || '') === 'true') {
            where.onboardedAt = { [Op.ne]: null };
        }
        if (String(query.activeOnly || '') === 'true') {
            where.status = { [Op.iLike]: 'active' };
        }

        const dealers = await Dealer.findAll({
            where,
            include: [
                { model: DealerCode, as: 'dealerCode' },
                { model: Application, as: 'application', attributes: ['city', 'state', 'preferredLocation'] },
                { model: User, as: 'asmManager', attributes: ['id', 'fullName', 'email', 'employeeId'], required: false },
                {
                    model: User,
                    as: 'user',
                    attributes: ['id', 'email', 'status', 'isActive', 'roleCode'],
                    ...(String(query.activeOnly || '') === 'true'
                        ? { where: { isActive: true, status: { [Op.iLike]: 'active' } }, required: true }
                        : {})
                }
            ],
            order: [['createdAt', 'DESC']]
        });
        res.json({ success: true, data: dealers });
    } catch (error) {
        console.error('Get dealers error:', error);
        res.status(500).json({ success: false, message: 'Error fetching dealer dashboard' });
    }
};

export const getDealerByApplicationId = async (req: Request, res: Response) => {
    try {
        const { applicationId } = req.params;
        const dealer = await Dealer.findOne({
            where: { applicationId },
            include: [{ model: db.User, as: 'user' }]
        });

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

        res.json({ success: true, data: dealer });
    } catch (error) {
        console.error('Get dealer by app ID error:', error);
        res.status(500).json({ success: false, message: 'Error fetching dealer' });
    }
};

export const createDealer = async (req: AuthRequest, res: Response) => {
    try {
        const { applicationId, dealerCodeId } = req.body;

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

        // SRS 3.1.2 Validation: Enforce 100% EOR (Evidence of Readiness) Checklist completion
        const eorChecklist = await EorChecklist.findOne({
            where: { applicationId: application.id },
            include: [{ model: EorChecklistItem, as: 'items' }]
        });

        const isEorComplete = eorChecklist && 
                             eorChecklist.status === 'Completed' && 
                             eorChecklist.items.length > 0 &&
                             eorChecklist.items.every((item: any) => item.isCompliant);

        if (!isEorComplete && application.overallStatus !== APPLICATION_STATUS.ONBOARDED) {
             return res.status(400).json({ 
                success: false, 
                message: `Final Onboarding Blocked: EOR Checklist is either missing, incomplete, or contains non-compliant items. All 100% readiness criteria must be verified by the auditor before inauguration.` 
            });
        }

        if (application.overallStatus !== APPLICATION_STATUS.INAUGURATION && 
            application.overallStatus !== APPLICATION_STATUS.APPROVED &&
            application.overallStatus !== APPLICATION_STATUS.ONBOARDED) {
            return res.status(400).json({ 
                success: false, 
                message: `Application must be in the '${APPLICATION_STATUS.INAUGURATION}' stage before final onboarding. Current status: ${application.overallStatus}` 
            });
        }

        // Find existing dealer or auto-detect dealer code
        let targetDealerCodeId = dealerCodeId;
        if (!targetDealerCodeId) {
            let dealerCodeRecord = await DealerCode.findOne({ where: { applicationId } });
            
            // AUTOMATIC FALLBACK: If no code record exists, create a default one to ensure 
            // downstream modules (Termination/Resignation) have a valid link.
            if (!dealerCodeRecord) {
                console.log(`[Dealer Onboarding] No DealerCode found for Application ${applicationId}. Creating default record.`);
                const tempCode = `RE-T-${Math.floor(Math.random() * 90000) + 10000}`;
                dealerCodeRecord = await DealerCode.create({
                    dealerCode: tempCode,
                    applicationId: application.id,
                    salesCode: tempCode,
                    serviceCode: `${tempCode}-S`,
                    status: 'Active',
                    isUsed: true
                });
            }
            
            targetDealerCodeId = dealerCodeRecord.id;
        }

        const existingDealer = await Dealer.findOne({ where: { applicationId } });
        let dealer = existingDealer;

        if (existingDealer) {
            // Update existing dealer if it's missing the code
            if (!existingDealer.dealerCodeId && targetDealerCodeId) {
                await existingDealer.update({ dealerCodeId: targetDealerCodeId });
                
                // Mark Code as Used
                await DealerCode.update({ 
                    isUsed: true, 
                    usedAt: new Date(), 
                    usedByApplicationId: applicationId 
                }, { where: { id: targetDealerCodeId } });
            }
        } else {
            // Mark Code as Used
            if (targetDealerCodeId) {
                await DealerCode.update({ 
                    isUsed: true, 
                    usedAt: new Date(), 
                    usedByApplicationId: applicationId 
                }, { where: { id: targetDealerCodeId } });
            }

            // Fetch milestone dates and payments from requests
            const loiRequest = await db.LoiRequest.findOne({ 
                where: { applicationId: application.id, status: { [Op.iLike]: 'Approved' } }, 
                order: [['approvedAt', 'DESC']] 
            });
            const loaRequest = await db.LoaRequest.findOne({ 
                where: { applicationId: application.id, status: { [Op.iLike]: 'Approved' } }, 
                order: [['approvedAt', 'DESC']] 
            });
            const missingFields = [];
            if (!application.panNumber) missingFields.push('PAN Number');
            if (!application.gstNumber) missingFields.push('GST Number');
            if (!application.bankName) missingFields.push('Bank Name');
            if (!application.accountNumber) missingFields.push('Account Number');
            if (!application.ifscCode) missingFields.push('IFSC Code');

            if (missingFields.length > 0) {
                return res.status(400).json({
                    success: false,
                    message: `Final Onboarding Failed: Mandatory fields missing: ${missingFields.join(', ')}. These must be filled before the dealer can be onboarded.`
                });
            }

            const deposit = await db.SecurityDeposit.findOne({
                where: { 
                    applicationId: application.id, 
                    status: 'Verified',
                    depositType: 'SECURITY_DEPOSIT' // Strictly the Security Deposit
                },
                order: [['verifiedAt', 'DESC']]
            });

            // Create Dealer Profile
            dealer = await Dealer.create({
                applicationId,
                dealerCodeId: targetDealerCodeId,
                legalName: application.applicantName,
                businessName: application.applicantName,
                registeredAddress: application.address || application.businessAddress || 'Address Pending',
                panNumber: application.panNumber,
                gstNumber: application.gstNumber,
                constitutionType: application.constitutionType || 'Proprietorship',
                status: 'Active',
                onboardedAt: new Date(),
                loiDate: loiRequest?.approvedAt,
                loaDate: loaRequest?.approvedAt,
                securityDepositAmount: deposit?.amount,
                securityDepositDate: deposit?.verifiedAt
            });

            // SRS 8.1: Automatically initialize Primary Bank Detail from application data
            if (application.accountNumber && application.ifscCode) {
                await DealerBankDetail.create({
                    dealerId: dealer.id,
                    accountHolderName: application.accountHolderName || application.applicantName,
                    accountNumber: application.accountNumber,
                    ifscCode: application.ifscCode,
                    bankName: application.bankName || 'Pending',
                    branchName: application.branchName || 'Pending',
                    isPrimary: true,
                    status: 'active'
                });
                console.log(`[Dealer Onboarding] Primary bank detail created for dealer ${dealer.id}.`);
            }

            await AuditLog.create({
                userId: req.user?.id,
                action: AUDIT_ACTIONS.CREATED,
                entityType: 'dealer',
                entityId: dealer.id
            });
        }


        // --- Create or Update User Account for the Dealer ---
        let user = await User.findOne({ where: { email: application.email } });
        
        if (user) {
            // Update existing user to Dealer role and link dealerId
            await user.update({
                roleCode: 'Dealer',
                dealerId: dealer.id,
                status: 'active',
                isActive: true
            });
            console.log(`[Dealer Onboarding] Updated existing user ${user.email} to Dealer role.`);
        } else {
            // Create new User account
            const hashedPassword = await bcrypt.hash('Dealer@123', 10); // Default password
            user = await User.create({
                fullName: application.applicantName,
                email: application.email,
                password: hashedPassword,
                roleCode: 'Dealer',
                dealerId: dealer.id,
                mobileNumber: application.phone,
                status: 'active',
                isActive: true,
                isExternal: true, // Dealers are external users
                districtId: application.districtId || application.locationId
            });
            console.log(`[Dealer Onboarding] Created new Dealer user account for ${user.email}.`);
        }

        await AuditLog.create({
            userId: req.user?.id,
            action: AUDIT_ACTIONS.CREATED,
            entityType: 'user',
            entityId: user.id,
            newData: { roleCode: 'Dealer', dealerId: dealer.id }
        });

        // --- Create or Link Outlet for this specific application ---
        // We use the application's unique ID to ensure we don't duplicate THE SAME application's outlet,
        // but we allow multiple outlets for the same User ID.
        let outlet = await Outlet.findOne({ 
            where: { 
                dealerId: user.id,
                name: { [Op.like]: `%${application.city || 'Primary'}%` }, // Rough check for same location
                createdAt: { [Op.gte]: new Date(new Date().getTime() - 60000) } // Prevent double-clicks in same minute
            } 
        });

        if (!outlet) {
            const dealerCodeRecord = await DealerCode.findOne({ where: { applicationId: application.id } });
            const outletCode = `OUT-${dealerCodeRecord?.dealerCode || Date.now().toString().slice(-6)}`;

            outlet = await Outlet.create({
                code: outletCode,
                name: `${application.applicantName} - ${application.city || 'Primary'}`,
                type: application.businessType === 'Studio' ? 'Studio' : 'Dealership',
                address: application.address || application.businessAddress || 'Address Pending',
                city: application.city || 'City Pending',
                state: application.state || 'State Pending',
                pincode: application.pincode || '000000',
                status: 'Active',
                establishedDate: new Date(),
                dealerId: user.id,
                districtId: application.districtId || application.locationId
            });

            console.log(`[Dealer Onboarding] Created outlet ${outlet.code} for application ${application.applicationId} linked to user ${user.email}.`);

            await AuditLog.create({
                userId: req.user?.id,
                action: AUDIT_ACTIONS.CREATED,
                entityType: 'outlet',
                entityId: outlet.id,
                newData: { code: outlet.code, name: outlet.name }
            });
        }

        // Final Step: Update Application Status to Onboarded
        if (application) {
            await WorkflowService.transitionApplication(application, APPLICATION_STATUS.ONBOARDED, req.user?.id || null, {
                reason: 'Dealer Onboarding Finalized',
                progressPercentage: 100
            });
        }

        res.status(201).json({ 
            success: true, 
            message: 'Dealer profile, user account, and primary outlet created successfully. Application status is now ONBOARDED.', 
            data: { 
                dealer, 
                user: { email: user.email, role: user.roleCode },
                outlet: { code: outlet.code, name: outlet.name }
            } 
        });
    } catch (error) {
        console.error('Create dealer error:', error);
        res.status(500).json({ success: false, message: 'Error creating dealer' });
    }
};

export const updateDealer = async (req: AuthRequest, res: Response) => {
    try {
        const { id } = req.params;
        const updateData = req.body;

        const dealer = await Dealer.findByPk(id);
        if (!dealer) return res.status(404).json({ success: false, message: 'Dealer not found' });

        await dealer.update(updateData);

        res.json({ success: true, message: 'Dealer updated successfully' });
    } catch (error) {
        res.status(500).json({ success: false, message: 'Error updating dealer' });
    }
};

export const getDealerDashboard = async (req: AuthRequest, res: Response) => {
    try {
        const userId = req.user?.id;
        if (!userId) return res.status(401).json({ success: false, message: 'Unauthorized' });

        // 1. Fetch User and linked Dealer Profile
        const user = await User.findByPk(userId, {
            include: [{ 
                association: 'dealerProfile', 
                include: [{ association: 'dealerCode' }] 
            }]
        });

        // 2. Fetch Active Outlets
        const outlets = await Outlet.findAll({
            where: { dealerId: userId },
            order: [['createdAt', 'DESC']]
        });

        // 3. Fetch Request Counts & Recent History
        const [resignations, relocations, constitutional] = await Promise.all([
            Resignation.findAll({ where: { dealerId: userId }, order: [['createdAt', 'DESC']] }),
            RelocationRequest.findAll({ where: { dealerId: userId }, order: [['createdAt', 'DESC']] }),
            ConstitutionalChange.findAll({ where: { dealerId: userId }, order: [['createdAt', 'DESC']] })
        ]);

        // Combine and sort recent requests
        const allRequests = [
            ...resignations.map((r: any) => ({ id: r.resignationId, type: 'Resignation', title: r.reason, status: r.status, date: r.submittedOn || (r as any).createdAt, color: 'bg-red-100 text-red-700 border-red-300' })),
            ...relocations.map((r: any) => ({ id: r.requestId, type: 'Relocation', title: `Relocation to ${r.newCity}`, status: r.status, date: (r as any).createdAt, color: 'bg-amber-100 text-amber-700 border-amber-300' })),
            ...constitutional.map((r: any) => ({ id: r.requestId, type: 'Constitutional Change', title: r.changeType, status: r.status, date: (r as any).createdAt, color: 'bg-blue-100 text-blue-700 border-blue-300' }))
        ].sort((a: any, b: any) => new Date(b.date).getTime() - new Date(a.date).getTime()).slice(0, 5);

        res.json({
            success: true,
            data: {
                profile: {
                    name: user?.fullName,
                    email: user?.email,
                    dealerCode: (user as any)?.dealerProfile?.dealerCode?.code || 'N/A',
                    businessName: (user as any)?.dealerProfile?.businessName || 'N/A'
                },
                outlets: outlets.map((o: any) => ({
                    id: o.id,
                    name: o.name,
                    code: o.code,
                    type: o.type,
                    status: o.status,
                    location: `${o.city}, ${o.state}`
                })),
                stats: {
                    constitutional: constitutional.length,
                    relocation: relocations.length,
                    resignation: resignations.length,
                    total: constitutional.length + relocations.length + resignations.length
                },
                recentRequests: allRequests
            }
        });
    } catch (error) {
        console.error('Get dealer dashboard error:', error);
        res.status(500).json({ success: false, message: 'Error fetching dashboard data' });
    }
};
