using System.ComponentModel.DataAnnotations;
using PowderCoating.Application.DTOs.Notification;
using PowderCoating.Application.Services;
using PowderCoating.Core.Enums;

namespace PowderCoating.Application.DTOs.Company
{
    /// <summary>
    /// Read model for company settings including operating costs
    /// </summary>
    public class CompanySettingsDto
    {
        public int Id { get; set; }
        public string CompanyName { get; set; } = string.Empty;
        public string? CompanyCode { get; set; }
        public string PrimaryContactName { get; set; } = string.Empty;
        public string PrimaryContactEmail { get; set; } = string.Empty;
        public string? Phone { get; set; }
        public string? Address { get; set; }
        public string? City { get; set; }
        public string? State { get; set; }
        public string? ZipCode { get; set; }
        public string? TimeZone { get; set; }
        public AccountingMethod AccountingMethod { get; set; } = AccountingMethod.Accrual;
        public bool HasLogo { get; set; }

        public CompanyOperatingCostsDto? OperatingCosts { get; set; }
        public CompanyPreferencesDto? Preferences { get; set; }
        public bool AiPhotoQuotesEnabled { get; set; }
        public List<NotificationTemplateDto> NotificationTemplates { get; set; } = new();

        // Stripe Connect / online payments
        public StripeConnectStatus StripeConnectStatus { get; set; }
        public string? StripeAccountId { get; set; }
        public OnlinePaymentSurchargeType OnlinePaymentSurchargeType { get; set; }
        public decimal OnlinePaymentSurchargeValue { get; set; }
        public bool OnlineSurchargeAcknowledged { get; set; }
        public bool AllowOnlinePayments { get; set; }

        // SMS gating
        public bool AllowSms { get; set; }
        public bool SmsEnabled { get; set; }
        public bool SmsDisabledByAdmin { get; set; }
        /// <summary>True when the company has an accepted agreement for the current SmsTermsVersion.</summary>
        public bool HasCurrentSmsAgreement { get; set; }
        public string SmsTermsVersion { get; set; } = string.Empty;

        // Timeclock settings
        public bool TimeclockEnabled { get; set; }
        public bool TimeclockAllowMultiplePunchesPerDay { get; set; }
        public int? TimeclockAutoClockOutHours { get; set; }
    }

    /// <summary>DTO for updating company-level timeclock settings from the Settings tab.</summary>
    public class UpdateTimeclockSettingsDto
    {
        public bool TimeclockEnabled { get; set; }
        public bool TimeclockAllowMultiplePunchesPerDay { get; set; }
        [Range(1, 24, ErrorMessage = "Auto clock-out must be between 1 and 24 hours.")]
        public int? TimeclockAutoClockOutHours { get; set; }
    }

    /// <summary>
    /// DTO for the company admin SMS opt-in/out toggle.
    /// When enabling for the first time (or after a terms version change), AgreedToTerms must
    /// be true and TermsVersion must match <c>AppConstants.SmsTermsVersion</c>.
    /// </summary>
    public class UpdateSmsPreferencesDto
    {
        public bool SmsEnabled { get; set; }
        public bool AgreedToTerms { get; set; }
        public string? TermsVersion { get; set; }
    }

    /// <summary>
    /// DTO for updating basic company information
    /// </summary>
    public class UpdateCompanySettingsDto
    {
        [Required(ErrorMessage = "Company name is required")]
        [StringLength(200, ErrorMessage = "Company name cannot exceed 200 characters")]
        public string CompanyName { get; set; } = string.Empty;

        [StringLength(10, ErrorMessage = "Company code cannot exceed 10 characters")]
        public string? CompanyCode { get; set; }

        [Required(ErrorMessage = "Primary contact name is required")]
        [StringLength(100, ErrorMessage = "Contact name cannot exceed 100 characters")]
        public string PrimaryContactName { get; set; } = string.Empty;

        [Required(ErrorMessage = "Primary contact email is required")]
        [EmailAddress(ErrorMessage = "Invalid email format")]
        [StringLength(100, ErrorMessage = "Email cannot exceed 100 characters")]
        public string PrimaryContactEmail { get; set; } = string.Empty;

