import {
  City,
  Country,
  Name,
  PostalCode,
  Province,
  Street,
  TINNumber,
  ValidationErrorDetail,
  extractOrPushError,
  maybeFromNullableVO,
} from "@repo/rdx-ddd";

import { IQueryMapperWithBulk, MapperParamsType, SequelizeQueryMapper } from "@erp/core/api";

import { Result } from "@repo/rdx-utils";
import { InvoiceRecipient } from "../../../domain";
import { CustomerInvoiceModel } from "../../sequelize";
import { CustomerInvoiceListDTO } from "./customer-invoice.list.mapper";

interface IInvoiceRecipientListMapper
  extends IQueryMapperWithBulk<CustomerInvoiceModel, InvoiceRecipient> {}

export class InvoiceRecipientListMapper
  extends SequelizeQueryMapper<CustomerInvoiceModel, InvoiceRecipient>
  implements IInvoiceRecipientListMapper
{
  public mapToDTO(
    raw: CustomerInvoiceModel,
    params?: MapperParamsType
  ): Result<InvoiceRecipient, Error> {
    /**
     * - Factura === proforma -> datos de "current_customer"
     * - Factura !== proforma -> snapshot de los datos (campos customer_*)
     */

    const { errors, attributes } = params as {
      errors: ValidationErrorDetail[];
      attributes: Partial<CustomerInvoiceListDTO>;
    };

    const { isProforma } = attributes;

    if (isProforma && !raw.current_customer) {
      errors.push({
        path: "current_customer",
        message: "Current customer not included in query (InvoiceRecipientListMapper)",
      });
    }

    const _name = isProforma ? raw.current_customer.name : raw.customer_name;
    const _tin = isProforma ? raw.current_customer.tin : raw.customer_tin;
    const _street = isProforma ? raw.current_customer.street : raw.customer_street;
    const _street2 = isProforma ? raw.current_customer.street2 : raw.customer_street2;
    const _city = isProforma ? raw.current_customer.city : raw.customer_city;
    const _postal_code = isProforma ? raw.current_customer.postal_code : raw.customer_postal_code;
    const _province = isProforma ? raw.current_customer.province : raw.customer_province;
    const _country = isProforma ? raw.current_customer.country : raw.customer_country;

    // Customer (snapshot)
    const customerName = extractOrPushError(Name.create(_name), "customer_name", errors);

    const customerTin = extractOrPushError(TINNumber.create(_tin), "customer_tin", errors);

    const customerStreet = extractOrPushError(
      maybeFromNullableVO(_street, (value) => Street.create(value)),
      "customer_street",
      errors
    );

    const customerStreet2 = extractOrPushError(
      maybeFromNullableVO(_street2, (value) => Street.create(value)),
      "customer_street2",
      errors
    );

    const customerCity = extractOrPushError(
      maybeFromNullableVO(_city, (value) => City.create(value)),
      "customer_city",
      errors
    );

    const customerProvince = extractOrPushError(
      maybeFromNullableVO(_province, (value) => Province.create(value)),
      "customer_province",
      errors
    );

    const customerPostalCode = extractOrPushError(
      maybeFromNullableVO(_postal_code, (value) => PostalCode.create(value)),
      "customer_postal_code",
      errors
    );

    const customerCountry = extractOrPushError(
      maybeFromNullableVO(_country, (value) => Country.create(value)),
      "customer_country",
      errors
    );

    return InvoiceRecipient.create({
      name: customerName!,
      tin: customerTin!,
      street: customerStreet!,
      street2: customerStreet2!,
      city: customerCity!,
      postalCode: customerPostalCode!,
      province: customerProvince!,
      country: customerCountry!,
    });
  }
}
