import db from '../database/models/index.js';
const { RelocationRequest, AuditLog, User, RequestParticipant, Outlet } = db;
import { AUDIT_ACTIONS, RELOCATION_STAGES, ROLES, REQUEST_TYPES } from '../common/config/constants.js';
import { getOffboardingAuditAction, formatOffboardingAction } from '../common/utils/offboardingWorkflow.utils.js';
import { writeWorkflowActivityWorknote } from '../common/utils/workflowWorknote.js';
import logger from '../common/utils/logger.js';
import { NotificationService } from './NotificationService.js';
import { syncSlaOnStageTransition } from '../common/utils/slaWorkflowSync.js';
import { getFrontendBaseUrl } from '../common/utils/frontendUrl.js';

export class RelocationWorkflowService {
    /**
     * Standardized method to transition a relocation request status
     */
    static async transitionRelocation(request: any, targetStatus: string, userId: string | null = null, metadata: any = {}) {
        const previousStatus = request.status;
        const { reason, stage, progressPercentage, action, auditAction } = metadata;

        const updateData: any = {
            status: targetStatus,
            updatedAt: new Date()
        };

        // Update stage if provided and valid
        if (stage && Object.values(RELOCATION_STAGES).includes(stage)) {
            updateData.currentStage = stage;
        }

        // Update progress percentage if explicitly provided
        if (progressPercentage !== undefined) {
            updateData.progressPercentage = progressPercentage;
        }

        const sourceStage = request.currentStage;

        // 1. Update Request Record
        await request.update(updateData);

        // 2. Update Timeline (JSON array)
        const user = userId ? await User.findByPk(userId) : null;
        const timelineEntry = {
            stage: sourceStage, // Store the stage where the action happened
            targetStage: stage || targetStatus,
            timestamp: new Date(),
            user: user ? user.fullName : 'System',
            action: action || `Transitioned to ${targetStatus}`,
            remarks: reason || ''
        };

        const updatedTimeline = [...(request.timeline || []), timelineEntry];
        await request.update({ timeline: updatedTimeline });

        const toStage = updateData.currentStage;
        if (toStage && toStage !== sourceStage) {
            await syncSlaOnStageTransition({
                entityType: 'relocation',
                entityId: request.id,
                fromStage: sourceStage,
                toStage
            });
        }

        // 3. Create Audit Log using standardized mapper
        const { actionType } = metadata;
        let resolvedAuditAction = getOffboardingAuditAction(actionType || action || 'Approved', REQUEST_TYPES.RELOCATION);
        if (auditAction) {
            resolvedAuditAction = auditAction;
        } else if (action === 'REJECT') {
            resolvedAuditAction = AUDIT_ACTIONS.REJECTED;
        } else if (action === 'REVOKE') {
            resolvedAuditAction = AUDIT_ACTIONS.RELOCATION_REVOKED;
        } else if (action === 'SEND_BACK') {
            resolvedAuditAction = AUDIT_ACTIONS.RELOCATION_SENT_BACK;
        }

        await db.RelocationAudit.create({
            userId: userId,
            relocationRequestId: request.id,
            action: formatOffboardingAction(resolvedAuditAction),
            remarks: reason || '',
            details: { status: targetStatus, stage: sourceStage, targetStage: stage || targetStatus }
        });
        
        // 4. Create Worknote for standardized communication trail
        if (reason && userId) {
            try {
                // Prepend action to remarks for better context in Work Notes
                const actionPrefix = action ? `${formatOffboardingAction(action)}: ` : '';
                await writeWorkflowActivityWorknote({
                    requestId: request.id,
                    requestType: 'relocation',
                    userId: userId,
                    noteText: `${actionPrefix}${reason}`,
                    noteType: (action === 'SEND_BACK' || action === 'SEND_BACK_TO_ASM') ? 'workflow' : 'internal'
                });
            } catch (wnErr) {
                logger.error('[RelocationWorkflowService] failed to write worknote:', wnErr);
            }
        }

        console.log(`[RelocationWorkflowService] Transitioned Request ${request.requestId} to ${targetStatus}`);

        await request.reload();
        const dealerUser = await User.findByPk(request.dealerId, { attributes: ['id', 'email', 'fullName'] });
        if (dealerUser?.email) {
            const portalBase = getFrontendBaseUrl();
            const stageLabel = request.currentStage || request.status || targetStatus;
            
            const { notifyStakeholdersOnTransition } = await import('../common/utils/workflow-email-notifications.js');

            await notifyStakeholdersOnTransition(
                request.id,
                REQUEST_TYPES.RELOCATION,
                stageLabel,
                {
                    code: request.requestId,
                    dealerName: dealerUser.fullName || 'Dealer',
                    dealerId: dealerUser.id,
                    actionUserFullName: user ? user.fullName : 'System',
                    action: action || `Transitioned to ${targetStatus}`,
                    remarks: reason || 'N/A',
                    link: `${portalBase}/relocation-requests/${request.id}`
                }
            );
        }

        return request;
    }

