import { Op } from 'sequelize';
import { DomainManagement } from '../models/index.js';
import {
    sendDomainRenewalAlerts,
    sendDomainRenewalAlertToUser
} from '../services/domainRenewalAlertService.js';
import sanitizeHtml from 'sanitize-html';
import {
    allowedStatuses,
    parseBoolean,
    formatDomain,
    handleDomainError
} from "../utils/domainHelpers.js";

import { todayOnly, addDays } from "../utils/dateHelpers.js";



export const createDomain = async (req, res) => {
    try {
        const {
            domain_name,
            client_name,
            client_email,
            registrar,
            expiry_date,
            status,
            auto_renew,
            ssl_enabled,
            ssl_expiry_date,
            last_renewed_at,
            cost

        } = req.body;

        if (!domain_name || !client_name || !client_email || !registrar || !expiry_date) {
            return res.status(400).json({
                success: false,
                message: 'Domain name, client name, client email, registrar and expiry date are required'
            });
        }

        if (status && !allowedStatuses.includes(status)) {
            return res.status(400).json({
                success: false,
                message: `Status must be one of: ${allowedStatuses.join(', ')}`
            });
        }

        const existingDomain = await DomainManagement.findOne({
            where: { domain_name: domain_name.trim().toLowerCase() }
        });

        if (existingDomain) {
            return res.status(409).json({
                success: false,
                message: 'Domain name already exists'
            });
        }

        const domain = await DomainManagement.create({
            domain_name,
            client_name,
            client_email,
            registrar,
            expiry_date,
            status: status || 'active',
            auto_renew: parseBoolean(auto_renew) || false,
            ssl_enabled: ssl_enabled === undefined ? true : parseBoolean(ssl_enabled),
            ssl_expiry_date,
            last_renewed_at,
            cost
        });

        return res.status(201).json({
            success: true,
            message: 'Domain created successfully',
            domain: formatDomain(domain)
        });
    } catch (error) {
        return handleDomainError(res, error);
    }
};

export const getDomains = async (req, res) => {
    try {
        const { search, status, registrar, auto_renew } = req.query;
        const where = {};

        if (status && status !== 'all') {
            where.status = status;
        }

        if (registrar) {
            where.registrar = registrar;
        }

        if (auto_renew !== undefined) {
            where.auto_renew = parseBoolean(auto_renew);
        }

        if (search) {
            where[Op.or] = [
                { domain_name: { [Op.like]: `%${search}%` } },
                { client_name: { [Op.like]: `%${search}%` } },
                { client_email: { [Op.like]: `%${search}%` } },
                {cost : { [Op.like]: `%${search}%` } },
                { registrar: { [Op.like]: `%${search}%` } }
            ];
        }

        const domains = await DomainManagement.findAll({
            where,
            order: [['expiry_date', 'ASC']]
        });

        return res.status(200).json({
            success: true,
            total: domains.length,
            domains: domains.map(formatDomain)
        });
    } catch (error) {
        return handleDomainError(res, error);
    }
};

export const getDomainById = async (req, res) => {
    try {
        const { id } = req.params;
        const domain = await DomainManagement.findByPk(id);

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

        return res.status(200).json({
            success: true,
            domain: formatDomain(domain)
        });
    } catch (error) {
        return handleDomainError(res, error);
    }
};

export const updateDomain = async (req, res) => {
    try {
        const { id } = req.params;

        const domain = await DomainManagement.findByPk(id);

        if (!domain) {
            return res.status(404).json({
                success: false,
                message: "Domain not found"
            });
        }
        if (req.body.status && !allowedStatuses.includes(req.body.status)) {
            return res.status(400).json({
                success: false,
                message: `Status must be one of: ${allowedStatuses.join(", ")}`
            });
        }

  const allowedFields = [
    "domain_name",
    "client_name",
    "registrar",
    "client_email",
    "expiry_date",
    "status",
    "auto_renew",
    "ssl_enabled",
    "ssl_expiry_date",
    "last_renewed_at",
    "cost"
];

        const updateData = {};

        for (let key of allowedFields) {
            if (req.body[key] !== undefined) {
                updateData[key] = req.body[key];
            }
        }

        if (updateData.auto_renew !== undefined) {
            updateData.auto_renew = parseBoolean(updateData.auto_renew);
        }

        if (updateData.ssl_enabled !== undefined) {
            updateData.ssl_enabled = parseBoolean(updateData.ssl_enabled);
        }

        if (updateData.status === "active") {
            updateData.last_renewed_at = todayOnly();
        }

        await domain.update(updateData);

        return res.status(200).json({
            success: true,
            message: "Domain updated successfully",
            domain: formatDomain(domain)
        });

    } catch (error) {
        return handleDomainError(res, error);
    }
};

