using Fast.Web.Models;

namespace Fast.Web.Logic;

/// <summary>
/// Validates required header fields on invoices before saving or approving.
/// Supports both Natural Gas and Crude Oil invoices.
/// </summary>
public static class InvoiceHeaderValidator
{
    #region MainInvoice Validation (shared by both Gas and Crude)

    /// <summary>
    /// Validates that all required header fields are populated.
    /// Throws an exception with a list of missing fields if validation fails.
    /// </summary>
    public static void ValidateRequiredFields(MainInvoice invoice, string invoiceNum)
    {
        var missingFields = GetMissingFields(invoice);
        if (missingFields.Count > 0)
        {
            var fieldList = string.Join(", ", missingFields);
            throw new Exception($"Invoice {invoiceNum}: Cannot save with approval. Missing required fields: {fieldList}");
        }
    }

    /// <summary>
    /// Returns a list of field names that are missing or empty.
    /// </summary>
    public static List<string> GetMissingFields(MainInvoice invoice)
    {
        var missing = new List<string>();

        if (IsDefaultDate(invoice.InvoiceDate))
            missing.Add("Invoice Date");

        if (IsNullOrDefault(invoice.DueDate))
            missing.Add("Due Date");

        if (IsNullOrDefault(invoice.InvoiceTypeId))
            missing.Add("Version (Invoice Type)");

        if (IsNullOrDefault(invoice.ContractPaymentTypeId))
            missing.Add("Payment Method");

        if (IsNullOrEmpty(invoice.InternalEntityAddressLine1))
            missing.Add("Internal Entity Address Line 1");

        if (IsNullOrEmpty(invoice.InternalEntityCity))
            missing.Add("Internal Entity City");

        if (IsNullOrDefault(invoice.InternalEntityStateId))
            missing.Add("Internal Entity State");

        if (IsNullOrEmpty(invoice.InternalEntityZip))
            missing.Add("Internal Entity Zip");

        if (IsNullOrEmpty(invoice.InternalEntityEmailAddress))
            missing.Add("Internal Entity Email Address");

        if (IsNullOrEmpty(invoice.InternalEntityTelephoneNum))
            missing.Add("Internal Entity Telephone");

        if (IsNullOrEmpty(invoice.ContactName) && IsNullOrEmpty(invoice.InternalEntityAttn))
            missing.Add("Contact Name");

        if (IsNullOrEmpty(invoice.ContactTelephoneNum))
            missing.Add("Contact Telephone");

        if (IsNullOrEmpty(invoice.ContactEmail))
            missing.Add("Contact Email");

        if (IsNullOrEmpty(invoice.PaymentBankName))
            missing.Add("Payment Bank Name");

        // At least one of Wire or ACH ABA number must be present
        if (IsNullOrEmpty(invoice.PaymentAbaNumWire) && IsNullOrEmpty(invoice.PaymentAbaNumAch))
            missing.Add("Payment ABA Number (Wire or ACH)");

        if (IsNullOrEmpty(invoice.PaymentAccountNum))
            missing.Add("Payment Account Number");

        if (IsNullOrEmpty(invoice.CustomerNum))
            missing.Add("Customer Number");

        if (IsNullOrEmpty(invoice.CounterpartyAddressLine1))
            missing.Add("Counterparty Address Line 1");

        if (IsNullOrEmpty(invoice.CounterpartyCity))
            missing.Add("Counterparty City");

        if (IsNullOrDefault(invoice.CounterpartyStateId))
            missing.Add("Counterparty State");

        if (IsNullOrEmpty(invoice.CounterpartyZip))
            missing.Add("Counterparty Zip");

        if (IsNullOrEmpty(invoice.CounterpartyAttn))
            missing.Add("Counterparty Attn");

        if (IsNullOrEmpty(invoice.CounterpartyEmailAddresses))
            missing.Add("Counterparty Email Address");

        return missing;
    }

    #endregion

    #region Natural Gas (InvoiceGa) Validation