    /**
     * Checks if a user is authorized to perform an action in the current stage
     */
    static async canUserAction(request: any, user: any) {
        if (!user) return false;
        
        // Super Admin bypass
        if (user.roleCode === ROLES.SUPER_ADMIN) return true;

        const stageMapping: Record<string, string> = {
            [RELOCATION_STAGES.ASM_REVIEW]: ROLES.ASM,
            'DD Admin Review': ROLES.ASM, // Legacy/alias mapping for older requests
            [RELOCATION_STAGES.RBM_REVIEW]: ROLES.RBM,
            [RELOCATION_STAGES.DD_ZM_REVIEW]: ROLES.DD_ZM,
            [RELOCATION_STAGES.ZBH_REVIEW]: ROLES.ZBH,
            [RELOCATION_STAGES.DD_LEAD_REVIEW]: ROLES.DD_LEAD,
            [RELOCATION_STAGES.NBH_APPROVAL]: ROLES.NBH,
            [RELOCATION_STAGES.LEGAL_CLEARANCE]: ROLES.LEGAL_ADMIN
        };

        const requiredRole = stageMapping[request.currentStage];
        if (!requiredRole) return false;

        // Role-based check
        if (user.roleCode !== requiredRole) return false;

        // Stage-specific participant assignment enforcement: actor must be mapped on this request.
        const participant = await RequestParticipant.findOne({
            where: {
                requestId: request.id,
                requestType: REQUEST_TYPES.RELOCATION,
                userId: user.id
            },
            attributes: ['id']
        });
        if (participant) return true;
        const anyParticipant = await RequestParticipant.findOne({
            where: { requestId: request.id, requestType: REQUEST_TYPES.RELOCATION },
            attributes: ['id']
        });
        // Backward compatibility for legacy requests created before participant auto-assignment.
        if (!anyParticipant) return true;

        // Match relocation.controller getRequests: territory actors must act even if RequestParticipant
        // omitted them (e.g. ASM was taken only from Dealer.asmId while list uses district.asmId).
        return await RelocationWorkflowService.userMatchesRelocationOutletHierarchy(request.id, user);
    }

    /** Same outlet hierarchy checks as internal-user filter on relocation list (ASM/RBM/DD-ZM/ZBH). */
    static async userMatchesRelocationOutletHierarchy(requestId: string, user: any): Promise<boolean> {
        const row = await RelocationRequest.findByPk(requestId, {
            include: [
                {
                    model: User,
                    as: 'dealer',
                    attributes: ['id'],
                    include: [{ model: db.Dealer, as: 'dealerProfile', attributes: ['asmId'] }]
                },
                {
                    model: Outlet,
                    as: 'outlet',
                    include: [
                        {
                            model: db.District,
                            as: 'district',
                            include: [
                                { model: db.Region, as: 'region' },
                                { model: db.Zone, as: 'zone' }
                            ]
                        }
                    ]
                }
            ]
        });
        if (!row) return false;
        const outlet = (row as any).outlet;
        const district = outlet?.district;
        if (!district) return false;
        const uid = user.id;
        const rc = user.roleCode;
        const outletLevelAsmId = (row as any).dealer?.dealerProfile?.asmId ?? null;
        if (rc === ROLES.ASM && (outletLevelAsmId === uid || district.asmId === uid)) return true;
        if (rc === ROLES.RBM && district.region?.rbmId === uid) return true;
        if (rc === ROLES.DD_ZM && district.zmId === uid) return true;
        if (rc === ROLES.ZBH && district.zone?.zbhId === uid) return true;
        return false;
    }
}
