using PowderCoating.Core.Enums;

namespace PowderCoating.Application.DTOs.Accounting;

// Accounting method badge — set on report DTOs so views can show "Cash Basis" / "Accrual Basis"
// without needing a separate round-trip to the company settings.


// ── Cash Flow Statement ──────────────────────────────────────────────────────

/// <summary>
/// Cash Flow Statement using the direct (cash-basis) method for operating activities.
/// Investing and Financing sections contain line items derived from account-level changes.
/// BeginningCash + NetChangeInCash should equal EndingCash (within rounding tolerances).
/// </summary>
public class CashFlowStatementDto
{
    public string CompanyName { get; set; } = string.Empty;
    public DateTime From { get; set; }
    public DateTime To { get; set; }
    public AccountingMethod Method { get; set; }

    // ── Operating (direct / cash method) ───────────────────────────────────
    /// <summary>Customer invoice payments received in the period.</summary>
    public decimal CashFromCustomers { get; set; }
    /// <summary>Vendor bill payments made in the period.</summary>
    public decimal CashToVendors { get; set; }
    /// <summary>Direct expense payments made in the period (not via bills).</summary>
    public decimal CashForExpenses { get; set; }
    public decimal NetOperating => CashFromCustomers - CashToVendors - CashForExpenses;

    // ── Investing ──────────────────────────────────────────────────────────
    public List<CashFlowLineDto> InvestingLines { get; set; } = new();
    public decimal NetInvesting => InvestingLines.Sum(l => l.Amount);

    // ── Financing ──────────────────────────────────────────────────────────
    public List<CashFlowLineDto> FinancingLines { get; set; } = new();
    public decimal NetFinancing => FinancingLines.Sum(l => l.Amount);

    // ── Summary ────────────────────────────────────────────────────────────
    public decimal BeginningCash { get; set; }
    public decimal NetChangeInCash => NetOperating + NetInvesting + NetFinancing;
    public decimal EndingCash => BeginningCash + NetChangeInCash;
}

/// <summary>A single line in the Investing or Financing section of the Cash Flow Statement.</summary>
public class CashFlowLineDto
{
    public string Label { get; set; } = string.Empty;
    /// <summary>Positive = cash inflow, negative = cash outflow.</summary>
    public decimal Amount { get; set; }
}

// ── Customer / Vendor Statements ─────────────────────────────────────────────

public class CustomerStatementDto
{
    public int CustomerId { get; set; }
    public string CustomerName { get; set; } = string.Empty;
    public string CompanyName { get; set; } = string.Empty;
    public string? CustomerAddress { get; set; }
    public DateTime From { get; set; }
    public DateTime To { get; set; }
    public decimal OpeningBalance { get; set; }
    public List<StatementLineDto> Lines { get; set; } = new();
    public decimal ClosingBalance { get; set; }
}

public class VendorStatementDto
{
    public int VendorId { get; set; }
    public string VendorName { get; set; } = string.Empty;
    public string CompanyName { get; set; } = string.Empty;
    public DateTime From { get; set; }
    public DateTime To { get; set; }
    public decimal OpeningBalance { get; set; }
    public List<StatementLineDto> Lines { get; set; } = new();
    public decimal ClosingBalance { get; set; }
}

public class StatementLineDto
{
    public DateTime Date { get; set; }
    /// <summary>E.g., "Invoice", "Payment", "Credit Applied", "Deposit Applied".</summary>
    public string Type { get; set; } = string.Empty;
    public string Reference { get; set; } = string.Empty;
    public string Description { get; set; } = string.Empty;
    /// <summary>Amount added to the balance (invoice for customer, bill for vendor).</summary>
    public decimal? Debit { get; set; }
    /// <summary>Amount reducing the balance (payment, credit).</summary>
    public decimal? Credit { get; set; }
    public decimal RunningBalance { get; set; }
}

// ── AP Aging ──────────────────────────────────────────────────────────────────

public class ApAgingReportDto
{
    public DateTime AsOf { get; set; }
    public string CompanyName { get; set; } = string.Empty;

    public List<ApAgingVendorDto> Vendors { get; set; } = new();