export const deleteDomain = async (req, res) => {
    try {
        const { id } = req.params;
        const domain = await DomainManagement.findByPk(id);

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

        await domain.destroy();

        return res.status(200).json({
            success: true,
            message: 'Domain deleted successfully'
        });
    } catch (error) {
        return handleDomainError(res, error);
    }
};

export const toggleAutoRenew = async (req, res) => {
    try {
        const { id } = req.params;
        const domain = await DomainManagement.findByPk(id);

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

        await domain.update({
            auto_renew: !domain.auto_renew
        });

        return res.status(200).json({
            success: true,
            message: 'Auto renew updated successfully',
            domain: formatDomain(domain)
        });
    } catch (error) {
        return handleDomainError(res, error);
    }
};

export const renewDomain = async (req, res) => {
    try {
        const { id } = req.params;
        const { expiry_date } = req.body;
        const domain = await DomainManagement.findByPk(id);

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

        if (!expiry_date) {
            return res.status(400).json({
                success: false,
                message: 'New expiry date is required'
            });
        }

        await domain.update({
            expiry_date,
            status: 'renewed',
            last_renewed_at: new Date()
        });

        return res.status(200).json({
            success: true,
            message: 'Domain renewed successfully',
            domain: formatDomain(domain)
        });
    } catch (error) {
        return handleDomainError(res, error);
    }
};

export const getDomainStats = async (req, res) => {
    try {
        const today = todayOnly();
        const nextThirtyDays = addDays(today, 30);

        const [
            totalDomains,
            activeDomains,
            expiringSoon,
            renewedDomains,
            sslEnabled,
            autoRenewEnabled
        ] = await Promise.all([
            DomainManagement.count(),
            DomainManagement.count({ where: { status: 'active' } }),
            DomainManagement.count({
                where: {
                    expiry_date: {
                        [Op.between]: [today, nextThirtyDays]
                    }
                }
            }),
            DomainManagement.count({ where: { status: 'renewed' } }),
            DomainManagement.count({ where: { ssl_enabled: true } }),
            DomainManagement.count({ where: { auto_renew: true } })
        ]);

        return res.status(200).json({
            success: true,
            stats: {
                totalDomains,
                activeDomains,
                expiringSoon,
                renewedDomains,
                sslCoverage: totalDomains ? Math.round((sslEnabled / totalDomains) * 100) : 0,
                autoRenewEnabled: totalDomains ? Math.round((autoRenewEnabled / totalDomains) * 100) : 0
            }
        });
    } catch (error) {
        return handleDomainError(res, error);
    }
};

export const getExpiryAlerts = async (req, res) => {
    try {
        const days = Number(req.query.days || 7);

        const today = new Date();
        today.setHours(0, 0, 0, 0);

        const alertEndDate = new Date();
        alertEndDate.setDate(alertEndDate.getDate() + days);
        alertEndDate.setHours(23, 59, 59, 999);

        const domains = await DomainManagement.findAll({
            where: {
                expiry_date: {
                    [Op.between]: [today, alertEndDate]
                }
            },
            order: [['expiry_date', 'ASC']]
        });

        return res.status(200).json({
            success: true,
            total: domains.length,
            alerts: domains.map(formatDomain)
        });

    } catch (error) {
        console.log(error); //  MUST ADD FOR DEBUG
        return handleDomainError(res, error);
    }
};
export const getRenewalActivity = async (req, res) => {
    try {
        const domains = await DomainManagement.findAll({
            where: {
                last_renewed_at: {
                    [Op.ne]: null
                }
            },
            order: [['last_renewed_at', 'DESC']],
            limit: 10
        });

        return res.status(200).json({
            success: true,
            total: domains.length,
            activity: domains.map(formatDomain)
        });
    } catch (error) {
        return handleDomainError(res, error);
    }
};

