import type { defineModule as defineBusinessPartnerModule } from "../../business-partner";
import type { Transaction } from "../generated/kysely-tailordb";
type BusinessPartnerModule = ReturnType<typeof defineBusinessPartnerModule>;
type BusinessPartnerQueries = BusinessPartnerModule["queries"];
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core";
import {
  CompanyScopeMismatchError,
  PartnerNotSupplierError,
  PaymentTermInactiveError,
  PaymentTermNotFoundError,
  SupplierNotFoundError,
} from "../lib/errors.generated";

export interface SetSupplierDefaultPurchasePaymentTermInput {
  companyId: string;
  supplierId: string;
  defaultPurchasePaymentTermId?: string | null;
}

export async function run(
  db: Transaction,
  input: SetSupplierDefaultPurchasePaymentTermInput,
  ctx: CommandContext,
  businessPartnerQueries: Pick<BusinessPartnerQueries, "getPartnerRole">,
) {
  const supplier = await db
    .selectFrom("BusinessPartner")
    .selectAll()
    .where("id", "=", input.supplierId)
    .executeTakeFirst();
  if (!supplier) {
    return err(new SupplierNotFoundError(input.supplierId));
  }

  const { partnerRole: supplierRole } = (
    await businessPartnerQueries.getPartnerRole(
      db,
      { partnerId: input.supplierId, role: "SUPPLIER" },
      ctx,
    )
  ).value;
  if (!supplierRole) {
    return err(new PartnerNotSupplierError(input.supplierId));
  }

  const paymentTermId = input.defaultPurchasePaymentTermId ?? null;
  if (paymentTermId) {
    const paymentTerm = await db
      .selectFrom("PurchasePaymentTerm")
      .selectAll()
      .where("id", "=", paymentTermId)
      .executeTakeFirst();
    if (!paymentTerm) {
      return err(new PaymentTermNotFoundError(paymentTermId));
    }
    if (paymentTerm.companyId !== input.companyId) {
      return err(new CompanyScopeMismatchError(paymentTermId));
    }
    if ((paymentTerm.status as string | null) !== "ACTIVE") {
      return err(new PaymentTermInactiveError(paymentTermId));
    }
  }

  const existing = await db
    .selectFrom("SupplierProfile")
    .selectAll()
    .where("companyId", "=", input.companyId)
    .where("supplierId", "=", input.supplierId)
    .forUpdate()
    .executeTakeFirst();
  if (existing) {
    if (existing.defaultPurchasePaymentTermId === paymentTermId) {
      return ok({ supplierProfile: existing });
    }

    const supplierProfile = await db
      .updateTable("SupplierProfile")
      .set({
        defaultPurchasePaymentTermId: paymentTermId,
      })
      .where("id", "=", existing.id)
      .returningAll()
      .executeTakeFirstOrThrow();

    return ok({ supplierProfile });
  }

  const supplierProfile = await db
    .insertInto("SupplierProfile")
    .values({
      companyId: input.companyId,
      supplierId: input.supplierId,
      defaultPurchasePaymentTermId: paymentTermId,
    })
    .returningAll()
    .executeTakeFirstOrThrow();

  return ok({ supplierProfile });
}
