using Microsoft.Extensions.Logging;
using PowderCoating.Application.Interfaces;
using PowderCoating.Core.Entities;

namespace PowderCoating.Infrastructure.Services;

/// <summary>
/// Platform-level email notification service that alerts SuperAdmin recipients about
/// key lifecycle events: new company registrations, bug reports, subscription expirations,
/// and grace-period transitions.
/// </summary>
/// <remarks>
/// Admin email addresses are read from the <c>AdminNotificationEmail</c> platform setting
/// (a comma-separated list).  If that setting is absent or empty, all notification methods
/// silently no-op rather than throwing, so a mis-configured setting never breaks the
/// action that triggered the notification.
///
/// This service sends platform-level alerts only — it does NOT send company-facing
/// emails (invoices, quote approvals, etc.), which are handled by <c>IEmailService</c>
/// directly from the relevant controllers.
/// </remarks>
public class AdminNotificationService : IAdminNotificationService
{
    private readonly IEmailService _emailService;
    private readonly IPlatformSettingsService _platformSettings;
    private readonly ILogger<AdminNotificationService> _logger;

    public AdminNotificationService(
        IEmailService emailService,
        IPlatformSettingsService platformSettings,
        ILogger<AdminNotificationService> logger)
    {
        _emailService = emailService;
        _platformSettings = platformSettings;
        _logger = logger;
    }

    /// <summary>
    /// Sends an email notification to all configured SuperAdmin addresses when a new tenant
    /// company completes registration, including company ID, plan name, and primary contact.
    /// </summary>
    /// <param name="companyId">Database ID of the newly created company.</param>
    /// <param name="companyName">Display name of the new company.</param>
    /// <param name="planName">Subscription plan the company signed up for.</param>
    /// <param name="contactName">Full name of the registration contact.</param>
    /// <param name="contactEmail">Email address of the registration contact.</param>
    public async Task NotifyNewCompanyRegisteredAsync(
        int companyId, string companyName, string planName,
        string contactName, string contactEmail)
    {
        var adminEmails = await GetAdminEmailsAsync();
        if (adminEmails == null) return;

        var subject = $"[New Signup] {companyName}";

        var html = $"""
            <h2>New Company Registered</h2>
            <table cellpadding="6" style="border-collapse:collapse;">
                <tr><td><strong>Company:</strong></td><td>{Encode(companyName)} (ID: {companyId})</td></tr>
                <tr><td><strong>Plan:</strong></td><td>{Encode(planName)}</td></tr>
                <tr><td><strong>Contact Name:</strong></td><td>{Encode(contactName)}</td></tr>
                <tr><td><strong>Contact Email:</strong></td><td>{Encode(contactEmail)}</td></tr>
                <tr><td><strong>Registered:</strong></td><td>{DateTime.UtcNow:MM/dd/yyyy h:mm tt} UTC</td></tr>
            </table>
            """;

        var plain = $"New Company Registered\n\n" +
                    $"Company: {companyName} (ID: {companyId})\n" +
                    $"Plan: {planName}\n" +
                    $"Contact: {contactName} <{contactEmail}>\n" +
                    $"Registered: {DateTime.UtcNow:MM/dd/yyyy h:mm tt} UTC";

        await SendAsync(adminEmails, subject, plain, html);
    }

    /// <summary>
    /// Sends an email notification to all configured SuperAdmin addresses when a user submits
    /// a bug report, including the report ID, title, priority, submitting user, and full
    /// description body so admins can triage without logging in.
    /// </summary>
    /// <param name="bugReportId">Database ID of the new bug report.</param>
    /// <param name="title">Short title of the bug report.</param>
    /// <param name="description">Full description text entered by the user.</param>
    /// <param name="priority">Priority label (e.g. Low, Medium, High, Critical).</param>
    /// <param name="submittedByName">Display name of the user who submitted the report.</param>
    /// <param name="companyName">Name of the company the submitting user belongs to.</param>
    public async Task NotifyBugReportSubmittedAsync(
        int bugReportId, string title, string description,
        string priority, string submittedByName, string companyName)
    {
        var adminEmails = await GetAdminEmailsAsync();
        if (adminEmails == null) return;

        var subject = $"[Bug Report] {title}";

        var html = $"""
            <h2>New Bug Report Submitted</h2>
            <table cellpadding="6" style="border-collapse:collapse;">
                <tr><td><strong>Report #:</strong></td><td>{bugReportId}</td></tr>
                <tr><td><strong>Title:</strong></td><td>{Encode(title)}</td></tr>
                <tr><td><strong>Priority:</strong></td><td>{Encode(priority)}</td></tr>
                <tr><td><strong>Submitted By:</strong></td><td>{Encode(submittedByName)}</td></tr>
                <tr><td><strong>Company:</strong></td><td>{Encode(companyName)}</td></tr>
                <tr><td><strong>Submitted:</strong></td><td>{DateTime.UtcNow:MM/dd/yyyy h:mm tt} UTC</td></tr>
            </table>
            <h3>Description</h3>
            <p style="white-space:pre-wrap;">{Encode(description)}</p>
            """;

        var plain = $"New Bug Report #{bugReportId}\n\n" +
                    $"Title: {title}\n" +
                    $"Priority: {priority}\n" +
                    $"Submitted By: {submittedByName}\n" +
                    $"Company: {companyName}\n" +
                    $"Submitted: {DateTime.UtcNow:MM/dd/yyyy h:mm tt} UTC\n\n" +
                    $"Description:\n{description}";

        await SendAsync(adminEmails, subject, plain, html);
    }