    /// <summary>
    /// Validates required fields directly from Natural Gas database model.
    /// Throws an exception with a list of missing fields if validation fails.
    /// </summary>
    public static void ValidateRequiredFields(InvoiceGa invoice)
    {
        var missingFields = GetMissingFields(invoice);
        if (missingFields.Count > 0)
        {
            var fieldList = string.Join(", ", missingFields);
            throw new Exception($"Invoice {invoice.InvoiceNum}: Cannot approve with missing required fields: {fieldList}");
        }
    }

    /// <summary>
    /// Returns a list of field names that are missing or empty from Natural Gas database model.
    /// </summary>
    public static List<string> GetMissingFields(InvoiceGa invoice)
    {
        var missing = new List<string>();

        if (IsDefaultDate(invoice.InvoiceDate))
            missing.Add("Invoice Date");

        if (IsNullOrDefault(invoice.DueDate))
            missing.Add("Due Date");

        if (IsNullOrDefault(invoice.InvoiceTypeId))
            missing.Add("Version (Invoice Type)");

        if (IsNullOrDefault(invoice.ContractPaymentTypeId))
            missing.Add("Payment Method");

        if (IsNullOrEmpty(invoice.InternalEntityAddressLine1))
            missing.Add("Internal Entity Address Line 1");

        if (IsNullOrEmpty(invoice.InternalEntityCity))
            missing.Add("Internal Entity City");

        if (IsNullOrDefault(invoice.InternalEntityStateId))
            missing.Add("Internal Entity State");

        if (IsNullOrEmpty(invoice.InternalEntityZip))
            missing.Add("Internal Entity Zip");

        if (IsNullOrEmpty(invoice.InternalEntityEmailAddress))
            missing.Add("Internal Entity Email Address");

        if (IsNullOrEmpty(invoice.InternalEntityTelephoneNum))
            missing.Add("Internal Entity Telephone");

        if (IsNullOrEmpty(invoice.ContactName) && IsNullOrEmpty(invoice.InternalEntityAttn))
            missing.Add("Contact Name");

        // Note: InvoiceGa uses ContactPhone, not ContactTelephoneNum
        if (IsNullOrEmpty(invoice.ContactPhone))
            missing.Add("Contact Telephone");

        if (IsNullOrEmpty(invoice.ContactEmail))
            missing.Add("Contact Email");

        if (IsNullOrEmpty(invoice.PaymentBankName))
            missing.Add("Payment Bank Name");

        // At least one of Wire or ACH ABA number must be present
        if (IsNullOrEmpty(invoice.PaymentAbaNumWire) && IsNullOrEmpty(invoice.PaymentAbaNumAch))
            missing.Add("Payment ABA Number (Wire or ACH)");

        if (IsNullOrEmpty(invoice.PaymentAccountNum))
            missing.Add("Payment Account Number");

        if (IsNullOrEmpty(invoice.CustomerNum))
            missing.Add("Customer Number");

        if (IsNullOrEmpty(invoice.CounterpartyAddressLine1))
            missing.Add("Counterparty Address Line 1");

        if (IsNullOrEmpty(invoice.CounterpartyCity))
            missing.Add("Counterparty City");

        if (IsNullOrDefault(invoice.CounterpartyStateId))
            missing.Add("Counterparty State");

        if (IsNullOrEmpty(invoice.CounterpartyZip))
            missing.Add("Counterparty Zip");

        if (IsNullOrEmpty(invoice.CounterpartyAttn))
            missing.Add("Counterparty Attn");

        if (IsNullOrEmpty(invoice.CounterpartyEmailAddresses))
            missing.Add("Counterparty Email Address");

        return missing;
    }

    #endregion

    #region Crude Oil (InvoiceCrude) Validation

