import { Job } from "agenda";
import Models from "../api/models";
import { Op } from "sequelize";
import { PAYMENT } from "../api/config/constants";
import { EmailTemplateService } from "../api/services/emailTemplate.service";
import { NotificationLogService } from "../api/services/notificationLog.service";

const ensureEmailTemplate = async () => {
    const code = "subscription-expiring";
    const existing = await Models.EmailTemplate.findOne({ where: { code } });
    if (!existing) {
        const defaultLanguage = await Models.Language.findOne({ where: { isDefault: true } }) || await Models.Language.findOne();
        const languageId = defaultLanguage ? defaultLanguage.id : 1;
        const emailTemplate = await Models.EmailTemplate.create({
            code,
            replacements: "name,daysLeft,planName",
            status: 1
        });
        await Models.EmailTemplateContent.create({
            emailTemplateId: emailTemplate.id,
            languageId,
            title: "Your subscription is expiring soon",
            subject: "Your plan {{planName}} is expiring soon",
            body: "<p>Dear {{name}},</p><p>Your plan <strong>{{planName}}</strong> is expiring in {{daysLeft}} days. Please pay again to continue using our premium features.</p><p>Thank you!</p>",
            bodyText: "Dear {{name}},\n\nYour plan {{planName}} is expiring in {{daysLeft}} days. Please pay again to continue using our premium features.\n\nThank you!"
        });
    }
};

const ensureNotificationTemplate = async () => {
    const code = "subscription-expiring";
    const existing = await Models.Notification.findOne({ where: { code } });
    if (!existing) {
        const defaultLanguage = await Models.Language.findOne({ where: { isDefault: true } }) || await Models.Language.findOne();
        const languageId = defaultLanguage ? defaultLanguage.id : 1;
        const notification = await Models.Notification.create({
            code,
            replacements: "daysLeft,planName",
            status: 1
        });
        await Models.NotificationContent.create({
            notificationId: notification.id,
            languageId,
            title: "Your subscription is expiring soon",
            body: "Your plan {{planName}} is expiring in {{daysLeft}} days. Click here to renew.",
            bodyText: "Your plan {{planName}} is expiring in {{daysLeft}} days. Click here to renew."
        });
    }
};

export const updateUserPremiumStatusCron = async () => {
    console.log("Running update_user_premium_status cron job...");
    try {
        // --- Expiration Warning for Non-Auto-Renewable (One-Off) Plans ---
        // Find all active subscriptions that are about to expire in <= 3 days (72 hours)
        // and have autoRenew: 0, and haven't had their warning sent yet.
        const threeDaysFromNow = new Date();
        threeDaysFromNow.setDate(threeDaysFromNow.getDate() + 3);

        const expiringSubscriptions = await Models.Subscription.findAll({
            where: {
                status: PAYMENT.SUBSCRIPTION_STATUS.ACTIVE,
                currentPeriodEnd: {
                    [Op.gt]: new Date(),
                    [Op.lte]: threeDaysFromNow
                }
            }
        });

        for (const sub of expiringSubscriptions) {
            const planData = sub.planData as any;
            if (planData && (planData.autoRenew === 0 || planData.autoRenew === false)) {
                if (!planData.expirationWarningSent) {
                    try {
                        const user = await Models.User.findByPk(sub.userId, {
                            include: [{ model: Models.UserProfile, as: 'userProfile' }]
                        });
                        
                        if (user) {
                            const name = user.userProfile?.name || "User";
                            const email = user.email;
                            const planName = planData.name || "Premium Plan";
                            
                            // Calculate days left
                            const msDiff = new Date(sub.currentPeriodEnd).getTime() - new Date().getTime();
                            const daysLeft = Math.max(1, Math.ceil(msDiff / (1000 * 60 * 60 * 24)));

                            // Send Email
                            try {
                                const emailTemplateService = new EmailTemplateService({
                                    userId: sub.userId,
                                    accountId: sub.accountId,
                                    language: "en",
                                    scope: [],
                                    config: null
                                });
                                await ensureEmailTemplate();
                                await emailTemplateService.sendEmailTemplate('subscription-expiring', [email], {
                                    name,
                                    planName,
                                    daysLeft: String(daysLeft)
                                });
                                console.log(`Sent subscription expiration email to ${email}`);
                            } catch (emailErr) {
                                console.error(`Failed to send expiration email to ${email}:`, emailErr);
                            }

                            // Send Notification
                            try {
                                await ensureNotificationTemplate();
                                await NotificationLogService.emitByCode({
                                    userId: sub.userId,
                                    notificationCode: "subscription-expiring",
                                    replacements: {
                                        planName,
                                        daysLeft: String(daysLeft)
                                    }
                                });
                                console.log(`Sent subscription expiration notification to userId ${sub.userId}`);
                            } catch (notifErr) {
                                console.error(`Failed to send expiration notification to userId ${sub.userId}:`, notifErr);
                            }

                            // Mark warning as sent
                            const updatedPlanData = {
                                ...planData,
                                expirationWarningSent: true
                            };
                            await Models.Subscription.update(
                                { planData: updatedPlanData },
                                { where: { id: sub.id } }
                            );
                        }
                    } catch (subErr) {
                        console.error(`Error processing expiration warning for subscription ${sub.id}:`, subErr);
                    }
                }
            }
        }

        // Find all premium users
        const premiumUsers = await Models.UserSetting.findAll({
            where: { isPremium: true },
            attributes: ['userId']
        });

        const userIds = premiumUsers.map((u: any) => u.userId);

        if (userIds.length > 0) {
            // Find all users among these who HAVE an active subscription
            const activeSubscriptions = await Models.Subscription.findAll({
                where: {
                    userId: { [Op.in]: userIds },
                    status: { [Op.in]: [PAYMENT.SUBSCRIPTION_STATUS.ACTIVE, PAYMENT.SUBSCRIPTION_STATUS.CANCELLED] },
                    [Op.or]: [
                        { currentPeriodEnd: { [Op.gt]: new Date() } },
                        { currentPeriodEnd: null }
                    ]
                },
                attributes: ['userId']
            });

            const activeUserIds = new Set(activeSubscriptions.map((s: any) => String(s.userId)));

            // Find users who are premium but DON'T have an active subscription
            const usersToDowngrade = userIds.filter((id: any) => !activeUserIds.has(String(id)));

            if (usersToDowngrade.length > 0) {
                await Models.UserSetting.update(
                    { isPremium: false },
                    { where: { userId: { [Op.in]: usersToDowngrade } } }
                );
                await Models.Subscription.update(
                    { status: PAYMENT.SUBSCRIPTION_STATUS.EXPIRED, autoRenew: 0 },
                    {
                        where: {
                            userId: { [Op.in]: usersToDowngrade }
                        }
                    }
                );
                console.log(`Downgraded ${usersToDowngrade.length} users from premium.`);
            } else {
                console.log("update_user_premium_status cron: No premium users needed downgrading.");
            }
        } else {
            console.log("update_user_premium_status cron: No premium users found.");
        }
        console.log("update_user_premium_status cron job completed successfully.");
    } catch (error) {
        console.error("Error in update_user_premium_status cron:", error);
    }
};

export default (agenda: any) => {
    agenda.define("update_user_premium_status", async (job: Job) => {
        await updateUserPremiumStatusCron();
    });
};
