import { ISequelizeMapper, SequelizeMapper } from "@/contexts/common/infrastructure";
import {
  City,
  Country,
  Email,
  Note,
  Phone,
  PostalCode,
  Province,
  Street,
  UniqueID,
} from "@shared/contexts";
import {
  IInvoiceParticipantAddressProps,
  InvoiceCustomer,
  InvoiceParticipantAddress,
} from "../../domain";
import { IInvoicingContext } from "../InvoicingContext";
import {
  InvoiceParticipantAddress_Model,
  TCreationInvoiceParticipantAddress_Model,
} from "../sequelize";

export interface IInvoiceParticipantAddressMapper
  extends ISequelizeMapper<
    InvoiceParticipantAddress_Model,
    TCreationInvoiceParticipantAddress_Model,
    InvoiceParticipantAddress
  > {}

export const createInvoiceParticipantAddressMapper = (
  context: IInvoicingContext
): IInvoiceParticipantAddressMapper => new InvoiceParticipantAddressMapper({ context });

class InvoiceParticipantAddressMapper
  extends SequelizeMapper<
    InvoiceParticipantAddress_Model,
    TCreationInvoiceParticipantAddress_Model,
    InvoiceParticipantAddress
  >
  implements IInvoiceParticipantAddressMapper
{
  protected toDomainMappingImpl(source: InvoiceParticipantAddress_Model, params: any) {
    const id = this.mapsValue(source, "address_id", UniqueID.create);

    const props: IInvoiceParticipantAddressProps = {
      type: source.type,
      street: this.mapsValue(source, "street", Street.create),
      city: this.mapsValue(source, "city", City.create),
      province: this.mapsValue(source, "province", Province.create),
      postalCode: this.mapsValue(source, "postal_code", PostalCode.create),
      country: this.mapsValue(source, "country", Country.create),
      email: this.mapsValue(source, "email", Email.create),
      phone: this.mapsValue(source, "phone", Phone.create),
      notes: this.mapsValue(source, "notes", Note.create),
    };

    const addressOrError = InvoiceParticipantAddress.create(props, id);

    if (addressOrError.isFailure) {
      throw addressOrError.error;
    }

    return addressOrError.object;
  }

  protected toPersistenceMappingImpl(
    source: InvoiceParticipantAddress,
    params: { sourceParent: InvoiceCustomer }
  ) {
    const { sourceParent } = params;

    return {
      address_id: source.id.toPrimitive(),
      participant_id: sourceParent.id.toPrimitive(),
      type: String(source.type),
      title: source.title,
      street: source.street.toPrimitive(),
      city: source.city.toPrimitive(),
      postal_code: source.postalCode.toPrimitive(),
      province: source.province.toPrimitive(),
      country: source.country.toPrimitive(),
      email: source.email.toPrimitive(),
      phone: source.phone.toPrimitive(),
    };
  }
}
