using System.Linq;
using CMSMicroservice.Application.CommissionCQ.Commands.TriggerWeeklyCalculation;
using CMSMicroservice.Application.CommissionCQ.Commands.BulkCreditPayouts;
using CMSMicroservice.Application.CommissionCQ.Queries.GetAllWeeklyPools;
using CMSMicroservice.Application.CommissionCQ.Queries.GetUserWeeklyBalances;
using CMSMicroservice.Application.CommissionCQ.Queries.GetMyWeeklyBalances;
using CMSMicroservice.Application.CommissionCQ.Queries.GetAvailableWeeks;
using CMSMicroservice.Application.CommissionCQ.Queries.GetUserCommissionPayouts;
using CMSMicroservice.Application.CommissionCQ.Queries.GetMyCommissionPayouts;
using CMSMicroservice.Application.CommissionCQ.Queries.GetWeekDefinitions;
using CMSMicroservice.Application.Common.Models;
using CMSMicroservice.Domain.Enums;
using CMSMicroservice.Protobuf.Protos.Commission;
using Google.Protobuf.WellKnownTypes;
using Mapster;
using AppWeekFilter = CMSMicroservice.Application.CommissionCQ.Queries.GetWeekDefinitions.GetWeekDefinitionsFilter;

namespace CMSMicroservice.WebApi.Common.Mappings;

public class CommissionProfile : IRegister
{
    public void Register(TypeAdapterConfig config)
    {
        // BulkCreditPayouts Request Mapping (proto → command)
        config.NewConfig<BulkCreditPayoutsRequest, BulkCreditPayoutsCommand>()
            .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId);

        // BulkCreditPayouts Response Mapping (result → proto)
        config.NewConfig<BulkCreditPayoutsResult, BulkCreditPayoutsResponse>()
            .Map(dest => dest.CreditedCount, src => src.CreditedCount)
            .Map(dest => dest.TotalCredited, src => src.TotalCredited)
            .Map(dest => dest.Message, src => $"{src.CreditedCount} کاربر، مجموعاً {src.TotalCredited:N0} ریال به کیف پول واریز شد");

        // GetAvailableWeeks Request Mapping
        config.NewConfig<GetAvailableWeeksRequest, GetAvailableWeeksQuery>()
            .Map(dest => dest.FutureWeeksCount, src => src.FutureWeeksCount > 0 ? src.FutureWeeksCount : 4)
            .Map(dest => dest.PastWeeksCount, src => src.PastWeeksCount > 0 ? src.PastWeeksCount : 12);

