using System.ComponentModel.DataAnnotations;
using ERPCore.Domain.Enums;

namespace ERPCore.Dtos.Hrm;

// --- Salary components ---

public sealed record SalaryComponentDto(
    int SalaryComponentId, string Code, string Name, SalaryComponentType ComponentType,
    bool IsTaxable, bool IsEpfEtfApplicable, EntityStatus Status, DateTime CreatedAt, DateTime? UpdatedAt);

public sealed class CreateSalaryComponentRequest
{
    [Required, StringLength(20)] public string Code { get; set; } = string.Empty;
    [Required, StringLength(200)] public string Name { get; set; } = string.Empty;
    [Required, EnumDataType(typeof(SalaryComponentType))] public SalaryComponentType ComponentType { get; set; }
    public bool IsTaxable { get; set; }
    public bool IsEpfEtfApplicable { get; set; }
}

public sealed class UpdateSalaryComponentRequest
{
    [Required, StringLength(200)] public string Name { get; set; } = string.Empty;
    public bool IsTaxable { get; set; }
    public bool IsEpfEtfApplicable { get; set; }
}

// --- Salary structure ---

public sealed record EmployeeSalaryStructureLineDto(int SalaryComponentId, string? SalaryComponentName, decimal Amount);

public sealed record EmployeeSalaryStructureDto(
    int EmployeeSalaryStructureId, int EmployeeId, DateTime EffectiveFrom, DateTime? EffectiveTo,
    decimal BasicSalary, string Currency, SalaryStructureStatus Status,
    List<EmployeeSalaryStructureLineDto> Lines, DateTime CreatedAt);

public sealed class SalaryStructureLineRequest
{
    [Required] public int SalaryComponentId { get; set; }
    [Range(0, double.MaxValue)] public decimal Amount { get; set; }
}

public sealed class CreateSalaryStructureRequest
{
    [Required] public DateTime EffectiveFrom { get; set; }
    [Range(0, double.MaxValue)] public decimal BasicSalary { get; set; }
    public List<SalaryStructureLineRequest> Lines { get; set; } = new();
}

// --- Loans ---

public sealed record LoanInstallmentDto(
    int LoanInstallmentId, int InstallmentNumber, int DueYear, int DueMonth,
    decimal ScheduledAmount, decimal? PaidAmount, int? PayrollRunId, LoanInstallmentStatus Status);

public sealed record EmployeeLoanDto(
    int EmployeeLoanId, string DocNo, int EmployeeId, LoanKind LoanKind, decimal PrincipalAmount,
    decimal InterestRate, decimal InstallmentAmount, int NumberOfInstallments, int StartYear, int StartMonth,
    decimal OutstandingBalance, LoanStatus Status, List<LoanInstallmentDto> Installments, DateTime CreatedAt);

public sealed class CreateEmployeeLoanRequest
{
    [Required, EnumDataType(typeof(LoanKind))] public LoanKind LoanKind { get; set; }
    [Range(0.01, double.MaxValue)] public decimal PrincipalAmount { get; set; }
    [Range(0, 1)] public decimal InterestRate { get; set; }
    [Range(0.01, double.MaxValue)] public decimal InstallmentAmount { get; set; }
    [Range(1, 360)] public int NumberOfInstallments { get; set; }
    [Range(2000, 2100)] public int StartYear { get; set; }
    [Range(1, 12)] public int StartMonth { get; set; }
}

// --- Statutory settings ---

public sealed record PayrollStatutorySettingDto(
    int PayrollStatutorySettingId, decimal EpfEmployeeRate, decimal EpfEmployerRate, decimal EtfEmployerRate,
    decimal OtMultiplierDefault, DateTime EffectiveFrom, DateTime? EffectiveTo);

public sealed class UpsertPayrollStatutorySettingRequest
{
    [Range(0, 1)] public decimal EpfEmployeeRate { get; set; } = 0.08m;
    [Range(0, 1)] public decimal EpfEmployerRate { get; set; } = 0.12m;
    [Range(0, 1)] public decimal EtfEmployerRate { get; set; } = 0.03m;
    [Range(1, 5)] public decimal OtMultiplierDefault { get; set; } = 1.5m;
    [Required] public DateTime EffectiveFrom { get; set; }
}

public sealed record TaxSlabDto(int TaxSlabId, DateTime EffectiveFrom, DateTime? EffectiveTo, decimal LowerBound, decimal? UpperBound, decimal Rate);

public sealed class CreateTaxSlabRequest
{
    [Required] public DateTime EffectiveFrom { get; set; }
    [Range(0, double.MaxValue)] public decimal LowerBound { get; set; }
    public decimal? UpperBound { get; set; }
    [Range(0, 1)] public decimal Rate { get; set; }
}

// --- Payroll run ---

public sealed record PayrollLineComponentDto(
    PayrollLineComponentCategory ComponentCategory, int? SalaryComponentId, string Label, decimal Amount, int SortOrder);

public sealed record PayrollLineDto(
    int PayrollLineId, int PayrollRunId, int EmployeeId, string? EmployeeCode, string? EmployeeName,
    decimal BasicSalary, decimal TotalAllowances, decimal OvertimeAmount, decimal GrossSalary,
    decimal LateDeductionAmount, decimal NoPayAmount, decimal LoanDeductionAmount,
    decimal EpfEmployeeAmount, decimal EpfEmployerAmount, decimal EtfEmployerAmount,
    decimal TaxAmount, decimal OtherDeductionsAmount, decimal NetSalary,
    int WorkingDays, int PresentDays, int AbsentDays, int LeaveDays, int OtMinutesTotal, int LateMinutesTotal);

public sealed record PayrollLineDetailDto(PayrollLineDto Line, List<PayrollLineComponentDto> Components);

public sealed record PayrollRunDto(
    int PayrollRunId, string DocNo, int PeriodYear, int PeriodMonth, int? BranchId, PayrollRunStatus Status,
    int GeneratedBy, DateTime GeneratedAt, int? ApprovedBy, DateTime? ApprovedAt,
    int? LockedBy, DateTime? LockedAt, int? UnlockedBy, DateTime? UnlockedAt, string? UnlockReason,
    decimal TotalGross, decimal TotalNet, int EmployeeCount);

public sealed class GeneratePayrollRunRequest
{
    [Range(2000, 2100)] public int PeriodYear { get; set; }
    [Range(1, 12)] public int PeriodMonth { get; set; }
    public int? BranchId { get; set; }
}

public sealed class UnlockPayrollRunRequest
{
    [Required, StringLength(500)] public string Reason { get; set; } = string.Empty;
}

public sealed record PayslipDto(int PayslipId, int PayrollLineId, DateTime GeneratedAt, DateTime? ReleasedAt, int? ReleasedBy);