    /// <summary>
    /// Sends an email notification to all configured SuperAdmin addresses when a company's
    /// subscription has expired and its account has been deactivated.
    /// </summary>
    /// <param name="companyId">Database ID of the expired company.</param>
    /// <param name="companyName">Display name of the company.</param>
    /// <param name="contactEmail">Primary contact email for the company.</param>
    /// <param name="expiredOn">The UTC date on which the subscription expired.</param>
    public async Task NotifyCompanyExpiredAsync(
        int companyId, string companyName, string contactEmail, DateTime expiredOn)
    {
        var adminEmails = await GetAdminEmailsAsync();
        if (adminEmails == null) return;

        var subject = $"[Subscription Expired] {companyName}";

        var html = $"""
            <h2>Company Subscription Expired</h2>
            <table cellpadding="6" style="border-collapse:collapse;">
                <tr><td><strong>Company:</strong></td><td>{Encode(companyName)} (ID: {companyId})</td></tr>
                <tr><td><strong>Contact Email:</strong></td><td>{Encode(contactEmail)}</td></tr>
                <tr><td><strong>Expired On:</strong></td><td>{expiredOn:MMMM d, yyyy}</td></tr>
            </table>
            <p>This company has been deactivated and is no longer able to log in.</p>
            """;

        var plain = $"Company Subscription Expired\n\n" +
                    $"Company: {companyName} (ID: {companyId})\n" +
                    $"Contact Email: {contactEmail}\n" +
                    $"Expired On: {expiredOn:MMMM d, yyyy}\n\n" +
                    $"This company has been deactivated.";

        await SendAsync(adminEmails, subject, plain, html);
    }

    /// <summary>
    /// Sends an email notification to all configured SuperAdmin addresses when a company
    /// enters a subscription grace period, including the grace-period end date so admins
    /// know when the account will auto-deactivate if not renewed.
    /// </summary>
    /// <param name="companyId">Database ID of the company entering grace period.</param>
    /// <param name="companyName">Display name of the company.</param>
    /// <param name="contactEmail">Primary contact email for the company.</param>
    /// <param name="gracePeriodEndsOn">UTC date on which the grace period expires.</param>
    public async Task NotifyCompanyGracePeriodAsync(
        int companyId, string companyName, string contactEmail, DateTime gracePeriodEndsOn)
    {
        var adminEmails = await GetAdminEmailsAsync();
        if (adminEmails == null) return;

        var subject = $"[Grace Period Started] {companyName}";

        var html = $"""
            <h2>Company Entered Grace Period</h2>
            <table cellpadding="6" style="border-collapse:collapse;">
                <tr><td><strong>Company:</strong></td><td>{Encode(companyName)} (ID: {companyId})</td></tr>
                <tr><td><strong>Contact Email:</strong></td><td>{Encode(contactEmail)}</td></tr>
                <tr><td><strong>Grace Period Ends:</strong></td><td>{gracePeriodEndsOn:MMMM d, yyyy}</td></tr>
            </table>
            <p>If not renewed by the grace period end date, this company will be automatically deactivated.</p>
            """;

        var plain = $"Company Entered Grace Period\n\n" +
                    $"Company: {companyName} (ID: {companyId})\n" +
                    $"Contact Email: {contactEmail}\n" +
                    $"Grace Period Ends: {gracePeriodEndsOn:MMMM d, yyyy}\n\n" +
                    $"If not renewed, this company will be automatically deactivated.";

        await SendAsync(adminEmails, subject, plain, html);
    }

