const { KycSubmission, KycDocument, User, sequelize } = require('../../models')
const storage = require('../../config/context');
const { getUploadedFile } = require('../../utils/helpers');
const mapKycStatus = {
    pending: "Pending Review",
    approved: "Approved",
    rejected: "Rejected"
};

const mapDocumentType = {
    id_card: "ID Card",
    passport: "Passport",
    driver_license: "Driver's License"
};

const mapSubmissionType = {
    basic_info: 'Basic Information',
    phone: 'Phone Number',
    id_document: 'Identity Verification',
    selfie: 'Selfie',
    address_proof: 'Address Proof',
    source_of_funds: 'Source of Funds',
    enhanced_due_diligence: 'Enhanced Due Diligence'
}



class kycService {

    determineKycLevel(user, submissions = []) {
        const approvedSteps = new Set(
            submissions
                .filter((item) => item.status === 'approved')
                .map((item) => item.step)
        );

        const hasEmail = !!user.emailVerified;
        const hasIdentity = approvedSteps.has('id_document') || approvedSteps.has('selfie');
        const hasAddress = approvedSteps.has('address_proof');
        const hasEnhanced =
            approvedSteps.has('source_of_funds') || approvedSteps.has('enhanced_due_diligence');

        if (hasEmail && hasIdentity && hasAddress && hasEnhanced) {
            return 'level4';
        }

        if (hasEmail && hasIdentity && hasAddress) {
            return 'level3';
        }

        if (hasEmail && hasIdentity) {
            return 'level2';
        }

        if (hasEmail) {
            return 'level1';
        }

        return 'none';
    }

    async getKycRequests(query) {
        const { page = 1, limit = 20, status } = query;
        const offset = (page - 1) * limit;
        const where = {};

        if (status) {
            where.status = status;
        }
        const { count, rows } = await KycSubmission.findAndCountAll({
            where,
            include: [{ model: KycDocument, as: 'documents' }, { model: User, as: 'user', attributes: ['id', 'email'] }],
            order: [['createdAt', 'DESC']],
            limit: parseInt(limit),
            offset: parseInt(offset),
        });

        return {
            total: count,
            page: parseInt(page),
            limit: parseInt(limit),
            requests: rows.map(submission => ({
                id: submission.id,
                userId: submission.userId,
                userEmail: submission.user?.email,
                step: mapSubmissionType[submission.step],
                status: mapKycStatus[submission.status],
                documents: submission.documents.map(doc => ({
                    id: doc.id,
                    type: doc.document_type,
                    documentUrl: getUploadedFile(doc.fileUrl, 'kyc'),
                    status: mapKycStatus[doc.status]
                }))
            }))
        };
    }

    async updateKycStatus(kycId, status, reason, adminId) {
        const validStatuses = ['pending', 'approved', 'rejected'];

        if (!validStatuses.includes(status)) {
            throw new Error("Invalid status value");
        }

        return await sequelize.transaction(async (t) => {

            const kycDoc = await KycSubmission.findByPk(kycId, {
                include: [{ model: KycDocument, as: 'documents' }],
                transaction: t,
                lock: t.LOCK.UPDATE // prevents race conditions
            });

            if (!kycDoc) {
                throw new Error("KYC document not found");
            }

            const user = await User.findByPk(kycDoc?.userId);
            if (!user) {
                throw new Error("User not found");
            }

            try {
                const now = new Date();

                // Update all documents
                for (const doc of kycDoc.documents) {
                    doc.status = status;
                    doc.reviewedAt = now;
                    doc.reviewedBy = adminId;
                    doc.reviewNote = reason || null;
                    await doc.save({ transaction: t });
                }

                // Update parent KYC
                kycDoc.status = status;
                kycDoc.reviewedAt = now;
                kycDoc.reviewedBy = adminId;
                kycDoc.reviewNote = reason || null;

                await kycDoc.save({ transaction: t });

                const submissions = await KycSubmission.findAll({
                    where: { userId: user?.id },
                    transaction: t,
                 });

                const nextLevel = this.determineKycLevel(user, submissions);
                await user.update({
                    kycLevel: nextLevel
                },{
                    transaction: t
                })

                return kycDoc;

            } catch (e) {
                console.error("Error updating KYC status:", e);
                throw new Error("Failed to update KYC status");
            }


        });
    }

    async getKycDetails(kycId) {
        const kycDoc = await KycDocument.findByPk(kycId, { include: [{ model: KycSubmission, as: 'submission' }, { model: User, as: 'user', attributes: ['id', 'email'] }] });
        if (!kycDoc) {
            throw new Error("KYC document not found");
        }
        return kycDoc;
    }
}

module.exports = new kycService();
