import { Request, Response } from 'express';
import db from '../../database/models/index.js';
const { Questionnaire, QuestionnaireQuestion, QuestionnaireOption, QuestionnaireResponse, Application, ApplicationStatusHistory } = db;
import { v4 as uuidv4 } from 'uuid';
import { AuthRequest } from '../../types/express.types.js';
import {
    APPLICATION_STATUS,
    SYSTEM_AUDIT_MODULES,
    SYSTEM_AUDIT_ACTIONS
} from '../../common/config/constants.js';
import { sendQuestionnaireAckEmail } from '../../common/utils/email.service.js';
import { logSystemAudit } from '../../services/systemAuditLog.service.js';

export const getLatestQuestionnaire = async (req: Request, res: Response) => {
    try {
        const questionnaire = await Questionnaire.findOne({
            where: { isActive: true },
            include: [{
                model: QuestionnaireQuestion,
                as: 'questions',
                order: [['order', 'ASC']],
                include: [{
                    model: QuestionnaireOption,
                    as: 'questionOptions',
                    order: [['order', 'ASC']]
                }]
            }],
            order: [['createdAt', 'DESC']]
        });

        if (!questionnaire) {
            return res.status(404).json({ success: false, message: 'No active questionnaire found' });
        }

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

export const createQuestionnaireVersion = async (req: AuthRequest, res: Response) => {
    try {
        const { version, questions } = req.body; // questions is array of { text, type, options, weight, section }

        // Deactivate old versions
        await Questionnaire.update({ isActive: false }, { where: { isActive: true } });

        const newQuestionnaire = await Questionnaire.create({
            version,
            isActive: true
        });

        if (questions && questions.length > 0) {
            for (const [index, q] of questions.entries()) {
                const question = await QuestionnaireQuestion.create({
                    questionnaireId: newQuestionnaire.id,
                    sectionName: q.sectionName || 'General',
                    questionText: q.questionText,
                    inputType: q.inputType || 'text',
                    options: null, // Legacy field
                    weight: q.weight || 0,
                    order: q.order || index + 1,
                    isMandatory: q.isMandatory !== false
                });

                if (q.options && Array.isArray(q.options) && q.options.length > 0) {
                    const optionRecords = q.options.map((opt: any, idx: number) => ({
                        questionId: question.id,
                        optionText: opt.text,
                        score: opt.score || 0,
                        order: idx + 1
                    }));
                    await QuestionnaireOption.bulkCreate(optionRecords);
                }
            }
        }

        const fullQuestionnaire = await Questionnaire.findByPk(newQuestionnaire.id, {
            include: [{ model: QuestionnaireQuestion, as: 'questions' }]
        });

        await logSystemAudit(req, {
            module: SYSTEM_AUDIT_MODULES.QUESTIONNAIRE,
            entityType: 'questionnaire',
            entityId: newQuestionnaire.id,
            entityLabel: `Questionnaire ${version}`,
            action: SYSTEM_AUDIT_ACTIONS.CREATED,
            description: `Published questionnaire version ${version} with ${questions?.length || 0} question(s); previous active version deactivated`,
            newData: {
                version,
                isActive: true,
                questionCount: questions?.length || 0
            }
        });

        res.status(201).json({ success: true, data: fullQuestionnaire });
    } catch (error) {
        console.error('Create questionnaire error:', error);
        res.status(500).json({ success: false, message: 'Error creating questionnaire version' });
    }
};

export const submitResponse = async (req: AuthRequest, res: Response) => {
    try {
        const { applicationId, responses } = req.body; // responses: [{ questionId, value }]

        const targetId = applicationId as string;
        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);

        // Verify application
        const application = await Application.findOne({
            where: isUUID ? { [db.Sequelize.Op.or]: [{ id: targetId }, { applicationId: targetId }] } : { applicationId: targetId }
        });

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

        // Get active questionnaire to link
        const questionnaire = await Questionnaire.findOne({ where: { isActive: true } });
        if (!questionnaire) return res.status(400).json({ success: false, message: 'No active questionnaire' });

        const responseRecords = responses.map((r: any) => ({
            applicationId: application.id,
            questionnaireId: questionnaire.id,
            questionId: r.questionId,
            responseValue: r.value,
            attachmentUrl: r.attachmentUrl || null
        }));

        // Bulk create responses (maybe delete old ones for this app/questionnaire first?)
        // For now, straight insert
        await QuestionnaireResponse.bulkCreate(responseRecords);

        // Calculate Score Logic (Placeholder for ONB-04)
        // calculateAndSaveScore(applicationId, questionnaire.id);

        await logSystemAudit(req, {
            module: SYSTEM_AUDIT_MODULES.QUESTIONNAIRE,
            entityType: 'questionnaire_response',
            entityId: application.id,
            entityLabel: `Application ${application.applicationId || application.id} · ${application.applicantName || 'Applicant'}`,
            action: SYSTEM_AUDIT_ACTIONS.SUBMITTED,
            description: `Authenticated questionnaire response submitted (${responses.length} answer(s))`,
            metadata: {
                questionnaireId: questionnaire.id,
                applicationId: application.id,
                responseCount: responses.length
            }
        });

        res.json({ success: true, message: 'Responses submitted successfully' });
    } catch (error) {
        console.error('Submit response error:', error);
        res.status(500).json({ success: false, message: 'Error submitting responses' });
    }
};

export const getAllQuestionnaires = async (req: Request, res: Response) => {
    try {
        const questionnaires = await Questionnaire.findAll({
            order: [['createdAt', 'DESC']],
            attributes: ['id', 'version', 'isActive', 'createdAt']
        });
        res.json({ success: true, data: questionnaires });
    } catch (error) {
        console.error('Get all questionnaires error:', error);
        res.status(500).json({ success: false, message: 'Error fetching questionnaires' });
    }
};

export const getQuestionnaireById = async (req: Request, res: Response) => {
    try {
        const { id } = req.params;
        const questionnaire = await Questionnaire.findByPk(id, {
            include: [{
                model: QuestionnaireQuestion,
                as: 'questions',
                order: [['order', 'ASC']],
                include: [{
                    model: QuestionnaireOption,
                    as: 'questionOptions',
                    order: [['order', 'ASC']]
                }]
            }]
        });

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

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

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

        // Verify valid application exists
        const application = await Application.findOne({ where: { applicationId } });
        if (!application) {
            return res.status(404).json({ success: false, message: 'Invalid Application ID' });
        }

        // Check if already submitted
        if (application.overallStatus !== APPLICATION_STATUS.QUESTIONNAIRE_PENDING) {
            return res.status(400).json({
                success: false,
                message: 'Questionnaire already submitted or link expired',
                code: 'ALREADY_SUBMITTED' // Frontend can use this code
            });
        }

        // Fetch active questionnaire
        const questionnaire = await Questionnaire.findOne({
            where: { isActive: true },
            include: [{
                model: QuestionnaireQuestion,
                as: 'questions',
                order: [['order', 'ASC']],
                include: [{
                    model: QuestionnaireOption,
                    as: 'questionOptions',
                    order: [['order', 'ASC']]
                }]
            }]
        });

        if (!questionnaire) {
            return res.status(404).json({ success: false, message: 'No active questionnaire found' });
        }

        res.json({ success: true, data: { applicationName: application.applicantName, ...questionnaire.toJSON() } });
    } catch (error) {
        console.error('Get public questionnaire error:', error);
        res.status(500).json({ success: false, message: 'Error fetching questionnaire' });
    }
};

export const submitPublicResponse = async (req: Request, res: Response) => {
    try {
        const { applicationId, responses } = req.body;

        const application = await Application.findOne({ where: { applicationId } });
        if (!application) {
            return res.status(404).json({ success: false, message: 'Invalid Application ID' });
        }

        // Double check status before processing
        if (application.overallStatus !== APPLICATION_STATUS.QUESTIONNAIRE_PENDING) {
            return res.status(400).json({ success: false, message: 'Questionnaire already submitted' });
        }

        const questionnaire = await Questionnaire.findOne({ where: { isActive: true } });
        if (!questionnaire) return res.status(400).json({ success: false, message: 'No active questionnaire' });

        // Calculate Score
        let totalScore = 0;
        const responseRecords = await Promise.all(responses.map(async (r: any) => {
            const question = await QuestionnaireQuestion.findByPk(r.questionId);
            let score = 0;

            if (question) {
                // If question has options (via new table), find score
                const option = await QuestionnaireOption.findOne({
                    where: {
                        questionId: question.id,
                        optionText: r.value
                    }
                });

                if (option) {
                    score = option.score || 0;
                }
            }

            totalScore += score;

            return {
                applicationId: application.id, // Use UUID from database
                questionnaireId: questionnaire.id,
                questionId: r.questionId,
                responseValue: r.value,
                attachmentUrl: r.attachmentUrl || null,
                score: score // Store individual answer score if needed (requires schema update for QuestionnaireResponse)
            };
        }));

        await QuestionnaireResponse.bulkCreate(responseRecords);

        // Update Application Status & Score
        const previousStatus = application.overallStatus;
        const newStatus = APPLICATION_STATUS.QUESTIONNAIRE_COMPLETED;

        await application.update({
            overallStatus: newStatus,
            score: totalScore,
            updatedAt: new Date()
        });

        // Log Status History
        await ApplicationStatusHistory.create({
            applicationId: application.id,
            previousStatus,
            newStatus,
            reason: 'Public Questionnaire Submitted',
            changedBy: null // System action / Public user
        });

        try {
            const location =
                (application as any).preferredLocation ||
                (application as any).city ||
                'your preferred location';
            await sendQuestionnaireAckEmail(
                application.email,
                application.applicantName || 'Applicant',
                location,
                application.applicationId || application.id
            );
        } catch (mailErr) {
            console.error('[submitPublicResponse] acknowledgement email:', mailErr);
        }

        await logSystemAudit(req, {
            actorName: application.applicantName || 'Public Applicant',
            actorRole: 'Prospective Dealer',
            module: SYSTEM_AUDIT_MODULES.QUESTIONNAIRE,
            entityType: 'questionnaire_response',
            entityId: application.id,
            entityLabel: `Application ${application.applicationId || application.id} · ${application.applicantName || 'Applicant'}`,
            action: SYSTEM_AUDIT_ACTIONS.SUBMITTED,
            description: `Public questionnaire submitted; status ${previousStatus} → ${newStatus}; total score ${totalScore}`,
            oldData: { overallStatus: previousStatus },
            newData: { overallStatus: newStatus, score: totalScore },
            metadata: {
                questionnaireId: questionnaire.id,
                applicationId: application.id,
                responseCount: responses.length
            }
        });

        res.json({ success: true, message: 'Responses submitted successfully' });
    } catch (error) {
        console.error('Submit public response error:', error);
        res.status(500).json({ success: false, message: 'Error submitting responses' });
    }
};
