using System.ComponentModel.DataAnnotations;

namespace PowderCoating.Application.DTOs.Customer;

public class CustomerDto
{
    public int Id { get; set; }
    public string? CompanyName { get; set; }
    public string? ContactFirstName { get; set; }
    public string? ContactLastName { get; set; }
    public string? Email { get; set; }
    public string? BillingEmail { get; set; }
    public string? Phone { get; set; }
    public string? MobilePhone { get; set; }
    public string? Address { get; set; }
    public string? City { get; set; }
    public string? State { get; set; }
    public string? ZipCode { get; set; }
    public string? Country { get; set; }
    public bool IsCommercial { get; set; }
    public string? TaxId { get; set; }
    public decimal CreditLimit { get; set; }
    public decimal CurrentBalance { get; set; }
    public decimal CreditBalance { get; set; }
    public string? PaymentTerms { get; set; }
    public int? PricingTierId { get; set; }
    public string? PricingTierName { get; set; }
    public bool IsTaxExempt { get; set; }
    public bool HasTaxExemptCertificate { get; set; }
    public string? TaxExemptCertificateFileName { get; set; }
    public string? GeneralNotes { get; set; }
    public bool IsActive { get; set; }
    public DateTime? LastContactDate { get; set; }
    public DateTime CreatedAt { get; set; }
    public bool NotifyByEmail { get; set; }
    public bool NotifyBySms { get; set; }
    public DateTime? SmsConsentedAt { get; set; }
    public string? SmsConsentMethod { get; set; }

    // CRM
    public string? LeadSource { get; set; }

    // Ship-to address
    public string? ShipToAddress { get; set; }
    public string? ShipToCity { get; set; }
    public string? ShipToState { get; set; }
    public string? ShipToZipCode { get; set; }
    public string? ShipToCountry { get; set; }
}

public class CreateCustomerDto : IValidatableObject
{
    [Display(Name = "Company Name")]
    [StringLength(200)]
    public string? CompanyName { get; set; }

    [Display(Name = "First Name")]
    [StringLength(100)]
    public string? ContactFirstName { get; set; }

    [Display(Name = "Last Name")]
    [StringLength(100)]
    public string? ContactLastName { get; set; }

    [Display(Name = "Email")]
    [StringLength(1000)]
    public string? Email { get; set; }

    [Display(Name = "Billing / Accounting Email")]
    [StringLength(1000)]
    public string? BillingEmail { get; set; }

    [Display(Name = "Phone")]
    [Phone(ErrorMessage = "Please enter a valid phone number")]
    [StringLength(20)]
    public string? Phone { get; set; }

    [Display(Name = "Mobile Phone")]
    [Phone(ErrorMessage = "Please enter a valid mobile phone number")]
    [StringLength(20)]
    public string? MobilePhone { get; set; }

    [Display(Name = "Street Address")]
    [StringLength(500)]
    public string? Address { get; set; }

    [Display(Name = "City")]
    [StringLength(100)]
    public string? City { get; set; }

    [Display(Name = "State")]
    [StringLength(50)]
    public string? State { get; set; }

    [Display(Name = "Zip Code")]
    [StringLength(20)]
    public string? ZipCode { get; set; }

    [Display(Name = "Country")]
    [StringLength(100)]
    public string? Country { get; set; } = "USA";

    [Display(Name = "Customer Type")]
    public bool IsCommercial { get; set; }

    [Display(Name = "Tax ID / EIN")]
    [StringLength(50)]
    public string? TaxId { get; set; }

    [Display(Name = "Credit Limit")]
    [Range(0, 9999999.99)]
    public decimal CreditLimit { get; set; }

    [Display(Name = "Payment Terms")]
    [StringLength(50)]
    public string? PaymentTerms { get; set; }

    [Display(Name = "Pricing Tier")]
    public int? PricingTierId { get; set; }

    [Display(Name = "Tax Exempt")]
    public bool IsTaxExempt { get; set; }

    [Display(Name = "General Notes")]
    [StringLength(2000)]
    public string? GeneralNotes { get; set; }

    [Display(Name = "How did you find us?")]
    [StringLength(100)]
    public string? LeadSource { get; set; }

    // Ship-to / alternate address
    [Display(Name = "Ship-To Street Address")]
    [StringLength(500)]
    public string? ShipToAddress { get; set; }

    [Display(Name = "City")]
    [StringLength(100)]
    public string? ShipToCity { get; set; }

