using CashLineERP.Application.Customers;
using CashLineERP.Application.Identity;
using CashLineERP.Application.Parties;
using CashLineERP.Application.Suppliers;
using CashLineERP.Contracts.Customers;
using CashLineERP.Contracts.External;
using CashLineERP.Contracts.Parties;
using CashLineERP.Contracts.Suppliers;

namespace CashLineERP.Application.External;

public sealed class InternalOnboardingIntakeService : IInternalOnboardingIntakeService
{
    private readonly IPartyOnboardingService _partyOnboardingService;
    private readonly ISupplierProfileService _supplierProfileService;
    private readonly ICustomerProfileService _customerProfileService;
    private readonly IIdentityReadRepository _identityReadRepository;

    public InternalOnboardingIntakeService(
        IPartyOnboardingService partyOnboardingService,
        ISupplierProfileService supplierProfileService,
        ICustomerProfileService customerProfileService,
        IIdentityReadRepository identityReadRepository)
    {
        _partyOnboardingService = partyOnboardingService;
        _supplierProfileService = supplierProfileService;
        _customerProfileService = customerProfileService;
        _identityReadRepository = identityReadRepository;
    }

    public PublicSupplierOnboardingApplicationResponse CreateSupplierApplication(CreateInternalSupplierOnboardingRequest request, long actorUserId)
    {
        var actorContext = ResolveActorContext(actorUserId);
        var partyName = ResolvePartyName(
            request.PartyName,
            request.Email,
            $"{actorContext.PartyNameFallback} Supplier");

        var party = _partyOnboardingService.CreateParty(new CreateBusinessPartyRequest(
            GeneratePartyCode("SUP", actorContext.PartyCodeSegment),
            partyName,
            "SUPPLIER",
            request.CountryCode,
            request.FirmNationalId,
            request.TaxRegistrationNumber,
            request.TaxBranchCode,
            request.Email,
            request.MobileNumber,
            request.AddressLine1,
            null,
            null,
            false,
            null));

        var profile = _supplierProfileService.CreateSupplierProfile(new CreateSupplierProfileRequest(
            party.PartyId,
            request.FirmNationalId,
            request.SupplierCategoryCode,
            request.DefaultCurrencyCode,
            request.PreferredPaymentMethodCode,
            request.PaymentTermsDays,
            request.LeadTimeDays,
            request.MinimumOrderAmount,
            request.BankName,
            request.BankAccountNumber,
            request.BankSwiftCode,
            request.Notes));

        var submitted = _supplierProfileService.SubmitSupplierProfile(profile.SupplierProfileId, actorUserId);

        return new PublicSupplierOnboardingApplicationResponse(
            party.PartyId,
            party.PartyCode,
            party.PartyName,
            submitted.SupplierProfileId,
            submitted.SupplierProfileCode,
            submitted.StatusCode,
            submitted.ComplianceStatusCode,
            submitted.ComplianceDocumentCount,
            actorContext.SupplierReviewStatusMessage);
    }

    public PublicCustomerOnboardingApplicationResponse CreateCustomerApplication(CreateInternalCustomerOnboardingRequest request, long actorUserId)
    {
        var actorContext = ResolveActorContext(actorUserId);
        var partyName = ResolvePartyName(
            request.PartyName,
            request.Email,
            $"{actorContext.PartyNameFallback} Customer");

        var party = _partyOnboardingService.CreateParty(new CreateBusinessPartyRequest(
            GeneratePartyCode("CUS", actorContext.PartyCodeSegment),
            partyName,
            "CUSTOMER",
            request.CountryCode,
            request.FirmNationalId,
            request.TaxRegistrationNumber,
            request.TaxBranchCode,
            request.Email,
            request.MobileNumber,
            request.AddressLine1,
            request.CreditLimitAmount,
            request.CreditTermsDays,
            false,
            null));

        var profile = _customerProfileService.CreateCustomerProfile(new CreateCustomerProfileRequest(
            party.PartyId,
            request.FirmNationalId,
            request.CustomerClassificationCode,
            request.CustomerSegmentCode,
            request.DefaultCurrencyCode,
            request.SalesChannelCode,
            request.PriceTierCode,
            request.InvoiceDeliveryMethodCode,
            request.Notes));

        var submitted = _customerProfileService.SubmitCustomerProfile(profile.CustomerProfileId, actorUserId);

        return new PublicCustomerOnboardingApplicationResponse(
            party.PartyId,
            party.PartyCode,
            party.PartyName,
            submitted.CustomerProfileId,
            submitted.CustomerProfileCode,
            submitted.StatusCode,
            submitted.TaxProfileStatusCode,
            submitted.ComplianceDocumentCount,
            actorContext.CustomerReviewStatusMessage);
    }

    private ActorContext ResolveActorContext(long actorUserId)
    {
        var actor = _identityReadRepository.FindByUserId(actorUserId);
        var isAccountingOffice = actor?.RoleCodes.Any(roleCode =>
            string.Equals(roleCode, "ACCOUNTING_OFFICE_USER", StringComparison.OrdinalIgnoreCase)
            || string.Equals(roleCode, "ACCOUNTING_OFFICE_SUPERVISOR", StringComparison.OrdinalIgnoreCase)) == true;

        if (isAccountingOffice)
        {
            var actorName = string.IsNullOrWhiteSpace(actor?.DisplayName)
                ? actor?.LoginName ?? "Accounting Office"
                : actor.DisplayName;
            return new ActorContext(
                PartyCodeSegment: "AO",
                PartyNameFallback: "Accounting Office Intake",
                SupplierReviewStatusMessage: $"Supplier onboarding case created by accounting office {actorName} and submitted for CashLine Operations review.",
                CustomerReviewStatusMessage: $"Customer onboarding case created by accounting office {actorName} and submitted for CashLine Operations review.");
        }

        return new ActorContext(
            PartyCodeSegment: "OPS",
            PartyNameFallback: "Operations Intake",
            SupplierReviewStatusMessage: "Supplier onboarding case created by CashLine Operations and submitted for review.",
            CustomerReviewStatusMessage: "Customer onboarding case created by CashLine Operations and submitted for review.");
    }

    private static string GeneratePartyCode(string prefix, string sourceSegment)
    {
        var suffix = $"{DateTime.UtcNow:yyMMddHHmmss}{Guid.NewGuid():N}"[..12];
        return $"{prefix}-{sourceSegment}-{suffix}";
    }

    private static string ResolvePartyName(string? requestedPartyName, string? email, string fallback)
    {
        if (!string.IsNullOrWhiteSpace(requestedPartyName))
        {
            return requestedPartyName.Trim();
        }

        if (!string.IsNullOrWhiteSpace(email))
        {
            return email.Trim();
        }

        return fallback;
    }

    private sealed record ActorContext(
        string PartyCodeSegment,
        string PartyNameFallback,
        string SupplierReviewStatusMessage,
        string CustomerReviewStatusMessage);
}