    public decimal TotalCurrent { get; set; }
    public decimal Total1to30   { get; set; }
    public decimal Total31to60  { get; set; }
    public decimal Total61to90  { get; set; }
    public decimal TotalOver90  { get; set; }
    public decimal TotalOutstanding => TotalCurrent + Total1to30 + Total31to60 + Total61to90 + TotalOver90;
}

public class ApAgingVendorDto
{
    public int VendorId { get; set; }
    public string VendorName { get; set; } = string.Empty;
    public List<ApAgingBillDto> Bills { get; set; } = new();
    public decimal TotalCurrent { get; set; }
    public decimal Total1to30   { get; set; }
    public decimal Total31to60  { get; set; }
    public decimal Total61to90  { get; set; }
    public decimal TotalOver90  { get; set; }
    public decimal TotalBalance => TotalCurrent + Total1to30 + Total31to60 + Total61to90 + TotalOver90;
}

public class ApAgingBillDto
{
    public int BillId { get; set; }
    public string BillNumber { get; set; } = string.Empty;
    public DateTime BillDate { get; set; }
    public DateTime? DueDate  { get; set; }
    public decimal BalanceDue { get; set; }
    public int DaysOverdue    { get; set; }
}

// ── Trial Balance ─────────────────────────────────────────────────────────────

public class TrialBalanceDto
{
    public DateTime AsOf { get; set; }
    public string CompanyName { get; set; } = string.Empty;
    public List<TrialBalanceLine> Lines { get; set; } = new();
    public decimal TotalDebits  { get; set; }
    public decimal TotalCredits { get; set; }
    public bool IsBalanced => Math.Abs(TotalDebits - TotalCredits) < 0.01m;
}

public class TrialBalanceLine
{
    public int AccountId           { get; set; }
    public string AccountNumber    { get; set; } = string.Empty;
    public string AccountName      { get; set; } = string.Empty;
    public AccountType AccountType { get; set; }
    public decimal DebitBalance    { get; set; }
    public decimal CreditBalance   { get; set; }
}

// ── Balance Reconciliation ─────────────────────────────────────────────────────

/// <summary>
/// Diagnostic that surfaces drift in the denormalized balances: each account's stored
/// <c>CurrentBalance</c> vs its recomputed ledger balance, plus the AR/AP subledger totals
/// (sum of Customer/Vendor CurrentBalance) vs their GL control account balances. Read-only.
/// </summary>
public class BalanceReconciliationDto
{
    public DateTime AsOf { get; set; }
    public string CompanyName { get; set; } = string.Empty;

    public List<BalanceReconciliationLine> AccountLines { get; set; } = new();

    public decimal ArControlBalance { get; set; }
    public decimal ArSubledgerTotal { get; set; }
    public decimal ArDifference => ArControlBalance - ArSubledgerTotal;

    public decimal ApControlBalance { get; set; }
    public decimal ApSubledgerTotal { get; set; }
    public decimal ApDifference => ApControlBalance - ApSubledgerTotal;

    public IEnumerable<BalanceReconciliationLine> DriftedAccounts => AccountLines.Where(l => !l.IsReconciled);
    public bool AccountsReconciled => AccountLines.All(l => l.IsReconciled);
    public bool ArReconciled => Math.Abs(ArDifference) < 0.01m;
    public bool ApReconciled => Math.Abs(ApDifference) < 0.01m;
    public bool AllReconciled => AccountsReconciled && ArReconciled && ApReconciled;
}

public class BalanceReconciliationLine
{
    public int AccountId           { get; set; }
    public string AccountNumber    { get; set; } = string.Empty;
    public string AccountName      { get; set; } = string.Empty;
    public AccountType AccountType { get; set; }
    /// <summary>The denormalized Account.CurrentBalance (what most UI reads).</summary>
    public decimal StoredBalance   { get; set; }
    /// <summary>The balance recomputed from source documents (what RecalculateBalances would set).</summary>
    public decimal LedgerBalance   { get; set; }
    public decimal Difference => StoredBalance - LedgerBalance;
    public bool IsReconciled => Math.Abs(Difference) < 0.01m;
}

// ── Profit & Loss ─────────────────────────────────────────────────────────────

public class ProfitAndLossDto
{
    public DateTime From { get; set; }
    public DateTime To { get; set; }
    public string CompanyName { get; set; } = string.Empty;
    public AccountingMethod AccountingMethod { get; set; } = AccountingMethod.Accrual;