        // TriggerWeeklyCalculation Request Mapping (proto → command)
        config.NewConfig<TriggerWeeklyCalculationRequest, CMSMicroservice.Application.CommissionCQ.Commands.TriggerWeeklyCalculation.TriggerWeeklyCalculationCommand>()
            .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId)
            .Map(dest => dest.ForceRecalculate, src => src.ForceRecalculate)
            .Map(dest => dest.SkipBalances, src => src.SkipBalances)
            .Map(dest => dest.SkipPayouts, src => src.SkipPayouts)
            .Map(dest => dest.PackageId, src => src.PackageId != null ? src.PackageId.Value : (long?)null);

        // GetWeeklyCommissionPool Request Mapping
        config.NewConfig<GetWeeklyCommissionPoolRequest, CMSMicroservice.Application.CommissionCQ.Queries.GetWeeklyCommissionPool.GetWeeklyCommissionPoolQuery>()
            .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId)
            .Map(dest => dest.PackageId, src => src.PackageId != null ? src.PackageId.Value : (long?)null);

        // GetWeeklyCommissionPool Response Mapping
        config.NewConfig<CMSMicroservice.Application.CommissionCQ.Queries.GetWeeklyCommissionPool.WeeklyCommissionPoolDto, GetWeeklyCommissionPoolResponse>()
            .Map(dest => dest.Id, src => src.Id)
            .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId)
            .Map(dest => dest.TotalPoolAmount, src => src.TotalPoolAmount)
            .Map(dest => dest.TotalBalances, src => (int)src.TotalBalances)
            .Map(dest => dest.ValuePerBalance, src => (long)src.ValuePerBalance)
            .Map(dest => dest.IsCalculated, src => src.IsCalculated)
            .Map(dest => dest.CalculatedAt, src => src.CalculatedAt.HasValue 
                ? Timestamp.FromDateTime(DateTime.SpecifyKind(src.CalculatedAt.Value, DateTimeKind.Utc)) 
                : null)
            .Map(dest => dest.Created, src => Timestamp.FromDateTimeOffset(src.Created))
            .Map(dest => dest.PackageId, src => src.PackageId)
            .Map(dest => dest.PackageTitle, src => src.PackageTitle)
            .Map(dest => dest.ValidationIsValid, src => src.ValidationIsValid)
            .Map(dest => dest.ValidationExpectedAmount, src => src.ValidationExpectedAmount)
            .Map(dest => dest.ValidationDiscrepancy, src => src.ValidationDiscrepancy)
            .Map(dest => dest.ValidationActivationCount, src => src.ValidationActivationCount);

        // GetAvailableWeeks Response Mapping
        config.NewConfig<GetAvailableWeeksResponseDto, GetAvailableWeeksResponse>()
            .Map(dest => dest.CurrentWeek, src => src.CurrentWeek)
            .Map(dest => dest.CalculatedWeeks, src => src.CalculatedWeeks)
            .Map(dest => dest.PendingWeeks, src => src.PendingWeeks)
            .Map(dest => dest.FutureWeeks, src => src.FutureWeeks);

        // WeekInfo Mapping
        config.NewConfig<WeekInfoDto, WeekInfo>()
            .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId)
            .Map(dest => dest.DisplayName, src => src.DisplayName)
            .Map(dest => dest.StartDate, src => Timestamp.FromDateTime(src.StartDate.ToUniversalTime()))
            .Map(dest => dest.EndDate, src => Timestamp.FromDateTime(src.EndDate.ToUniversalTime()))
            .Map(dest => dest.IsCalculated, src => src.IsCalculated)
            .Map(dest => dest.CalculatedAt, src => src.CalculatedAt.HasValue 
                ? Timestamp.FromDateTime(src.CalculatedAt.Value.ToUniversalTime()) 
                : null)

            .Map(dest => dest.LastExecutionStatus, src => src.LastExecutionStatus ?? string.Empty)
            .Map(dest => dest.TotalPoolAmount, src => src.TotalPoolAmount ?? 0)
            .Map(dest => dest.EligibleUsersCount, src => src.EligibleUsersCount ?? 0)
            .Map(dest => dest.DisplayText, src => src.DisplayText);

        // GetUserCommissionPayouts Response Model Mapping
        config.NewConfig<GetUserCommissionPayoutsResponseModel, UserCommissionPayoutModel>()
            .Map(dest => dest.Id, src => src.Id)
            .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId)
            .Map(dest => dest.UserId, src => src.UserId)
            .Map(dest => dest.UserName, src => $"{src.FirstName} {src.LastName}")
            .Map(dest => dest.WeekDisplayName, src => src.WeekDisplayName)
            .Map(dest => dest.WeeklyPoolId, src => src.WeeklyPoolId)
            .Map(dest => dest.BalancesEarned, src => src.BalancesEarned)
            .Map(dest => dest.ValuePerBalance, src => src.ValuePerBalance)
            .Map(dest => dest.TotalAmount, src => src.TotalAmount)
            .Map(dest => dest.Status, src => (int)src.Status)
            .Map(dest => dest.PaidAt, src => src.PaidAt.HasValue 
                ? Timestamp.FromDateTime(src.PaidAt.Value.ToUniversalTime()) 
                : null)
            .Map(dest => dest.WithdrawalMethod, src => src.WithdrawalMethod.HasValue 
                ? (int)src.WithdrawalMethod.Value 
                : (int?)null)
            .Map(dest => dest.IbanNumber, src => src.IbanNumber ?? string.Empty)
            .Map(dest => dest.WithdrawnAt, src => src.WithdrawnAt.HasValue 
                ? Timestamp.FromDateTime(src.WithdrawnAt.Value.ToUniversalTime()) 
                : null)
            .Map(dest => dest.Created, src => Timestamp.FromDateTimeOffset(src.Created))
            .Map(dest => dest.PackageId, src => src.PackageId)
            .Map(dest => dest.PackageTitle, src => src.PackageTitle);

        // GetWeekDefinitions Request Mapping
        config.NewConfig<GetWeekDefinitionsRequest, GetWeekDefinitionsQuery>()
            .Map(dest => dest.PaginationState, src => src.PaginationState != null 
                ? new PaginationState { PageNumber = src.PaginationState.PageNumber, PageSize = src.PaginationState.PageSize } 
                : null)
            .Map(dest => dest.SortBy, src => src.SortBy)
            .Map(dest => dest.Filter, src => src.Filter != null 
                ? new AppWeekFilter
                {
                    SearchText = src.Filter.SearchText,
                    WeekOrder = src.Filter.WeekOrder,
                    GregorianWeekNumber = src.Filter.GregorianWeekNumber,
                    PersianWeekNumber = src.Filter.PersianWeekNumber,
                    GregorianYear = src.Filter.GregorianYear,
                    PersianYear = src.Filter.PersianYear,
                    IsActive = src.Filter.IsActive
                } 
                : null);

        // GetAllWeeklyPools Request Mapping
        config.NewConfig<GetAllWeeklyPoolsRequest, GetAllWeeklyPoolsQuery>()
            .Map(dest => dest.FromWeekDefinitionId, src => src.FromWeekDefinitionId != null ? src.FromWeekDefinitionId.Value : (long?)null)
            .Map(dest => dest.ToWeekDefinitionId, src => src.ToWeekDefinitionId != null ? src.ToWeekDefinitionId.Value : (long?)null)
            .Map(dest => dest.OnlyCalculated, src => src.OnlyCalculated != null ? src.OnlyCalculated.Value : (bool?)null)
            .Map(dest => dest.PackageId, src => src.PackageId != null ? src.PackageId.Value : (long?)null)
            .Map(dest => dest.PageIndex, src => src.PageIndex > 0 ? src.PageIndex : 1)
            .Map(dest => dest.PageSize, src => src.PageSize > 0 ? src.PageSize : 10);

        // GetAllWeeklyPools Response Mapping
        config.NewConfig<GetAllWeeklyPoolsResponseDto, GetAllWeeklyPoolsResponse>()
            .Map(dest => dest.MetaData, src => src.MetaData != null 
                ? new CMSMicroservice.Protobuf.Protos.MetaData 
                  { 
                    TotalCount = src.MetaData.TotalCount, 
                    PageSize = src.MetaData.PageSize, 
                    CurrentPage = src.MetaData.CurrentPage, 
                    TotalPage = src.MetaData.TotalPages 
                  }
                : new CMSMicroservice.Protobuf.Protos.MetaData())
            .Map(dest => dest.Models, src => src.Models);

        // WeeklyCommissionPoolDto → WeeklyCommissionPoolModel
        config.NewConfig<WeeklyCommissionPoolDto, WeeklyCommissionPoolModel>()
            .Map(dest => dest.Id, src => src.Id)
            .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId)
            .Map(dest => dest.WeekDisplayName, src => src.WeekDisplayName)
            .Map(dest => dest.TotalPoolAmount, src => src.TotalPoolAmount)
            .Map(dest => dest.TotalBalances, src => src.TotalBalances)
            .Map(dest => dest.ValuePerBalance, src => src.ValuePerBalance)
            .Map(dest => dest.IsCalculated, src => src.IsCalculated)
            .Map(dest => dest.CalculatedAt, src => src.CalculatedAt.HasValue 
                ? Timestamp.FromDateTime(DateTime.SpecifyKind(src.CalculatedAt.Value, DateTimeKind.Utc)) 
                : null)
            .Map(dest => dest.Created, src => Timestamp.FromDateTime(DateTime.SpecifyKind(src.Created, DateTimeKind.Utc)))
            .Map(dest => dest.PackageId, src => src.PackageId)
            .Map(dest => dest.PackageTitle, src => src.PackageTitle);

        // GetWeekDefinitions Response Mapping
        config.NewConfig<GetWeekDefinitionsResponseDto, GetWeekDefinitionsResponse>()
            .Map(dest => dest.TotalCount, src => src.TotalCount)
            .Map(dest => dest.Data, src => src.Data);

        // WeekDefinitionItem Mapping
        config.NewConfig<WeekDefinitionItemDto, WeekDefinitionItem>()
            .Map(dest => dest.Id, src => src.Id)
            .Map(dest => dest.WeekOrder, src => src.WeekOrder)
            .Map(dest => dest.DisplayName, src => src.DisplayName)
            .Map(dest => dest.GregorianWeekNumber, src => src.GregorianWeekNumber)
            .Map(dest => dest.PersianWeekNumber, src => src.PersianWeekNumber)
            .Map(dest => dest.StartDate, src => Timestamp.FromDateTime(DateTime.SpecifyKind(src.StartDate, DateTimeKind.Utc)))
            .Map(dest => dest.EndDate, src => Timestamp.FromDateTime(DateTime.SpecifyKind(src.EndDate, DateTimeKind.Utc)))
            .Map(dest => dest.GregorianYear, src => src.GregorianYear)
            .Map(dest => dest.PersianYear, src => src.PersianYear)
            .Map(dest => dest.IsActive, src => src.IsActive)
            .Map(dest => dest.IsCurrentWeek, src => src.IsCurrentWeek);

        // GetUserWeeklyBalances Response Model Mapping
        config.NewConfig<GetUserWeeklyBalancesResponseModel, UserWeeklyBalanceModel>()
            .Map(dest => dest.Id, src => src.Id)
            .Map(dest => dest.UserId, src => src.UserId)
            .Map(dest => dest.UserFullName, src => src.UserFullName)
            .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId)
            .Map(dest => dest.WeekDisplayName, src => src.WeekDisplayName)
            .Map(dest => dest.LeftLegNewMembers, src => src.LeftLegNewMembers)
            .Map(dest => dest.LeftLegCarryover, src => src.LeftLegCarryover)
            .Map(dest => dest.LeftLegTotal, src => src.LeftLegTotal)
            .Map(dest => dest.RightLegNewMembers, src => src.RightLegNewMembers)
            .Map(dest => dest.RightLegCarryover, src => src.RightLegCarryover)
            .Map(dest => dest.RightLegTotal, src => src.RightLegTotal)
            .Map(dest => dest.TotalBalances, src => src.TotalBalances)
            .Map(dest => dest.WeeklyPoolContribution, src => src.WeeklyPoolContribution)
            .Map(dest => dest.CalculatedAt, src => src.CalculatedAt.HasValue 
                ? Timestamp.FromDateTime(DateTime.SpecifyKind(src.CalculatedAt.Value, DateTimeKind.Utc)) 
                : null)
            .Map(dest => dest.IsExpired, src => src.IsExpired)
            .Map(dest => dest.Created, src => Timestamp.FromDateTimeOffset(src.Created))
            .Map(dest => dest.PackageId, src => src.PackageId)
            .Map(dest => dest.PackageTitle, src => src.PackageTitle);

        // GetMyCommissionPayouts Request Mapping
        config.NewConfig<GetMyCommissionPayoutsRequest, GetMyCommissionPayoutsQuery>()
            .Map(dest => dest.Status, src => src.Status != null && src.Status.Value >= 0 
                ? (CommissionPayoutStatus?)src.Status.Value 
                : null)
            .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId != null ? src.WeekDefinitionId.Value : (long?)null)
            .Map(dest => dest.PackageId, src => src.PackageId != null ? src.PackageId.Value : (long?)null)
            .Map(dest => dest.PaginationState, src => new PaginationState 
            { 
                PageNumber = src.PageNumber > 0 ? src.PageNumber : 1, 
                PageSize = src.PageSize > 0 ? src.PageSize : 10 
            });

        // GetMyCommissionPayouts Response Mapping
        config.NewConfig<GetMyCommissionPayoutsResponseDto, GetMyCommissionPayoutsResponse>()
            .Map(dest => dest.MetaData, src => src.MetaData != null 
                ? new CustomerMetaData { TotalCount = src.MetaData.TotalCount } 
                : new CustomerMetaData())
            .Map(dest => dest.Payouts, src => src.Models);

        // CustomerCommissionPayoutModel Mapping
        config.NewConfig<GetMyCommissionPayoutsResponseModel, CustomerCommissionPayoutModel>()
            .Map(dest => dest.Id, src => src.Id)
            .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId)
            .Map(dest => dest.WeekDisplayName, src => src.WeekDisplayName)
            .Map(dest => dest.BalancesEarned, src => src.BalancesEarned)
            .Map(dest => dest.TotalAmount, src => src.TotalAmount)
            .Map(dest => dest.AmountFormatted, src => src.AmountFormatted)
            .Map(dest => dest.Status, src => (int)src.Status)
            .Map(dest => dest.CalculatedDate, src => src.CalculatedDate.HasValue 
                ? Timestamp.FromDateTime(src.CalculatedDate.Value.ToUniversalTime()) 
                : null)
            .Map(dest => dest.DatePersian, src => src.DatePersian)
            .Map(dest => dest.PackageId, src => src.PackageId)
            .Map(dest => dest.PackageTitle, src => src.PackageTitle);

        // GetMyWeeklyBalances Request Mapping
        config.NewConfig<GetMyWeeklyBalancesRequest, GetMyWeeklyBalancesQuery>()
            .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId != null ? src.WeekDefinitionId.Value : (long?)null)
            .Map(dest => dest.OnlyActive, src => src.OnlyActive)
            .Map(dest => dest.PackageId, src => src.PackageId != null ? src.PackageId.Value : (long?)null)
            .Map(dest => dest.PaginationState, src => new PaginationState 
            { 
                PageNumber = src.PageNumber > 0 ? src.PageNumber : 1, 
                PageSize = src.PageSize > 0 ? src.PageSize : 10 
            });

        // GetMyWeeklyBalances Response Mapping
        config.NewConfig<GetUserWeeklyBalancesResponseDto, GetMyWeeklyBalancesResponse>()
            .Map(dest => dest.MetaData, src => src.MetaData != null 
                ? new CustomerMetaData { TotalCount = src.MetaData.TotalCount } 
                : new CustomerMetaData())
            .Map(dest => dest.Balances, src => src.Models)
            .Map(dest => dest.TotalLeftBalances, src => src.Models.Sum(m => m.LeftLegTotal))
            .Map(dest => dest.TotalRightBalances, src => src.Models.Sum(m => m.RightLegTotal))
            .Map(dest => dest.WeakerLeg, src => 
                src.Models.Sum(m => m.LeftLegTotal) < src.Models.Sum(m => m.RightLegTotal) 
                ? "Left" 
                : src.Models.Sum(m => m.LeftLegTotal) > src.Models.Sum(m => m.RightLegTotal) 
                    ? "Right" 
                    : "Equal");

        // CustomerWeeklyBalanceModel Mapping
        config.NewConfig<GetUserWeeklyBalancesResponseModel, CustomerWeeklyBalanceModel>()
            .Map(dest => dest.Id, src => src.Id)
            .Map(dest => dest.WeekDefinitionId, src => src.WeekDefinitionId)
            .Map(dest => dest.WeekDisplayName, src => src.WeekDisplayName)
            .Map(dest => dest.LeftLegBalances, src => src.LeftLegTotal)
            .Map(dest => dest.RightLegBalances, src => src.RightLegTotal)
            .Map(dest => dest.TotalBalances, src => src.TotalBalances)
            .Map(dest => dest.WeeklyPoolContribution, src => src.WeeklyPoolContribution)
            .Map(dest => dest.IsExpired, src => src.IsExpired)
            .Map(dest => dest.CalculatedAt, src => src.CalculatedAt.HasValue 
                ? Timestamp.FromDateTime(DateTime.SpecifyKind(src.CalculatedAt.Value, DateTimeKind.Utc)) 
                : null)
            .Map(dest => dest.PackageId, src => src.PackageId)
            .Map(dest => dest.PackageTitle, src => src.PackageTitle);
    }
}