export const sendRenewalAlertEmails = async (req, res) => {
    try {
        const result = await sendDomainRenewalAlerts();

        return res.status(200).json({
            success: true,
            ...result
        });
    } catch (error) {
        return handleDomainError(res, error);
    }
};

export const sendRenewalAlertEmailToUser = async (req, res) => {
    try {
        const { id } = req.params;
        const { cost: bodyCost, custom_cost, customMessageHtml } = req.body;
        const domain = await DomainManagement.findByPk(id);

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

        const requestedCost = bodyCost ?? custom_cost;
        const parsedCost = requestedCost === undefined || requestedCost === null || requestedCost === ''
            ? null
            : Number(requestedCost);

        if (parsedCost !== null && (!Number.isFinite(parsedCost) || parsedCost < 0)) {
            return res.status(400).json({
                success: false,
                message: 'Invalid cost value'
            });
        }

        const sanitizedHtml = customMessageHtml
            ? sanitizeHtml(customMessageHtml, {
                allowedTags: sanitizeHtml.defaults.allowedTags.concat([
                    'img',
                    'table',
                    'thead',
                    'tbody',
                    'tr',
                    'td',
                    'th',
                    'h1',
                    'h2',
                    'span'
                ]),
                allowedAttributes: {
                    ...sanitizeHtml.defaults.allowedAttributes,
                    '*': ['style', 'class'],
                    a: ['href', 'target', 'rel'],
                    img: ['src', 'alt', 'width', 'height']
                },
                allowedSchemes: ['http', 'https', 'mailto'],
                allowedStyles: {
                    '*': {
                        color: [/^.*$/],
                        'background-color': [/^.*$/],
                        background: [/^.*$/],
                        'text-align': [/^.*$/],
                        'font-size': [/^.*$/],
                        'font-weight': [/^.*$/],
                        'font-family': [/^.*$/],
                        padding: [/^.*$/],
                        margin: [/^.*$/],
                        border: [/^.*$/],
                        'border-bottom': [/^.*$/],
                        'border-radius': [/^.*$/],
                        'border-collapse': [/^.*$/],
                        width: [/^.*$/],
                        'max-width': [/^.*$/],
                        overflow: [/^.*$/],
                        'line-height': [/^.*$/]
                    }
                }
            })
            : null;

        const result = await sendDomainRenewalAlertToUser(domain, parsedCost, sanitizedHtml);

        return res.status(200).json({
            success: result.sent,
            ...result
        });
    } catch (error) {
        return handleDomainError(res, error);
    }
};


// export const getClientList = async (req, res) => {
//     try {
//         const clients = await DomainManagement.findAll({
//             attributes: ['client', 'email','domain_name'],
//             order: [['created_at', 'DESC']],
//         });

//         const clientList = clients.map(client => client.client);

//         return res.status(200).json({
//             success: true,
//             clients: clientList
//         });
//     } catch (error) {
//         return handleDomainError(res, error);
//     }
// };

export const getClientLists = async (req, res) => {
    try {
        const clients = await DomainManagement.findAll({
            attributes: ['client_name', 'client_email', 'domain_name'],
            order: [['created_at', 'DESC']],
        });

     
        const clientGroupMap = {};

        clients.forEach(row => {
            const name = row.client_name;
            if (!name) return;

            if (!clientGroupMap[name]) {
                clientGroupMap[name] = {
                    name: name,
                    email: row.client_email || '',
                    domains: []
                };
            }

    
            if (row.domain_name && !clientGroupMap[name].domains.includes(row.domain_name)) {
                clientGroupMap[name].domains.push(row.domain_name);
            }
        });

        const dynamicClientList = Object.values(clientGroupMap);

        return res.status(200).json({
            success: true,
            clients: dynamicClientList
        });
    } catch (error) {
        return handleDomainError(res, error);
    }
};