    [Display(Name = "State")]
    [StringLength(50)]
    public string? ShipToState { get; set; }

    [Display(Name = "Zip Code")]
    [StringLength(20)]
    public string? ShipToZipCode { get; set; }

    [Display(Name = "Country")]
    [StringLength(100)]
    public string? ShipToCountry { get; set; }

    [Display(Name = "Notify by Email")]
    public bool NotifyByEmail { get; set; } = true;

    [Display(Name = "Notify by SMS")]
    public bool NotifyBySms { get; set; } = false;

    /// <summary>
    /// Form-only flag: staff checks this to record that the customer gave verbal consent to receive SMS.
    /// Not mapped to any entity field — the controller handles setting SmsConsentedAt and SmsConsentMethod.
    /// </summary>
    [Display(Name = "Customer has verbally consented to receive SMS notifications")]
    public bool SmsConsentGranted { get; set; } = false;

    public IEnumerable<ValidationResult> Validate(ValidationContext validationContext)
    {
        // At least one name field is required (Company Name OR Contact First/Last Name)
        if (string.IsNullOrWhiteSpace(CompanyName) &&
            string.IsNullOrWhiteSpace(ContactFirstName) &&
            string.IsNullOrWhiteSpace(ContactLastName))
        {
            yield return new ValidationResult(
                "Please provide either a Company Name or a Contact Name (First and/or Last Name)",
                new[] { nameof(CompanyName), nameof(ContactFirstName), nameof(ContactLastName) });
        }

        // At least one contact method is required (Email, Phone, or Mobile Phone)
        if (string.IsNullOrWhiteSpace(Email) && string.IsNullOrWhiteSpace(Phone) && string.IsNullOrWhiteSpace(MobilePhone))
        {
            yield return new ValidationResult(
                "Please provide at least one contact method (Email, Phone, or Mobile Phone)",
                new[] { nameof(Email), nameof(Phone), nameof(MobilePhone) });
        }

        // Validate each address in comma-separated email fields
        foreach (var addr in SplitEmails(Email))
        {
            if (!IsValidEmail(addr))
                yield return new ValidationResult(
                    $"'{addr}' is not a valid email address.",
                    new[] { nameof(Email) });
        }
        foreach (var addr in SplitEmails(BillingEmail))
        {
            if (!IsValidEmail(addr))
                yield return new ValidationResult(
                    $"'{addr}' is not a valid email address.",
                    new[] { nameof(BillingEmail) });
        }
    }

    private static IEnumerable<string> SplitEmails(string? value) =>
        string.IsNullOrWhiteSpace(value)
            ? []
            : value.Split(',', StringSplitOptions.RemoveEmptyEntries | StringSplitOptions.TrimEntries);

    private static bool IsValidEmail(string email)
    {
        try { _ = new System.Net.Mail.MailAddress(email); return true; }
        catch { return false; }
    }
}

public class UpdateCustomerDto : CreateCustomerDto
{
    public int Id { get; set; }
    public bool IsActive { get; set; }
    public bool HasTaxExemptCertificate { get; set; }
    public string? TaxExemptCertificateFileName { get; set; }
    // Read from entity so the Edit view can display consent status
    public DateTime? SmsConsentedAt { get; set; }
    public string? SmsConsentMethod { get; set; }
}

public class CustomerListDto
{
    public int Id { get; set; }
    public string? CompanyName { get; set; }
    public string ContactName { get; set; } = string.Empty;
    public string? Phone { get; set; }
    public string? Email { get; set; }
    public bool IsCommercial { get; set; }
    public decimal CurrentBalance { get; set; }
    public bool IsActive { get; set; }
    public DateTime? LastContactDate { get; set; }
    public bool NotifyByEmail { get; set; }
    public bool NotifyBySms { get; set; }
}

public class AddCreditDto
{
    [Required]
    [Range(0.01, 99999.99, ErrorMessage = "Amount must be between $0.01 and $99,999.99")]
    public decimal Amount { get; set; }

    [Required]
    [StringLength(200, ErrorMessage = "Reason cannot exceed 200 characters")]
    [Display(Name = "Reason")]
    public string Reason { get; set; } = string.Empty;

    [StringLength(1000)]
    [Display(Name = "Notes")]
    public string? Notes { get; set; }

    [Display(Name = "Expiry Date (optional)")]
    public DateTime? ExpiryDate { get; set; }
}
