import {
  EmailAddress,
  PhoneNumber,
  PostalAddress,
  TINNumber,
  UniqueID,
} from "@/core/common/domain";
import {
  type ISequelizeMapper,
  type MapperParamsType,
  SequelizeMapper,
} from "@/core/common/infrastructure/sequelize/sequelize-mapper";
import { Maybe, Result } from "@repo/rdx-utils";
import { Contact } from "../../domain";
import { ContactCreationAttributes, ContactModel } from "../sequelize/contact.model";

export interface IContactMapper
  extends ISequelizeMapper<ContactModel, ContactCreationAttributes, Contact> {}

export class ContactMapper
  extends SequelizeMapper<ContactModel, ContactCreationAttributes, Contact>
  implements IContactMapper
{
  public mapToDomain(source: ContactModel, params?: MapperParamsType): Result<Contact, Error> {
    const idOrError = UniqueID.create(source.id);
    const tinOrError = TINNumber.create(source.tin);
    const emailOrError = EmailAddress.create(source.email);
    const phoneOrError = PhoneNumber.create(source.phone);
    const faxOrError = PhoneNumber.createNullable(source.fax);
    const postalAddressOrError = PostalAddress.create({
      street: source.street,
      city: source.city,
      state: source.state,
      postalCode: source.postal_code,
      country: source.country,
    });

    const result = Result.combine([
      idOrError,
      tinOrError,
      emailOrError,
      phoneOrError,
      faxOrError,
      postalAddressOrError,
    ]);

    if (result.isFailure) {
      return Result.fail(result.error);
    }

    return Contact.create(
      {
        isFreelancer: source.is_companyr,
        reference: source.reference,
        name: source.name,
        tradeName: source.trade_name ? Maybe.some(source.trade_name) : Maybe.none(),
        tin: tinOrError.data,
        address: postalAddressOrError.data,
        email: emailOrError.data,
        phone: phoneOrError.data,
        fax: faxOrError.data,
        website: source.website ? Maybe.some(source.website) : Maybe.none(),
        legalRecord: source.legal_record,
        defaultTax: source.default_tax,
        status: source.status,
        langCode: source.language_code,
        currencyCode: source.currency_code,
      },
      idOrError.data
    );
  }

  public mapToPersistence(
    source: Contact,
    params?: MapperParamsType
  ): Result<ContactCreationAttributes, Error> {
    return Result.ok({
      id: source.id.toString(),
      reference: source.reference,
      is_companyr: source.isFreelancer,
      name: source.name,
      trade_name: source.tradeName.getOrUndefined(),
      tin: source.tin.toString(),

      street: source.address.street,
      city: source.address.city,
      state: source.address.state,
      postal_code: source.address.postalCode,
      country: source.address.country,

      email: source.email.toString(),
      phone: source.phone.toString(),
      fax: source.fax.isSome() ? source.fax.getOrUndefined()?.toString() : undefined,
      website: source.website.getOrUndefined(),

      legal_record: source.legalRecord,
      default_tax: source.defaultTax,
      status: source.isActive ? "active" : "inactive",
      language_code: source.langCode,
      currency_code: source.currencyCode,
    });
  }
}

const contactMapper: ContactMapper = new ContactMapper();
export { contactMapper };
