using Books.Api.EventFlow.Repositories;
using Ledger.Core.Models;
using Ledger.Core.Services;

namespace Books.Api.Reporting;

/// <summary>
/// Service for generating VAT (moms) reports from ledger data.
/// Aggregates VAT account balances for SKAT compliance.
/// </summary>
public class VatReportService(
    IAccountRepository accountRepository,
    ILedgerService ledgerService,
    ILogger<VatReportService> logger) : IVatReportService
{
    // Standard Danish VAT account numbers
    // TODO: These should ideally come from company-level configuration,
    //       as different chart-of-accounts templates may use different numbers.
    private const string InputVatAccountNumber = "5610";  // Købsmoms (indgående moms)
    private const string OutputVatAccountNumber = "5611"; // Salgsmoms (udgående moms)

    public async Task<VatReportDto> GenerateReportAsync(
        string companyId,
        DateOnly periodStart,
        DateOnly periodEnd,
        CancellationToken ct = default)
    {
        // Validate period
        if (periodEnd < periodStart)
        {
            throw new ArgumentException("Slutdato skal være efter startdato", nameof(periodEnd));
        }

        var daysDiff = periodEnd.DayNumber - periodStart.DayNumber;
        if (daysDiff > 366)
        {
            throw new ArgumentException("Perioden må ikke overstige ét år (366 dage)", nameof(periodEnd));
        }

        logger.LogInformation(
            "Generating VAT report for company {CompanyId} from {PeriodStart} to {PeriodEnd}",
            companyId, periodStart, periodEnd);

        // Look up VAT accounts
        var inputVatAccount = await accountRepository.GetByCompanyAndNumberAsync(
            companyId, InputVatAccountNumber, ct);
        var outputVatAccount = await accountRepository.GetByCompanyAndNumberAsync(
            companyId, OutputVatAccountNumber, ct);

        var report = new VatReportDto
        {
            PeriodStart = periodStart,
            PeriodEnd = periodEnd
        };

        // If neither VAT account exists, return empty report
        if (inputVatAccount == null && outputVatAccount == null)
        {
            logger.LogWarning(
                "No VAT accounts found for company {CompanyId}. Returning empty report.",
                companyId);
            return report;
        }

        // Collect account IDs for ledger query
        var accountIds = new List<Guid>();

        if (inputVatAccount != null && TryParseAccountGuid(inputVatAccount.Id, out var inputGuid))
        {
            accountIds.Add(inputGuid);
        }

        if (outputVatAccount != null && TryParseAccountGuid(outputVatAccount.Id, out var outputGuid))
        {
            accountIds.Add(outputGuid);
        }

        if (accountIds.Count == 0)
        {
            logger.LogWarning("No valid VAT account GUIDs found for company {CompanyId}", companyId);
            return report;
        }

        // Query ledger for aggregated balances in the period
        var query = new EntriesQuery
        {
            AccountIds = accountIds,
            From = new DateTimeOffset(periodStart.ToDateTime(TimeOnly.MinValue)),
            To = new DateTimeOffset(periodEnd.ToDateTime(TimeOnly.MaxValue)),
            Aggregate = true
        };

        var result = await ledgerService.QueryEntriesAsync(query, ct);

        // Process aggregated balances
        if (result.Aggregates != null)
        {
            foreach (var balance in result.Aggregates)
            {
                if (inputVatAccount != null &&
                    TryParseAccountGuid(inputVatAccount.Id, out var checkInputGuid) &&
                    balance.AccountId == checkInputGuid)
                {
                    // Input VAT (5610): Debits are VAT receivable/deductions
                    // Box B = total input VAT deduction
                    report.BoxB = balance.TotalDebits;
                    report.TransactionCount += balance.EntryCount;

                    logger.LogDebug(
                        "Input VAT (5610): TotalDebits={Debits}, TotalCredits={Credits}, NetChange={Net}",
                        balance.TotalDebits, balance.TotalCredits, balance.NetChange);
                }
                else if (outputVatAccount != null &&
                         TryParseAccountGuid(outputVatAccount.Id, out var checkOutputGuid) &&
                         balance.AccountId == checkOutputGuid)
                {
                    // Output VAT (5611): Credits are VAT payable to SKAT
                    // Box A = total output VAT (salgsmoms)
                    report.BoxA = balance.TotalCredits;
                    report.TransactionCount += balance.EntryCount;

                    logger.LogDebug(
                        "Output VAT (5611): TotalDebits={Debits}, TotalCredits={Credits}, NetChange={Net}",
                        balance.TotalDebits, balance.TotalCredits, balance.NetChange);
                }
            }
        }

        // Calculate summary totals
        // Box A = Salgsmoms (domestic output VAT)
        // Box B = Købsmoms (input VAT - deductible)
        // Box C = EU-varekøb moms (not yet supported - requires VAT code breakdown)
        // Box D = Ydelseskøb moms (not yet supported - requires VAT code breakdown)
        report.TotalOutputVat = report.BoxA + report.BoxC + report.BoxD;
        report.TotalInputVat = report.BoxB;
        report.NetVat = report.TotalOutputVat - report.TotalInputVat;

        // Basis1 (Felt 1): Net domestic turnover with VAT
        // TODO: Query actual net turnover from transactions with output VAT codes (U25)
        //       instead of back-calculating from VAT amount, which is inaccurate when
        //       mixed VAT rates or partial deductions are involved.
        //       Ideally: query revenue account balances filtered by VAT code U25.
        // For now, back-calculate from output VAT assuming standard 25% rate
        if (report.BoxA > 0)
        {
            report.Basis1 = Math.Round(report.BoxA / 0.25m, 2);
        }

        // TODO: Box C (EU-varekøb moms) - Requires VAT code breakdown from transactions.
        //       Query transactions with VAT code IEUV to compute reverse-charge VAT on EU goods.
        //       report.BoxC = sum of VAT calculated on IEUV transactions.
        //       report.Basis3 = net purchase amount for IEUV transactions.

        // TODO: Box D (Ydelseskøb moms) - Requires VAT code breakdown from transactions.
        //       Query transactions with VAT codes IEUY, IVV, IVY to compute reverse-charge VAT
        //       on services purchased from abroad.
        //       report.BoxD = sum of VAT calculated on IEUY/IVV/IVY transactions.
        //       report.Basis4 = net purchase amount for IEUY/IVV/IVY transactions.

        logger.LogInformation(
            "VAT report generated for company {CompanyId}: OutputVAT={OutputVat}, InputVAT={InputVat}, NetVAT={NetVat}",
            companyId, report.TotalOutputVat, report.TotalInputVat, report.NetVat);

        return report;
    }

    private static bool TryParseAccountGuid(string accountId, out Guid guid)
    {
        // Account IDs are in format "account-{guid}"
        if (accountId.StartsWith("account-"))
        {
            return Guid.TryParse(accountId.Replace("account-", ""), out guid);
        }

        guid = Guid.Empty;
        return false;
    }
}
