import { Injectable, OnModuleInit } from '@nestjs/common';
import { ModelsService } from 'src/models/models.service';
import { UserType } from 'src/user/schema/users.schema';
import { PaymentGateway } from 'src/settings/schema/settings.schema';
import * as bcrypt from 'bcrypt';
import { SubscriptionCheckoutType } from 'src/settings/schema/settings.schema';
@Injectable()
export class AdminSeeder implements OnModuleInit {
    constructor(private readonly models: ModelsService) { }

    async onModuleInit() {
        await this.syncUserIndexes();
        await this.migrateAgentFlatten();
        await this.migrateUserActivity();
        await this.seedSuperAdmin();
        await this.seedDefaultSettings();
        await this.seedLanguages();
    }

    // Moves older databases from the plain unique email index to the partial one (agents may have no email).
    async syncUserIndexes() {
        try {
            await this.models.UserModel.syncIndexes();
        } catch (error) {
            console.error('Error syncing user indexes:', error);
        }
    }

    // One-off, idempotent: agents used to keep their fields inside an `agent` sub-document. Move them to top-level
    // fields, turn a legacy region name string into a region record, and rename the old VERIFIED document status.
    async migrateAgentFlatten() {
        try {
            const users = this.models.UserModel.collection;
            const legacy = await users.find({ user_type: 'AGENT', agent: { $type: 'object' } }).toArray();

            for (const user of legacy) {
                const a = (user as any).agent;

                let region_id = a.region_id ?? null;
                const regionName = typeof a.region === 'string' ? a.region.trim() : '';
                if (!region_id && regionName) {
                    let region: any = await this.models.RegionModel.findOne({ name: regionName }).collation({ locale: 'en', strength: 2 });
                    if (!region) region = await this.models.RegionModel.create({ name: regionName });
                    region_id = region._id;
                }

                await users.updateOne({ _id: user._id }, {
                    $set: {
                        agent_no: a.agent_no ?? null,
                        agent_code: a.agent_code ?? null,
                        agent_status: a.status ?? null,
                        region_id,
                        category_ids: a.category_ids ?? [],
                        invited_by: a.invited_by ?? null,
                        invited_at: a.invited_at ?? null,
                        accepted_at: a.accepted_at ?? null,
                        irdai_number: a.irdai_number ?? null,
                        training_hours: a.training_hours ?? null,
                        kyc_documents: (a.documents ?? []).map((d: any) => ({ ...d, status: d.status === 'VERIFIED' ? 'APPROVED' : d.status })),
                        kyc_submitted_at: a.submitted_at ?? null,
                        kyc_reviewed_by: a.reviewed_by ?? null,
                        kyc_reviewed_at: a.reviewed_at ?? null,
                        kyc_reject_reason: a.reject_reason ?? null
                    },
                    $unset: { agent: '' }
                });
            }

            if (legacy.length) console.log(`Flattened ${legacy.length} agent(s) from the nested agent object to top-level fields.`);
        } catch (error) {
            console.error('Error flattening agents:', error);
        }
    }

    // One-off, idempotent: the audit trail used to live in an `activity` array on each user; move it to the activity-logs collection.
    async migrateUserActivity() {
        try {
            const users = this.models.UserModel.collection;
            const legacy = await users.find({ 'activity.0': { $exists: true } }).toArray();

            for (const user of legacy) {
                const logs = ((user as any).activity as any[]).map(a => ({
                    subject_id: user._id,
                    action: a.action,
                    actor_id: a.actor_id ?? null,
                    actor_name: a.actor_name ?? null,
                    meta: a.meta ?? null,
                    created_at: a.created_at ?? +new Date()
                }));
                await this.models.ActivityLogModel.insertMany(logs);
                await users.updateOne({ _id: user._id }, { $unset: { activity: '' } });
            }

            if (legacy.length) console.log(`Moved the activity trail of ${legacy.length} user(s) to the activity-logs collection.`);
        } catch (error) {
            console.error('Error migrating user activity:', error);
        }
    }

    async seedSuperAdmin() {
        try {
            // Check if any super admin exists
            const existingSuperAdmin = await this.models.UserModel.findOne({
                user_type: UserType.SUPER_ADMIN
            });

            if (existingSuperAdmin) {
                console.log('Super admin already exists. Skipping seed.');
                return;
            }

            console.log('Seeding super admin...');

            const email = 'common@yopmail.com';
            const password = 'Admin@#123';

            // Default super admin credentials
            const superAdminData = {
                email,
                password: await bcrypt.hash(password, 10),
                name: 'Super Admin',
                user_type: UserType.SUPER_ADMIN,
                is_email_verified: true,
                is_active: true,
                created_at: +new Date(),
                updated_at: +new Date()
            };

            // Create super admin
            await this.models.UserModel.create(superAdminData);

            console.log('Super admin created successfully!');
            console.log('Email:', superAdminData.email);
            console.log('Password:', password);
            console.log('Please change the password after first login!');
        } catch (error) {
            console.error('Error seeding super admin:', error);
        }
    }

    async seedDefaultSettings() {
        try {
            // Check if settings already exist
            const existingSettings = await this.models.SettingsModel.findOne();

            if (existingSettings) {
                console.log('Default settings already exist. Skipping seed.');
                return;
            }

            console.log('Seeding default settings...');

            const currentTime = +new Date();

            // Default settings data
            const defaultSettings = {
                payment_gateway: PaymentGateway.STRIPE,
                vendor_commission_percentage: 10,
                referral_amount: 50,
                is_instant_referral_reward: false,
                referral_required_orders: 3,
                referral_time_limit_days: 30,
                subscription_checkout_type : SubscriptionCheckoutType.ONE_TIME_CHECKOUT,
                in_app_purchased_enable: false,
                description: 'Default system settings',
                tax: 18,
                currency: 'USD',
                currency_symbol : "$",
                created_at: currentTime,
                updated_at: currentTime
            };

            // Create default settings
            await this.models.SettingsModel.create(defaultSettings);

            console.log('Default settings created successfully!');
            console.log('Payment Gateway:', defaultSettings.payment_gateway);
            console.log('Vendor Commission:', defaultSettings.vendor_commission_percentage + '%');
            console.log('Tax:', defaultSettings.tax + '%');
            console.log('Referral Amount:', defaultSettings.referral_amount);
            console.log('Currency:', defaultSettings.currency);
        } catch (error) {
            console.error('Error seeding default settings:', error);
        }
    }


    async seedLanguages() {
        console.log('Seeding languages...');
        const languages = [
            { name: 'English', code: 'en', direction: 'ltr' , is_default: true },
            { name: 'Hindi', code: 'hi', direction: 'ltr' , is_default: false },
        ];

        const existingLanguages = await this.models.LanguageModel.find();

        if (existingLanguages.length === 0){
            console.log('No languages found. Seeding default languages...');
            const currentTime = +new Date();
    
            const defaultLanguages = languages.map((language) => ({
                ...language,
                created_at: currentTime,
                updated_at: currentTime
            }));
    
            await this.models.LanguageModel.insertMany(defaultLanguages);
    
            console.log('Languages created successfully!');
        }else{
            console.log('Languages already exist. Skipping seed.');
        }

    }
}
