using System.Net;
using System.Text;
using ERPCore.Domain.Entities;
using ERPCore.Domain.Enums;
using ERPCore.Dtos.Hrm;
using ERPCore.Repositories.Interfaces;
using ERPCore.Services.Interfaces;
using Microsoft.EntityFrameworkCore;

namespace ERPCore.Services.Hrm;

/// <inheritdoc cref="IPayslipService"/>
public sealed class PayslipService : IPayslipService
{
    private readonly IRepository<Payslip> _payslips;

    public PayslipService(IRepository<Payslip> payslips) => _payslips = payslips;

    public async Task<PayslipDto?> GetAsync(int payslipId, CancellationToken ct = default)
    {
        var payslip = await _payslips.Query().AsNoTracking().FirstOrDefaultAsync(p => p.PayslipId == payslipId, ct);
        return payslip is null ? null : new PayslipDto(payslip.PayslipId, payslip.PayrollLineId, payslip.GeneratedAt, payslip.ReleasedAt, payslip.ReleasedBy);
    }

    public async Task<string?> RenderHtmlAsync(int payslipId, CancellationToken ct = default)
    {
        var payslip = await _payslips.Query().AsNoTracking()
            .Include(p => p.PayrollLine!).ThenInclude(l => l.Employee)
            .Include(p => p.PayrollLine!).ThenInclude(l => l.Components)
            .Include(p => p.PayrollLine!).ThenInclude(l => l.PayrollRun)
            .FirstOrDefaultAsync(p => p.PayslipId == payslipId, ct);
        if (payslip?.PayrollLine is null) return null;

        var line = payslip.PayrollLine;
        var employee = line.Employee;
        var run = line.PayrollRun;

        var rows = new StringBuilder();
        foreach (var group in line.Components.GroupBy(c => c.ComponentCategory))
        {
            var title = group.Key switch
            {
                PayrollLineComponentCategory.Earning => "Earnings",
                PayrollLineComponentCategory.Deduction => "Deductions",
                _ => "Employer Contributions (informational, not deducted)"
            };
            rows.Append($"<tr><td colspan='2' style='font-weight:bold;padding-top:12px;'>{WebUtility.HtmlEncode(title)}</td></tr>");
            foreach (var c in group.OrderBy(c => c.SortOrder))
                rows.Append($"<tr><td>{WebUtility.HtmlEncode(c.Label)}</td><td style='text-align:right;'>{c.Amount:N2}</td></tr>");
        }

        const string style = "body{font-family:Arial,sans-serif;font-size:14px;color:#111;}"
            + "table{width:100%;border-collapse:collapse;} td{padding:4px 8px;}"
            + ".totals td{font-weight:bold;border-top:2px solid #333;}"
            + "h2{margin-bottom:0;} .sub{color:#555;margin-top:2px;}";

        var html = new StringBuilder();
        html.Append("<!doctype html><html><head><meta charset=\"utf-8\"><title>Payslip</title><style>")
            .Append(style).Append("</style></head><body>")
            .Append("<h2>Payslip</h2>")
            .Append("<div class=\"sub\">Employee: ").Append(WebUtility.HtmlEncode(employee?.FullName ?? string.Empty))
            .Append(" (").Append(WebUtility.HtmlEncode(employee?.EmployeeCode ?? string.Empty)).Append(")</div>")
            .Append("<div class=\"sub\">Period: ").Append(run?.PeriodMonth.ToString("00")).Append('/').Append(run?.PeriodYear)
            .Append(" &middot; Run ").Append(WebUtility.HtmlEncode(run?.DocNo ?? string.Empty)).Append("</div>")
            .Append("<table>").Append(rows)
            .Append("<tr class=\"totals\"><td>Gross Salary</td><td style=\"text-align:right;\">").Append(line.GrossSalary.ToString("N2")).Append("</td></tr>")
            .Append("<tr class=\"totals\"><td>Net Salary</td><td style=\"text-align:right;\">").Append(line.NetSalary.ToString("N2")).Append("</td></tr>")
            .Append("</table>")
            .Append("<p class=\"sub\">Generated ").Append(payslip.GeneratedAt.ToString("yyyy-MM-dd HH:mm")).Append(" UTC</p>")
            .Append("</body></html>");

        return html.ToString();
    }
}
