import { Op } from 'sequelize';
import {
  CustomerBaseModel,
  CustomerIndividualModel,
  CustomerBusinessModel,
  BusinessContactModel,
  ObjectAddressModel,
} from '../../models';
import { ISyncPayload } from '../../types/sync-payload.type';
import { IBusinessSyncPayload, IIndividualSyncPayload } from '../../interfaces';
import { CustomerTypeEnum } from '../../enum/customer-type.enum';
import { IAddress } from '@tomei/general';

/**
 * Builds a normalized ISyncPayload for a given CustomerId by reading CB tables.
 * Keeps the shape consistent with your discriminated union (Individual | Business)
 *
 * @param customerId - The ID of the customer to build the payload for
 * @returns A promise that resolves to the normalized ISyncPayload
 */
export async function buildCustomerPayload(
  customerId: string,
): Promise<ISyncPayload> {
  const customerBase = await CustomerBaseModel.findByPk(customerId);
  if (!customerBase) {
    throw new Error(`CustomerBase not found for CustomerId=${customerId}`);
  }

  const addresses = await ObjectAddressModel.findAll({
    where: {
      ObjectId: customerId,
      ObjectType: 'Customer',
      Status: { [Op.ne]: 'Deleted' },
    },
    order: [
      ['IsDefaultYN', 'DESC'],
      ['UpdatedAt', 'DESC'],
    ],
  });

  const Address: IAddress[] = addresses.map((a) => ({
    AddressLine1: a.AddressLine1,
    AddressLine2: a.AddressLine2 ?? '',
    City: a.City,
    State: a.State ?? '',
    PostCode: a.PostalCode, //DEV WARN: Postcode and/or PostalCode can be not consistent between systems
    Country: a.Country,
    AddressType: a.AddressType,
    IsDefaultYN: a.IsDefaultYN,
    Latitude: (a as any).Latitude ?? undefined,
    Longitude: (a as any).Longitude ?? undefined,
  }));

  const sourceSystem = customerBase.UpdatedBySystemCode ?? '';

  if (customerBase.Type === CustomerTypeEnum.Individual) {
    const cbIndividual = await CustomerIndividualModel.findByPk(customerId);
    if (!cbIndividual) {
      throw new Error(
        `CustomerIndividual not found for CustomerId=${customerId}`,
      );
    }

    const payload: IIndividualSyncPayload = {
      // base payload fields
      CustomerId: customerBase.CustomerId,
      Type: CustomerTypeEnum.Individual,
      Email: customerBase.Email ?? '-',
      ContactNo: customerBase.ContactNo ?? '-',
      SourceSystem: sourceSystem,
      Address,
      // individual payload fields
      FullName: cbIndividual.FullName,
      IdType: cbIndividual.IdType,
      IdNo: cbIndividual.IdNo,
      // optional/nullable individual fields
      Title: cbIndividual.Title ?? 'N/A',
      PreferredName: cbIndividual.PreferredName ?? cbIndividual.FullName,
      Birthdate: cbIndividual.Birthdate ?? undefined,
      Gender: cbIndividual.Gender ?? undefined,
      Ethnicity: cbIndividual.Ethnicity ?? undefined,
      Nationality: cbIndividual.Nationality ?? undefined,
      PreferredLanguage: cbIndividual.PreferredLanguage ?? undefined,
    };

    return payload;
  }

  const cbBusiness = await CustomerBusinessModel.findByPk(customerId);
  if (!cbBusiness) {
    throw new Error(`CustomerBusiness not found for CustomerId=${customerId}`);
  }

  const cbBusinessPIC = await BusinessContactModel.findOne({
    where: { CustomerId: customerId, IsMainYN: 'Y' },
    order: [['UpdatedAt', 'DESC']],
  });

  const payload: IBusinessSyncPayload = {
    // base payload fields
    CustomerId: customerBase.CustomerId,
    Type: CustomerTypeEnum.Business,
    Email: customerBase.Email,
    ContactNo: customerBase.ContactNo,
    SourceSystem: sourceSystem,
    Address,
    // business payload fields
    CompanyName: cbBusiness.CompanyName,
    RegistrationNo: cbBusiness.RegistrationNo ?? undefined,
    TaxIdentificationNo: cbBusiness.TaxIdentificationNo ?? undefined,
    // PIC is optional in your writer; keep it optional here too
    PIC: cbBusinessPIC
      ? {
          Name: cbBusinessPIC.Name,
          ContactNo: cbBusinessPIC.ContactNo,
          Email: cbBusinessPIC.Email ?? undefined,
          Position: cbBusinessPIC.Position ?? undefined,
          IsMainYN: cbBusinessPIC.IsMainYN,
        }
      : undefined,
  };

  return payload;
}