    public List<FinancialReportLine> RevenueLines { get; set; } = new();
    public decimal TotalRevenue { get; set; }

    public List<FinancialReportLine> CogsLines { get; set; } = new();
    public decimal TotalCogs { get; set; }

    public decimal GrossProfit => TotalRevenue - TotalCogs;
    public decimal GrossMarginPercent => TotalRevenue == 0 ? 0 : Math.Round(GrossProfit / TotalRevenue * 100, 1);

    public List<FinancialReportLine> ExpenseLines { get; set; } = new();
    public decimal TotalExpenses { get; set; }

    public decimal OperatingIncome => GrossProfit - TotalExpenses;
    public decimal NetIncome => OperatingIncome;   // Extend later for other income/tax
}

public class FinancialReportLine
{
    public int AccountId { get; set; }
    public string AccountNumber { get; set; } = string.Empty;
    public string AccountName { get; set; } = string.Empty;
    public decimal Amount { get; set; }
}

// ── Balance Sheet ─────────────────────────────────────────────────────────────

public class BalanceSheetDto
{
    public DateTime AsOf { get; set; }
    public string CompanyName { get; set; } = string.Empty;
    public AccountingMethod AccountingMethod { get; set; } = AccountingMethod.Accrual;

    // Assets
    public List<FinancialReportLine> CurrentAssets { get; set; } = new();
    public List<FinancialReportLine> FixedAssets { get; set; } = new();
    public List<FinancialReportLine> OtherAssets { get; set; } = new();
    public decimal TotalAssets { get; set; }

    // Liabilities
    public List<FinancialReportLine> CurrentLiabilities { get; set; } = new();
    public List<FinancialReportLine> LongTermLiabilities { get; set; } = new();
    public decimal TotalLiabilities { get; set; }

    // Equity
    public List<FinancialReportLine> EquityLines { get; set; } = new();
    public decimal RetainedEarnings { get; set; }   // Computed net income to date
    public decimal TotalEquity { get; set; }

    public decimal TotalLiabilitiesAndEquity => TotalLiabilities + TotalEquity;

    // Helper: is the sheet balanced?
    public bool IsBalanced => Math.Abs(TotalAssets - TotalLiabilitiesAndEquity) < 0.01m;
}

// ── AR Aging ──────────────────────────────────────────────────────────────────

public class ArAgingReportDto
{
    public DateTime AsOf { get; set; }
    public string CompanyName { get; set; } = string.Empty;

    public List<ArAgingCustomerDto> Customers { get; set; } = new();

    public decimal TotalCurrent { get; set; }
    public decimal Total1to30 { get; set; }
    public decimal Total31to60 { get; set; }
    public decimal Total61to90 { get; set; }
    public decimal TotalOver90 { get; set; }
    public decimal TotalOutstanding => TotalCurrent + Total1to30 + Total31to60 + Total61to90 + TotalOver90;
}

public class ArAgingCustomerDto
{
    public int CustomerId { get; set; }
    public string CustomerName { get; set; } = string.Empty;
    public List<ArAgingInvoiceDto> Invoices { get; set; } = new();
    public decimal TotalCurrent { get; set; }
    public decimal Total1to30 { get; set; }
    public decimal Total31to60 { get; set; }
    public decimal Total61to90 { get; set; }
    public decimal TotalOver90 { get; set; }
    public decimal TotalBalance => TotalCurrent + Total1to30 + Total31to60 + Total61to90 + TotalOver90;
}

public class ArAgingInvoiceDto
{
    public int InvoiceId { get; set; }
    public string InvoiceNumber { get; set; } = string.Empty;
    public DateTime InvoiceDate { get; set; }
    public DateTime? DueDate { get; set; }
    public decimal BalanceDue { get; set; }
    public int DaysOverdue { get; set; }
}

// ── Sales & Income ────────────────────────────────────────────────────────────

public class SalesIncomeReportDto
{
    public DateTime From { get; set; }
    public DateTime To { get; set; }
    public string CompanyName { get; set; } = string.Empty;