    /// <summary>
    /// Validates required fields directly from Crude Oil database model.
    /// Throws an exception with a list of missing fields if validation fails.
    /// </summary>
    public static void ValidateRequiredFields(InvoiceCrude invoice)
    {
        var missingFields = GetMissingFields(invoice);
        if (missingFields.Count > 0)
        {
            var fieldList = string.Join(", ", missingFields);
            throw new Exception($"Invoice {invoice.InvoiceNum}: Cannot approve with missing required fields: {fieldList}");
        }
    }

    /// <summary>
    /// Returns a list of field names that are missing or empty from Crude Oil database model.
    /// </summary>
    public static List<string> GetMissingFields(InvoiceCrude invoice)
    {
        var missing = new List<string>();

        if (IsDefaultDate(invoice.InvoiceDate))
            missing.Add("Invoice Date");

        if (IsNullOrDefault(invoice.DueDate))
            missing.Add("Due Date");

        if (IsNullOrDefault(invoice.InvoiceTypeId))
            missing.Add("Version (Invoice Type)");

        if (IsNullOrDefault(invoice.ContractPaymentTypeId))
            missing.Add("Payment Method");

        if (IsNullOrEmpty(invoice.InternalEntityAddressLine1))
            missing.Add("Internal Entity Address Line 1");

        if (IsNullOrEmpty(invoice.InternalEntityCity))
            missing.Add("Internal Entity City");

        if (IsNullOrDefault(invoice.InternalEntityStateId))
            missing.Add("Internal Entity State");

        if (IsNullOrEmpty(invoice.InternalEntityZip))
            missing.Add("Internal Entity Zip");

        if (IsNullOrEmpty(invoice.InternalEntityEmailAddress))
            missing.Add("Internal Entity Email Address");

        if (IsNullOrEmpty(invoice.InternalEntityTelephoneNum))
            missing.Add("Internal Entity Telephone");

        if (IsNullOrEmpty(invoice.ContactName) && IsNullOrEmpty(invoice.InternalEntityAttn))
            missing.Add("Contact Name");

        // Note: InvoiceCrude uses ContactPhone, not ContactTelephoneNum
        if (IsNullOrEmpty(invoice.ContactPhone))
            missing.Add("Contact Telephone");

        if (IsNullOrEmpty(invoice.ContactEmail))
            missing.Add("Contact Email");

        if (IsNullOrEmpty(invoice.PaymentBankName))
            missing.Add("Payment Bank Name");

        // At least one of Wire or ACH ABA number must be present
        if (IsNullOrEmpty(invoice.PaymentAbaNumWire) && IsNullOrEmpty(invoice.PaymentAbaNumAch))
            missing.Add("Payment ABA Number (Wire or ACH)");

        if (IsNullOrEmpty(invoice.PaymentAccountNum))
            missing.Add("Payment Account Number");

        if (IsNullOrEmpty(invoice.CustomerNum))
            missing.Add("Customer Number");

        if (IsNullOrEmpty(invoice.CounterpartyAddressLine1))
            missing.Add("Counterparty Address Line 1");

        if (IsNullOrEmpty(invoice.CounterpartyCity))
            missing.Add("Counterparty City");

        if (IsNullOrDefault(invoice.CounterpartyStateId))
            missing.Add("Counterparty State");

        if (IsNullOrEmpty(invoice.CounterpartyZip))
            missing.Add("Counterparty Zip");

        if (IsNullOrEmpty(invoice.CounterpartyAttn))
            missing.Add("Counterparty Attn");

        if (IsNullOrEmpty(invoice.CounterpartyEmailAddresses))
            missing.Add("Counterparty Email Address");

        return missing;
    }

    #endregion

    #region Helper Methods

    private static bool IsNullOrEmpty(string? value) => string.IsNullOrWhiteSpace(value);

    private static bool IsDefaultDate(DateOnly date) => date == default;

    private static bool IsNullOrDefault(int? value) => !value.HasValue || value == 0;

    private static bool IsNullOrDefault(int value) => value == 0;

    private static bool IsNullOrDefault(DateOnly? value) => !value.HasValue || value.Value == default;

    #endregion
}