    /// <summary>
    /// Sends an email to all configured SuperAdmin addresses when a user submits the
    /// Contact Us form, including the sender's name, email, company, category, subject,
    /// and full message so admins can respond directly from their email client.
    /// </summary>
    public async Task NotifyContactFormSubmittedAsync(
        string senderName, string senderEmail, string companyName,
        string category, string subject, string message)
    {
        var adminEmails = await GetAdminEmailsAsync();
        if (adminEmails == null) return;

        var emailSubject = $"[Contact Us] {category} — {subject}";

        var html = $"""
            <h2>Contact Us Form Submission</h2>
            <table cellpadding="6" style="border-collapse:collapse;">
                <tr><td><strong>Name:</strong></td><td>{Encode(senderName)}</td></tr>
                <tr><td><strong>Email:</strong></td><td><a href="mailto:{Encode(senderEmail)}">{Encode(senderEmail)}</a></td></tr>
                <tr><td><strong>Company:</strong></td><td>{Encode(companyName)}</td></tr>
                <tr><td><strong>Category:</strong></td><td>{Encode(category)}</td></tr>
                <tr><td><strong>Subject:</strong></td><td>{Encode(subject)}</td></tr>
                <tr><td><strong>Submitted:</strong></td><td>{DateTime.UtcNow:MM/dd/yyyy h:mm tt} UTC</td></tr>
            </table>
            <h3>Message</h3>
            <p style="white-space:pre-wrap;">{Encode(message)}</p>
            """;

        var plain = $"Contact Us Form Submission\n\n" +
                    $"Name: {senderName}\n" +
                    $"Email: {senderEmail}\n" +
                    $"Company: {companyName}\n" +
                    $"Category: {category}\n" +
                    $"Subject: {subject}\n" +
                    $"Submitted: {DateTime.UtcNow:MM/dd/yyyy h:mm tt} UTC\n\n" +
                    $"Message:\n{message}";

        await SendAsync(adminEmails, emailSubject, plain, html, replyToEmail: senderEmail, replyToName: senderName);
    }

    // ─── Helpers ─────────────────────────────────────────────────────────────

    /// <summary>
    /// Reads the <c>AdminNotificationEmail</c> platform setting and returns a list of valid
    /// email addresses, or <c>null</c> if the setting is absent, blank, or contains no
    /// parseable addresses.
    /// </summary>
    /// <remarks>
    /// Returning <c>null</c> (rather than an empty list) is intentional: callers use a
    /// null-check early-return pattern (<c>if (adminEmails == null) return;</c>) which is
    /// cleaner than checking <c>Count == 0</c> in each notification method.  A DEBUG-level
    /// log entry is written so that missing configuration is detectable without generating
    /// noise at WARNING or above in normal operation.
    /// </remarks>
    /// <returns>Non-empty list of email strings, or <c>null</c> if none are configured.</returns>
    private async Task<List<string>?> GetAdminEmailsAsync()
    {
        var raw = await _platformSettings.GetAsync(PlatformSettingKeys.AdminNotificationEmail);
        if (string.IsNullOrWhiteSpace(raw))
        {
            _logger.LogDebug("PlatformSetting '{Key}' is not configured — skipping admin notification.",
                PlatformSettingKeys.AdminNotificationEmail);
            return null;
        }

        var emails = raw
            .Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries)
            .Where(e => e.Contains('@'))
            .ToList();

        if (emails.Count == 0)
        {
            _logger.LogDebug("PlatformSetting '{Key}' contained no valid addresses — skipping.",
                PlatformSettingKeys.AdminNotificationEmail);
            return null;
        }

        return emails;
    }

    /// <summary>
    /// Sends the notification email to each address in <paramref name="adminEmails"/> via
    /// <see cref="IEmailService"/>, logging a warning for any individual send failure without
    /// re-throwing so that a bad address does not prevent delivery to the remaining recipients.
    /// </summary>
    /// <param name="adminEmails">Validated list of recipient email addresses.</param>
    /// <param name="subject">Email subject line.</param>
    /// <param name="plain">Plain-text fallback body.</param>
    /// <param name="html">HTML-formatted body shown by modern email clients.</param>
    private async Task SendAsync(List<string> adminEmails, string subject, string plain, string html,
        string? replyToEmail = null, string? replyToName = null)
    {
        foreach (var email in adminEmails)
        {
            var (success, error) = await _emailService.SendEmailAsync(
                toEmail: email,
                toName: "PCL Admin",
                subject: subject,
                plainTextBody: plain,
                htmlBody: html,
                replyToEmail: replyToEmail,
                replyToName: replyToName);

            if (!success)
                _logger.LogWarning("Admin notification email failed for {Email} ({Subject}): {Error}", email, subject, error);
            else
                _logger.LogInformation("Admin notification sent to {Email}: {Subject}", email, subject);
        }
    }

    /// <summary>
    /// HTML-encodes a string for safe embedding in email HTML bodies, guarding against
    /// XSS if user-supplied values (company names, titles, descriptions) contain angle
    /// brackets or other special characters.  Null input is treated as empty string.
    /// </summary>
    private static string Encode(string? value) =>
        System.Net.WebUtility.HtmlEncode(value ?? string.Empty);
}