    public decimal TotalInvoiced { get; set; }
    public decimal TotalCollected { get; set; }
    public decimal TotalTax { get; set; }
    public decimal TotalDiscount { get; set; }
    public decimal NetRevenue => TotalInvoiced - TotalDiscount;
    public int InvoiceCount { get; set; }
    public int CustomerCount { get; set; }
    public decimal AverageInvoiceValue => InvoiceCount == 0 ? 0 : Math.Round(TotalInvoiced / InvoiceCount, 2);

    public List<SalesByCustomerDto> ByCustomer { get; set; } = new();
    public List<SalesByMonthDto> ByMonth { get; set; } = new();
    public List<SalesInvoiceLineDto> Invoices { get; set; } = new();
}

public class SalesByCustomerDto
{
    public int CustomerId { get; set; }
    public string CustomerName { get; set; } = string.Empty;
    public int InvoiceCount { get; set; }
    public decimal TotalInvoiced { get; set; }
    public decimal TotalPaid { get; set; }
    public decimal BalanceDue { get; set; }
}

public class SalesByMonthDto
{
    public int Year { get; set; }
    public int Month { get; set; }
    public string Label { get; set; } = string.Empty;
    public decimal TotalInvoiced { get; set; }
    public decimal TotalCollected { get; set; }
    public int InvoiceCount { get; set; }
}

public class SalesInvoiceLineDto
{
    public int InvoiceId { get; set; }
    public string InvoiceNumber { get; set; } = string.Empty;
    public string CustomerName { get; set; } = string.Empty;
    public DateTime InvoiceDate { get; set; }
    public DateTime? DueDate { get; set; }
    public string Status { get; set; } = string.Empty;
    public decimal SubTotal { get; set; }
    public decimal TaxAmount { get; set; }
    public decimal Total { get; set; }
    public decimal AmountPaid { get; set; }
    public decimal BalanceDue { get; set; }
}

// ============================================================
// SALES TAX REPORT
// ============================================================

public class SalesTaxReportDto
{
    public DateTime From { get; set; }
    public DateTime To { get; set; }
    public string CompanyName { get; set; } = string.Empty;

    /// <summary>Subtotal of invoices where TaxAmount > 0.</summary>
    public decimal TotalTaxableSales { get; set; }
    /// <summary>Subtotal of invoices where TaxAmount == 0.</summary>
    public decimal TotalNonTaxableSales { get; set; }
    /// <summary>Sum of all TaxAmount values across the period.</summary>
    public decimal TotalTaxBilled { get; set; }
    public int TaxableInvoiceCount { get; set; }
    public int NonTaxableInvoiceCount { get; set; }
    public decimal EffectiveTaxRate => TotalTaxableSales == 0 ? 0
        : Math.Round(TotalTaxBilled / TotalTaxableSales * 100, 2);

    public List<SalesTaxByAccountDto> ByAccount { get; set; } = new();
    public List<SalesTaxByMonthDto> ByMonth { get; set; } = new();
    public List<SalesTaxInvoiceLineDto> Invoices { get; set; } = new();
}

public class SalesTaxByAccountDto
{
    public int? AccountId { get; set; }
    public string AccountName { get; set; } = string.Empty;
    public string AccountNumber { get; set; } = string.Empty;
    public decimal TaxableSales { get; set; }
    public decimal TaxBilled { get; set; }
    public int InvoiceCount { get; set; }
}

public class SalesTaxByMonthDto
{
    public int Year { get; set; }
    public int Month { get; set; }
    public string Label { get; set; } = string.Empty;
    public decimal TaxableSales { get; set; }
    public decimal TaxBilled { get; set; }
    public int InvoiceCount { get; set; }
}

public class SalesTaxInvoiceLineDto
{
    public int InvoiceId { get; set; }
    public string InvoiceNumber { get; set; } = string.Empty;
    public string CustomerName { get; set; } = string.Empty;
    public DateTime InvoiceDate { get; set; }
    public string Status { get; set; } = string.Empty;
    public decimal SubTotal { get; set; }
    public decimal TaxPercent { get; set; }
    public decimal TaxAmount { get; set; }
    public decimal Total { get; set; }
    public decimal AmountPaid { get; set; }
    public decimal BalanceDue { get; set; }
    public string TaxAccountName { get; set; } = string.Empty;
}
