using Microsoft.EntityFrameworkCore;
using ROLAC.API.Data;
using ROLAC.API.DTOs.Settings;
using ROLAC.API.Entities;
using ROLAC.API.Services.Notifications;

namespace ROLAC.API.Services;

public class SettingsService : ISettingsService
{
    private readonly AppDbContext _db;
    private readonly INotificationSettingsService _notificationSettings;

    public SettingsService(AppDbContext db, INotificationSettingsService notificationSettings)
    {
        _db = db;
        _notificationSettings = notificationSettings;
    }

    public async Task<SiteSettingDto> GetSiteAsync()
    {
        var s = await GetOrCreateSiteAsync();
        return new SiteSettingDto
        {
            SiteTitle       = s.SiteTitle,
            SiteTitleZh     = s.SiteTitleZh,
            DefaultLanguage = s.DefaultLanguage,
            TimeZone        = s.TimeZone,
            DateFormat      = s.DateFormat,
            Currency        = s.Currency,
        };
    }

    public async Task UpdateSiteAsync(UpdateSiteSettingRequest r)
    {
        var s = await GetOrCreateSiteAsync();
        s.SiteTitle       = r.SiteTitle;
        s.SiteTitleZh     = r.SiteTitleZh;
        s.DefaultLanguage = r.DefaultLanguage;
        s.TimeZone        = r.TimeZone;
        s.DateFormat      = r.DateFormat;
        s.Currency        = r.Currency;
        await _db.SaveChangesAsync();
    }

    public async Task<NotificationSettingDto> GetNotificationAsync()
    {
        var n = await GetOrCreateNotificationAsync();
        return new NotificationSettingDto
        {
            EnableEmail               = n.EnableEmail,
            SmtpHost                  = n.SmtpHost,
            SmtpPort                  = n.SmtpPort,
            SmtpUseSsl                = n.SmtpUseSsl,
            SmtpUser                  = n.SmtpUser,
            FromAddress               = n.FromAddress,
            FromName                  = n.FromName,
            HasSmtpPassword           = !string.IsNullOrEmpty(n.SmtpPassword),
            EnableLine                = n.EnableLine,
            HasLineChannelAccessToken = !string.IsNullOrEmpty(n.LineChannelAccessToken),
            HasLineChannelSecret      = !string.IsNullOrEmpty(n.LineChannelSecret),
            // WebhookUrl is filled by the controller (needs the request host).
        };
    }

    public async Task UpdateNotificationAsync(UpdateNotificationSettingRequest r)
    {
        var n = await GetOrCreateNotificationAsync();
        n.EnableEmail = r.EnableEmail;
        n.SmtpHost    = r.SmtpHost;
        n.SmtpPort    = r.SmtpPort;
        n.SmtpUseSsl  = r.SmtpUseSsl;
        n.SmtpUser    = r.SmtpUser;
        n.FromAddress = r.FromAddress ?? "";
        n.FromName    = r.FromName ?? "";
        n.EnableLine  = r.EnableLine;

        // Secrets are write-only: a blank value means "keep what's stored".
        if (!string.IsNullOrWhiteSpace(r.SmtpPassword))
            n.SmtpPassword = r.SmtpPassword;
        if (!string.IsNullOrWhiteSpace(r.LineChannelAccessToken))
            n.LineChannelAccessToken = r.LineChannelAccessToken;
        if (!string.IsNullOrWhiteSpace(r.LineChannelSecret))
            n.LineChannelSecret = r.LineChannelSecret;

        await _db.SaveChangesAsync();

        // Drop the cached snapshot so the new values are used on the next send — no restart needed.
        _notificationSettings.Reload();
    }

    private async Task<SiteSetting> GetOrCreateSiteAsync()
    {
        var s = await _db.SiteSettings.OrderBy(x => x.Id).FirstOrDefaultAsync();
        if (s is null)
        {
            s = new SiteSetting { SiteTitle = "Church" };
            _db.SiteSettings.Add(s);
            await _db.SaveChangesAsync();
        }
        return s;
    }

    private async Task<NotificationSetting> GetOrCreateNotificationAsync()
    {
        var n = await _db.NotificationSettings.OrderBy(x => x.Id).FirstOrDefaultAsync();
        if (n is null)
        {
            n = new NotificationSetting();
            _db.NotificationSettings.Add(n);
            await _db.SaveChangesAsync();
        }
        return n;
    }
}
