import {
  City,
  Country,
  CurrencyCode,
  DomainError,
  EmailAddress,
  LanguageCode,
  Name,
  PhoneNumber,
  PostalAddress,
  PostalCode,
  Province,
  Street,
  TINNumber,
  TaxCode,
  TextValue,
  URLAddress,
  UniqueID,
  ValidationErrorCollection,
  ValidationErrorDetail,
  extractOrPushError,
  maybeFromNullableVO,
} from "@repo/rdx-ddd";
import { Collection, Result, isNullishOrEmpty } from "@repo/rdx-utils";
import { CreateCustomerRequestDTO } from "../../../../common";
import { CustomerProps, CustomerStatus } from "../../../domain";

/**
 * Convierte el DTO a las props validadas (CustomerProps).
 * No construye directamente el agregado.
 *
 * @param dto - DTO con los datos de la factura de cliente
 * @returns 
 
 *
 */

export function mapDTOToCreateCustomerProps(dto: CreateCustomerRequestDTO) {
  try {
    const errors: ValidationErrorDetail[] = [];

    const customerId = extractOrPushError(UniqueID.create(dto.id), "id", errors);

    const status = CustomerStatus.createActive();
    const isCompany = dto.is_company === "true";

    const reference = extractOrPushError(
      maybeFromNullableVO(dto.reference, (value) => Name.create(value)),
      "reference",
      errors
    );

    const name = extractOrPushError(Name.create(dto.name), "name", errors);

    const tradeName = extractOrPushError(
      maybeFromNullableVO(dto.trade_name, (value) => Name.create(value)),
      "trade_name",
      errors
    );

    const tinNumber = extractOrPushError(
      maybeFromNullableVO(dto.tin, (value) => TINNumber.create(value)),
      "tin",
      errors
    );

    const street = extractOrPushError(
      maybeFromNullableVO(dto.street, (value) => Street.create(value)),
      "street",
      errors
    );

    const street2 = extractOrPushError(
      maybeFromNullableVO(dto.street2, (value) => Street.create(value)),
      "street2",
      errors
    );

    const city = extractOrPushError(
      maybeFromNullableVO(dto.city, (value) => City.create(value)),
      "city",
      errors
    );

    const province = extractOrPushError(
      maybeFromNullableVO(dto.province, (value) => Province.create(value)),
      "province",
      errors
    );

    const postalCode = extractOrPushError(
      maybeFromNullableVO(dto.postal_code, (value) => PostalCode.create(value)),
      "postal_code",
      errors
    );

    const country = extractOrPushError(
      maybeFromNullableVO(dto.country, (value) => Country.create(value)),
      "country",
      errors
    );

    const primaryEmailAddress = extractOrPushError(
      maybeFromNullableVO(dto.email_primary, (value) => EmailAddress.create(value)),
      "email_primary",
      errors
    );

    const secondaryEmailAddress = extractOrPushError(
      maybeFromNullableVO(dto.email_secondary, (value) => EmailAddress.create(value)),
      "email_secondary",
      errors
    );

    const primaryPhoneNumber = extractOrPushError(
      maybeFromNullableVO(dto.phone_primary, (value) => PhoneNumber.create(value)),
      "phone_primary",
      errors
    );

    const secondaryPhoneNumber = extractOrPushError(
      maybeFromNullableVO(dto.phone_secondary, (value) => PhoneNumber.create(value)),
      "phone_secondary",
      errors
    );

    const primaryMobileNumber = extractOrPushError(
      maybeFromNullableVO(dto.mobile_primary, (value) => PhoneNumber.create(value)),
      "mobile_primary",
      errors
    );

    const secondaryMobileNumber = extractOrPushError(
      maybeFromNullableVO(dto.mobile_secondary, (value) => PhoneNumber.create(value)),
      "mobile_secondary",
      errors
    );

    const faxNumber = extractOrPushError(
      maybeFromNullableVO(dto.fax, (value) => PhoneNumber.create(value)),
      "fax",
      errors
    );

    const website = extractOrPushError(
      maybeFromNullableVO(dto.website, (value) => URLAddress.create(value)),
      "website",
      errors
    );

    const legalRecord = extractOrPushError(
      maybeFromNullableVO(dto.legal_record, (value) => TextValue.create(value)),
      "legal_record",
      errors
    );

    const languageCode = extractOrPushError(
      LanguageCode.create(dto.language_code),
      "language_code",
      errors
    );

    const currencyCode = extractOrPushError(
      CurrencyCode.create(dto.currency_code),
      "currency_code",
      errors
    );

    const defaultTaxes = new Collection<TaxCode>();

    if (!isNullishOrEmpty(dto.default_taxes)) {
      dto.default_taxes!.map((taxCode, index) => {
        const tax = extractOrPushError(TaxCode.create(taxCode), `default_taxes.${index}`, errors);
        if (tax) {
          defaultTaxes.add(tax!);
        }
      });
    }

    if (errors.length > 0) {
      return Result.fail(new ValidationErrorCollection("Customer props mapping failed", errors));
    }

    const postalAddressProps = {
      street: street!,
      street2: street2!,
      city: city!,
      postalCode: postalCode!,
      province: province!,
      country: country!,
    };

    const postalAddress = extractOrPushError(
      PostalAddress.create(postalAddressProps),
      "address",
      errors
    );

    const customerProps: Omit<CustomerProps, "companyId"> = {
      status: status!,
      reference: reference!,

      isCompany: isCompany,
      name: name!,
      tradeName: tradeName!,
      tin: tinNumber!,

      address: postalAddress!,

      emailPrimary: primaryEmailAddress!,
      emailSecondary: secondaryEmailAddress!,
      phonePrimary: primaryPhoneNumber!,
      phoneSecondary: secondaryPhoneNumber!,
      mobilePrimary: primaryMobileNumber!,
      mobileSecondary: secondaryMobileNumber!,

      fax: faxNumber!,
      website: website!,

      legalRecord: legalRecord!,
      defaultTaxes: defaultTaxes!,
      languageCode: languageCode!,
      currencyCode: currencyCode!,
    };

    return Result.ok({ id: customerId!, props: customerProps });
  } catch (err: unknown) {
    return Result.fail(new DomainError("Customer props mapping failed", { cause: err }));
  }
}