        [Phone(ErrorMessage = "Invalid phone number format")]
        [StringLength(20, ErrorMessage = "Phone number cannot exceed 20 characters")]
        public string? Phone { get; set; }

        [StringLength(200, ErrorMessage = "Address cannot exceed 200 characters")]
        public string? Address { get; set; }

        [StringLength(100, ErrorMessage = "City cannot exceed 100 characters")]
        public string? City { get; set; }

        [StringLength(2, ErrorMessage = "State must be 2 characters")]
        public string? State { get; set; }

        [StringLength(10, ErrorMessage = "Zip code cannot exceed 10 characters")]
        public string? ZipCode { get; set; }

        [StringLength(50, ErrorMessage = "Time zone cannot exceed 50 characters")]
        public string? TimeZone { get; set; }

        /// <summary>Cash or Accrual accounting method preference for financial reports.</summary>
        public AccountingMethod AccountingMethod { get; set; } = AccountingMethod.Accrual;
    }

    /// <summary>
    /// Read model for company operating costs
    /// </summary>
    public class CompanyOperatingCostsDto
    {
        public int Id { get; set; }
        public int CompanyId { get; set; }

        // Labor Rates
        public decimal StandardLaborRate { get; set; }
        public decimal? LaborCostPerHour { get; set; }
        public decimal AdditionalCoatLaborPercent { get; set; }

        // Equipment Operating Costs
        public decimal OvenOperatingCostPerHour { get; set; }
        public decimal SandblasterCostPerHour { get; set; }
        public decimal CoatingBoothCostPerHour { get; set; }

        // Material Costs
        public decimal PowderCoatingCostPerSqFt { get; set; }

        // Tax
        public decimal TaxPercent { get; set; }

        // Shop Supplies Rate
        public decimal ShopSuppliesRate { get; set; }

        // Markup / Margin
        public PowderCoating.Core.Enums.PricingMode PricingMode { get; set; } = PowderCoating.Core.Enums.PricingMode.MarkupOnMaterial;
        public decimal GeneralMarkupPercentage { get; set; }
        public decimal TargetMarginPercent { get; set; }

        // Rush Charge
        public string RushChargeType { get; set; } = "Percentage"; // "Percentage" or "FixedAmount"
        public decimal RushChargePercentage { get; set; }
        public decimal RushChargeFixedAmount { get; set; }

        // Shop Minimum
        public decimal ShopMinimumCharge { get; set; }

        // Part Complexity Multipliers (%)
        public decimal ComplexitySimplePercent { get; set; }
        public decimal ComplexityModeratePercent { get; set; }
        public decimal ComplexityComplexPercent { get; set; }
        public decimal ComplexityExtremePercent { get; set; }

        // AI Profile
        public string? AiContextProfile { get; set; }

        // Shop Capability
        public ShopCapabilityTier ShopCapabilityTier { get; set; }
        public BlastSetupType BlastSetupType { get; set; }
        public decimal CompressorCfm { get; set; }
        public int BlastNozzleSize { get; set; }
        public BlastSubstrateType PrimaryBlastSubstrate { get; set; }
        public decimal? BlastRateSqFtPerHourOverride { get; set; }
        public CoatingGunType CoatingGunType { get; set; }
        public decimal? CoatingRateSqFtPerHourOverride { get; set; }

        /// <summary>Derived blast rate — shown to the user as a sanity-check value.</summary>
        public decimal DerivedBlastRateSqFtPerHour { get; set; }
        /// <summary>Derived coating rate — shown to the user as a sanity-check value.</summary>
        public decimal DerivedCoatingRateSqFtPerHour { get; set; }

        // Facility Overhead
        public decimal MonthlyRent { get; set; }
        public decimal MonthlyUtilities { get; set; }
        public int MonthlyBillableHours { get; set; } = 160;

        /// <summary>Derived facility overhead rate = (MonthlyRent + MonthlyUtilities) / MonthlyBillableHours.</summary>
        public decimal FacilityOverheadRatePerHour { get; set; }
    }

