import { ok, err } from "@tailor-platform/erp-kit/core";
import type { PartnerAddressAddressType } from "../generated/enums";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  PartnerNotFoundError,
  PartnerInactiveError,
  MissingRequiredAddressFieldError,
  InvalidCountryCodeError,
} from "../lib/errors.generated";

export interface CreatePartnerAddressInput {
  partnerId: string;
  addressType: PartnerAddressAddressType;
  line1: string;
  line2?: string;
  city: string;
  state?: string;
  postalCode: string;
  country: string;
  isDefault?: boolean;
}

/**
 * Function: createPartnerAddress
 *
 * Creates a new address for a business partner. If isDefault is true,
 * unsets the previous default address of the same type for the same partner.
 */
export async function run<CF extends Record<string, unknown>>(
  db: Transaction,
  input: CreatePartnerAddressInput & CF,
) {
  const {
    partnerId,
    addressType,
    line1,
    line2,
    city,
    state,
    postalCode,
    country,
    isDefault = false,
    ...customFields
  } = input;

  // 1. Check partner exists
  const partner = await db
    .selectFrom("BusinessPartner")
    .selectAll()
    .where("id", "=", partnerId)
    .forUpdate()
    .executeTakeFirst();

  if (!partner) {
    return err(new PartnerNotFoundError(partnerId));
  }

  // 2. Check partner is not INACTIVE
  if (partner.status === "INACTIVE") {
    return err(new PartnerInactiveError(partnerId));
  }

  // 3. Validate required fields
  if (!line1?.trim()) {
    return err(new MissingRequiredAddressFieldError("line1"));
  }
  if (!city?.trim()) {
    return err(new MissingRequiredAddressFieldError("city"));
  }
  if (!postalCode?.trim()) {
    return err(new MissingRequiredAddressFieldError("postalCode"));
  }

  // 4. Validate country code (ISO 3166-1 alpha-2: two uppercase letters)
  if (!/^[A-Z]{2}$/.test(country)) {
    return err(new InvalidCountryCodeError(country));
  }

  // 5. If isDefault, unset previous default of same type for same partner
  if (isDefault) {
    await db
      .updateTable("PartnerAddress")
      .set({ isDefault: false })
      .where("partnerId", "=", partnerId)
      .where("addressType", "=", addressType)
      .where("isDefault", "=", true)
      .execute();
  }

  // 6. Create address
  const address = await db
    .insertInto("PartnerAddress")
    .values({
      ...(customFields as Record<string, unknown>),
      partnerId,
      addressType,
      line1,
      line2: line2 ?? null,
      city,
      state: state ?? null,
      postalCode,
      country,
      isDefault,
    })
    .returningAll()
    .executeTakeFirstOrThrow();

  return ok({ address });
}
