import type { Transaction } from "../generated/kysely-tailordb";
import {
  InvalidNameError,
  InvalidTypeError,
  CompanyNotFoundError,
  CompanyInactiveError,
  DuplicateNameError,
  MissingRequiredFieldsError,
  InvalidCountryError,
  InvalidTimezoneError,
} from "../lib/errors.generated";
import { ok, err } from "@tailor-platform/erp-kit/module";

export interface CreateSiteInput {
  name: string;
  type: string;
  companyId: string;
  street: string;
  city: string;
  state?: string;
  postalCode: string;
  country: string;
  timezone: string;
}

const VALID_SITE_TYPES = ["OFFICE", "WAREHOUSE", "STORE", "FACTORY", "DISTRIBUTION_CENTER"];

function isValidCountryCode(code: string): boolean {
  try {
    const displayNames = new Intl.DisplayNames(["en"], { type: "region" });
    const name = displayNames.of(code);
    return name !== undefined && name !== code;
  } catch {
    return false;
  }
}

function isValidTimezone(tz: string): boolean {
  try {
    Intl.DateTimeFormat(undefined, { timeZone: tz });
    return true;
  } catch {
    return false;
  }
}

/**
 * Function: createSite
 *
 * Creates a new operational site within a company, capturing its classification,
 * physical address, and timezone.
 */
export async function run<CF extends Record<string, unknown>>(
  db: Transaction,
  input: CreateSiteInput & CF,
) {
  const {
    name,
    type,
    companyId,
    street,
    city,
    state,
    postalCode,
    country,
    timezone,
    ...customFields
  } = input;

  // 1. Validate name non-empty
  if (!name || name.trim() === "") {
    return err(new InvalidNameError(name ?? ""));
  }

  // 2. Validate type in allowed list
  if (!VALID_SITE_TYPES.includes(type)) {
    return err(new InvalidTypeError(type));
  }

  // 3. Find company by companyId
  const company = await db
    .selectFrom("Company")
    .selectAll()
    .where("id", "=", companyId)
    .executeTakeFirst();

  if (!company) {
    return err(new CompanyNotFoundError(companyId));
  }

  // 4. Company must be ACTIVE
  if (company.status !== "ACTIVE") {
    return err(new CompanyInactiveError(companyId));
  }

  // 5. Check name uniqueness in company with forUpdate()
  const existingSite = await db
    .selectFrom("Site")
    .selectAll()
    .where("name", "=", name)
    .where("companyId", "=", companyId)
    .forUpdate()
    .executeTakeFirst();

  if (existingSite) {
    return err(new DuplicateNameError(name));
  }

  // 6. Validate address fields
  if (!street || street.trim() === "") {
    return err(new MissingRequiredFieldsError("street"));
  }
  if (!city || city.trim() === "") {
    return err(new MissingRequiredFieldsError("city"));
  }
  if (!postalCode || postalCode.trim() === "") {
    return err(new MissingRequiredFieldsError("postalCode"));
  }
  if (!country || country.trim() === "") {
    return err(new MissingRequiredFieldsError("country"));
  }

  // 7. Validate country code
  if (!isValidCountryCode(country)) {
    return err(new InvalidCountryError(country));
  }

  // 8. Validate timezone
  if (!isValidTimezone(timezone)) {
    return err(new InvalidTimezoneError(timezone));
  }

  // 9. Insert with status "ACTIVE"
  const site = await db
    .insertInto("Site")
    .values({
      ...(customFields as Record<string, unknown>),
      name,
      type,
      companyId,
      street,
      city,
      state: state ?? null,
      postalCode,
      country,
      timezone,
      status: "ACTIVE",
      createdAt: new Date(),
      updatedAt: null,
    })
    .returningAll()
    .executeTakeFirst();

  return ok({ site: site! });
}