    /// <summary>
    /// DTO for updating company operating costs
    /// </summary>
    public class UpdateOperatingCostsDto
    {
        // Labor Rates (per hour)
        [Required(ErrorMessage = "Standard labor rate is required")]
        [Range(0, 10000, ErrorMessage = "Standard labor rate must be between 0 and 10,000")]
        [Display(Name = "Standard Labor Rate ($/hr)")]
        public decimal StandardLaborRate { get; set; }

        [Range(0, 10000, ErrorMessage = "Labor cost rate must be between 0 and 10,000")]
        [Display(Name = "Shop Labor Cost Rate ($/hr)")]
        public decimal? LaborCostPerHour { get; set; }

        [Range(0, 100, ErrorMessage = "Additional coat labor percent must be between 0 and 100")]
        [Display(Name = "Additional Coat Labor (%)")]
        public decimal AdditionalCoatLaborPercent { get; set; } = 30m;

        // Equipment Operating Costs (per hour)
        [Required(ErrorMessage = "Oven operating cost is required")]
        [Range(0, 10000, ErrorMessage = "Oven operating cost must be between 0 and 10,000")]
        [Display(Name = "Oven Operating Cost ($/hr)")]
        public decimal OvenOperatingCostPerHour { get; set; }

        [Range(0, 10000, ErrorMessage = "Sandblaster cost must be between 0 and 10,000")]
        [Display(Name = "Sandblaster Cost ($/hr)")]
        public decimal SandblasterCostPerHour { get; set; }

        [Range(0, 10000, ErrorMessage = "Coating booth cost must be between 0 and 10,000")]
        [Display(Name = "Coating Booth Cost ($/hr)")]
        public decimal CoatingBoothCostPerHour { get; set; }

        // Material Costs
        [Range(0, 1000, ErrorMessage = "Powder coating cost must be between 0 and 1,000")]
        [Display(Name = "Powder Coating Cost Per Sq Ft ($/sq ft)")]
        public decimal PowderCoatingCostPerSqFt { get; set; }

        // Tax
        [Range(0, 100, ErrorMessage = "Tax percent must be between 0 and 100")]
        [Display(Name = "Tax Percent (%)")]
        public decimal TaxPercent { get; set; }

        // Shop Supplies Rate
        [Range(0, 100, ErrorMessage = "Shop supplies rate must be between 0 and 100")]
        [Display(Name = "Shop Supplies Rate (%)")]
        public decimal ShopSuppliesRate { get; set; }

        // Markup / Margin Mode
        [Display(Name = "Pricing Mode")]
        public PowderCoating.Core.Enums.PricingMode PricingMode { get; set; } = PowderCoating.Core.Enums.PricingMode.MarkupOnMaterial;

        [Range(0, 100, ErrorMessage = "General markup percentage must be between 0 and 100")]
        [Display(Name = "General Markup (%)")]
        public decimal GeneralMarkupPercentage { get; set; }

        [Range(0, 99, ErrorMessage = "Target margin must be between 0 and 99")]
        [Display(Name = "Target Margin (%)")]
        public decimal TargetMarginPercent { get; set; }

        // Rush Charge
        [StringLength(20, ErrorMessage = "Rush charge type cannot exceed 20 characters")]
        [Display(Name = "Rush Charge Type")]
        public string RushChargeType { get; set; } = "Percentage"; // "Percentage" or "FixedAmount"

        [Range(0, 100, ErrorMessage = "Rush charge percentage must be between 0 and 100")]
        [Display(Name = "Rush Charge (%)")]
        public decimal RushChargePercentage { get; set; }

        [Range(0, 100000, ErrorMessage = "Rush charge fixed amount must be between 0 and 100,000")]
        [Display(Name = "Rush Charge Fixed Amount ($)")]
        public decimal RushChargeFixedAmount { get; set; }

        // Shop Minimum
        [Range(0, 100000, ErrorMessage = "Shop minimum charge must be between 0 and 100,000")]
        [Display(Name = "Shop Minimum Charge ($)")]
        public decimal ShopMinimumCharge { get; set; }

        // Part Complexity Multipliers
        [Range(0, 500)]
        public decimal ComplexitySimplePercent { get; set; } = 0m;

        [Range(0, 500)]
        public decimal ComplexityModeratePercent { get; set; } = 5m;

