const { Client, ContactPerson } = require('../models/client');
const { User, Role } = require('../models/foundation');
const { logAction } = require('../utils/logger');
const { generateSecurePassword } = require('../utils/passwordGenerator');
const { sendWelcomeEmail } = require('../services/notificationService');
const { sequelize } = require('../config/db');
const bcrypt = require('bcryptjs');

exports.getAllClients = async () => {
    return await Client.findAll({
        where: { isActive: true },
        include: [{ model: ContactPerson, as: 'contactPersons' }],
        order: [['name', 'ASC']]
    });
};

exports.getClientById = async (id) => {
    return await Client.findByPk(id, {
        include: [{ model: ContactPerson, as: 'contactPersons' }]
    });
};

exports.createClient = async (data, userId) => {
    const transaction = await sequelize.transaction();
    try {
        // 1. Validate Email and Phone (Required for portal creation)
        if (!data.email || !data.phone) {
            throw new Error('Both Email and Phone are required for Client creation to ensure portal access.');
        }

        // 2. Check if email already exists in User table
        const existingUser = await User.findOne({ where: { email: data.email } });
        if (existingUser) {
            throw new Error('A user with this email already exists in the system.');
        }

        // 3. Generate Customer Number (if not provided)
        if (!data.customerNumber) {
            const initials = (data.companyName || data.name || 'CUST')
                .split(' ')
                .map(w => w[0])
                .join('')
                .toUpperCase()
                .substring(0, 3);

            const count = await Client.count();
            data.customerNumber = `${initials}-CUS-${(count + 1).toString().padStart(4, '0')}`;
        }

        // 4. Create Client Record
        const client = await Client.create(data, { transaction });

        // 5. Handle Contact Persons
        if (data.contactPersons && Array.isArray(data.contactPersons)) {
            const contacts = data.contactPersons.map(cp => ({ ...cp, clientId: client.id }));
            await ContactPerson.bulkCreate(contacts, { transaction });
        }

        let plainPassword = null;

        // 6. Create Portal User (Default is true based on requirements)
        if (data.portalAccess === true || data.portalAccess === 'true' || data.portalAccess === undefined) {
            const customPassword = data.customPassword ? String(data.customPassword).trim() : null;
            plainPassword = customPassword || generateSecurePassword();
            const hashedPassword = await bcrypt.hash(plainPassword, 10);

            let clientRole = await Role.findOne({ where: { constant: 'CLIENT' } });
            if (!clientRole) {
                clientRole = await Role.create({ name: 'Client Portal User', constant: 'CLIENT' }, { transaction });
            }

            const user = await User.create({
                fullName: client.name,
                email: client.email,
                phone: client.phone,
                password: hashedPassword,
                roleId: clientRole.id,
                isActive: true,
                mustChangePassword: true,
                clientId: client.id
            }, { transaction });

            // 7. Send Welcome Email IF requested
            if (data.sendLoginDetails === true || data.sendLoginDetails === 'true') {
                try {
                    await sendWelcomeEmail(user, plainPassword);
                    await user.update({ credentialsSent: true }, { transaction });
                } catch (emailErr) {
                    console.error('Failed to send welcome email:', emailErr);
                }
            }
        }

        await transaction.commit();
        await logAction(userId, 'CREATE', 'CLIENT', { id: client.id, name: client.name }, null);
        return { ...client.toJSON(), generatedPassword: plainPassword };
    } catch (err) {
        await transaction.rollback();
        throw err;
    }
};

exports.updateClient = async (id, data, userId) => {
    const transaction = await sequelize.transaction();
    try {
        const client = await Client.findByPk(id);
        if (!client) throw new Error('Client not found');

        const oldEmail = client.email;
        await client.update(data, { transaction });

        // Handle Contact Persons (Sync)
        if (data.contactPersons && Array.isArray(data.contactPersons)) {
            await ContactPerson.destroy({ where: { clientId: id }, transaction });
            const contacts = data.contactPersons.map(cp => ({ ...cp, clientId: id }));
            await ContactPerson.bulkCreate(contacts, { transaction });
        }

        // --- Handle Portal Access Synchronization ---
        const portalUser = await User.findOne({ where: { clientId: id } });

        if (data.portalAccess === true || data.portalAccess === 'true') {
            if (!portalUser) {
                // Create user if it doesn't exist
                const plainPassword = data.customPassword || generateSecurePassword();
                const hashedPassword = await bcrypt.hash(plainPassword, 10);

                let clientRole = await Role.findOne({ where: { constant: 'CLIENT' } });
                if (!clientRole) {
                    clientRole = await Role.create({ name: 'Client Portal User', constant: 'CLIENT' }, { transaction });
                }

                const newUser = await User.create({
                    fullName: client.name,
                    email: client.email,
                    phone: client.phone,
                    password: hashedPassword,
                    roleId: clientRole.id,
                    isActive: true,
                    mustChangePassword: true,
                    clientId: client.id
                }, { transaction });

                if (data.sendLoginDetails === true || data.sendLoginDetails === 'true') {
                    await sendWelcomeEmail(newUser, plainPassword);
                    await newUser.update({ credentialsSent: true }, { transaction });
                }
            } else {
                // Sync user info and ensure active
                await portalUser.update({
                    fullName: client.name,
                    email: client.email,
                    phone: client.phone,
                    isActive: true
                }, { transaction });
            }
        } else if (data.portalAccess === false || data.portalAccess === 'false') {
            if (portalUser) {
                // Deactivate portal user
                await portalUser.update({ isActive: false }, { transaction });
            }
        }

        await transaction.commit();
        await logAction(userId, 'UPDATE', 'CLIENT', { id: client.id }, null);
        return client;
    } catch (err) {
        await transaction.rollback();
        throw err;
    }
};

exports.deleteClient = async (id, userId) => {
    const client = await Client.findByPk(id);
    if (!client) throw new Error('Client not found');

    // Soft delete client
    client.isActive = false;
    await client.save();

    // Deactivate associated portal user
    const portalUser = await User.findOne({ where: { clientId: id } });
    if (portalUser) {
        portalUser.isActive = false;
        await portalUser.save();
    }

    await logAction(userId, 'DELETE', 'CLIENT', { id: client.id }, null);
};