        [Range(0, 500)]
        public decimal ComplexityComplexPercent { get; set; } = 15m;

        [Range(0, 500)]
        public decimal ComplexityExtremePercent { get; set; } = 25m;

        // Facility Overhead
        [Range(0, 1000000, ErrorMessage = "Monthly rent must be between 0 and 1,000,000")]
        [Display(Name = "Monthly Rent ($)")]
        public decimal MonthlyRent { get; set; } = 0m;

        [Range(0, 1000000, ErrorMessage = "Monthly utilities must be between 0 and 1,000,000")]
        [Display(Name = "Monthly Utilities ($)")]
        public decimal MonthlyUtilities { get; set; } = 0m;

        [Range(1, 10000, ErrorMessage = "Billable hours must be between 1 and 10,000")]
        [Display(Name = "Billable Hours/Month")]
        public int MonthlyBillableHours { get; set; } = 160;
    }

    /// <summary>DTO for updating the company AI profile text used for AI Photo Quote calibration.</summary>
    public class UpdateAiProfileDto
    {
        [StringLength(2000, ErrorMessage = "AI profile cannot exceed 2000 characters")]
        public string? AiContextProfile { get; set; }
    }

    /// <summary>DTO for saving the Quoting Calibration / Shop Capability Profile tab.</summary>
    public class UpdateBlastProfileDto
    {
        public ShopCapabilityTier ShopCapabilityTier { get; set; }
        public BlastSetupType BlastSetupType { get; set; }

        [Range(0, 2000, ErrorMessage = "CFM must be between 0 and 2000")]
        public decimal CompressorCfm { get; set; }

        [Range(3, 8, ErrorMessage = "Nozzle size must be between #3 and #8")]
        public int BlastNozzleSize { get; set; } = 4;

        public BlastSubstrateType PrimaryBlastSubstrate { get; set; }

        [Range(0, 5000, ErrorMessage = "Blast rate override must be between 0 and 5000")]
        public decimal? BlastRateSqFtPerHourOverride { get; set; }

        public CoatingGunType CoatingGunType { get; set; }

        [Range(0, 5000, ErrorMessage = "Coating rate override must be between 0 and 5000")]
        public decimal? CoatingRateSqFtPerHourOverride { get; set; }
    }

    /// <summary>
    /// Response returned after saving or recalculating the blast profile,
    /// so the UI can display the freshly derived rates without a page reload.
    /// </summary>
    public class BlastProfileResultDto
    {
        public decimal DerivedBlastRate { get; set; }
        public decimal DerivedCoatingRate { get; set; }
    }

    // ── Named blast setups ──────────────────────────────────────────────────────

    public class BlastSetupDto
    {
        public int Id { get; set; }
        public string Name { get; set; } = string.Empty;
        public BlastSetupType SetupType { get; set; }
        public decimal CompressorCfm { get; set; }
        public int BlastNozzleSize { get; set; }
        public BlastSubstrateType PrimarySubstrate { get; set; }
        public decimal? BlastRateSqFtPerHourOverride { get; set; }
        public bool IsDefault { get; set; }
        public bool IsActive { get; set; }
        public int DisplayOrder { get; set; }
        public decimal DerivedRate { get; set; }
    }

    public class SaveBlastSetupDto
    {
        public int? Id { get; set; }

        [Required]
        [StringLength(100)]
        public string Name { get; set; } = string.Empty;

        public BlastSetupType SetupType { get; set; }

        [Range(0, 9999)]
        public decimal CompressorCfm { get; set; }

        [Range(2, 8)]
        public int BlastNozzleSize { get; set; } = 5;

        public BlastSubstrateType PrimarySubstrate { get; set; }

        [Range(0, 99999)]
        public decimal? BlastRateSqFtPerHourOverride { get; set; }

        public bool IsDefault { get; set; }
        public bool IsActive { get; set; } = true;
    }

    /// <summary>Lightweight summary injected into wizard pages for the blast-setup dropdown.</summary>
    public class BlastSetupSummaryDto
    {
        public int Id { get; set; }
        public string Name { get; set; } = string.Empty;
        public decimal DerivedRate { get; set; }
        public bool IsDefault { get; set; }
    }
}
