import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core";
import { Decimal } from "decimal.js";
import type { Transaction, Updateable } from "../generated/kysely-tailordb";
import {
  InvalidToleranceValueError,
  InvoiceToleranceConfigNotFoundError,
} from "../lib/errors.generated";

export interface InvoiceToleranceConfigPatch {
  quantityAbsoluteTolerance?: string | null;
  quantityPercentageTolerance?: string | null;
  unitPriceAbsoluteTolerance?: string | null;
  unitPricePercentageTolerance?: string | null;
}

export interface UpdateInvoiceToleranceConfigInput {
  companyId: string;
  supplierId: string;
  patch: InvoiceToleranceConfigPatch;
}

const toleranceFields = [
  "quantityAbsoluteTolerance",
  "quantityPercentageTolerance",
  "unitPriceAbsoluteTolerance",
  "unitPricePercentageTolerance",
] as const;

function validateToleranceValues(patch: InvoiceToleranceConfigPatch) {
  for (const field of toleranceFields) {
    const value = patch[field];
    if (value != null && new Decimal(value).lt(0)) {
      return err(new InvalidToleranceValueError(field));
    }
  }
  return ok({});
}

export async function run(
  db: Transaction,
  input: UpdateInvoiceToleranceConfigInput,
  _ctx: CommandContext,
) {
  const { companyId, supplierId, patch } = input;

  const config = await db
    .selectFrom("InvoiceToleranceConfig")
    .selectAll()
    .where("companyId", "=", companyId)
    .where("supplierId", "=", supplierId)
    .forUpdate()
    .executeTakeFirst();
  if (!config) return err(new InvoiceToleranceConfigNotFoundError(`${companyId}:${supplierId}`));

  const toleranceResult = validateToleranceValues(patch);
  if (!toleranceResult.ok) return toleranceResult;

  const values: Updateable<"InvoiceToleranceConfig"> = {};
  if (patch.quantityAbsoluteTolerance !== undefined) {
    values.quantityAbsoluteTolerance = patch.quantityAbsoluteTolerance;
  }
  if (patch.quantityPercentageTolerance !== undefined) {
    values.quantityPercentageTolerance = patch.quantityPercentageTolerance;
  }
  if (patch.unitPriceAbsoluteTolerance !== undefined) {
    values.unitPriceAbsoluteTolerance = patch.unitPriceAbsoluteTolerance;
  }
  if (patch.unitPricePercentageTolerance !== undefined) {
    values.unitPricePercentageTolerance = patch.unitPricePercentageTolerance;
  }

  if (Object.keys(values).length === 0) {
    return ok({ invoiceToleranceConfig: config });
  }

  const invoiceToleranceConfig = await db
    .updateTable("InvoiceToleranceConfig")
    .set(values)
    .where("id", "=", config.id)
    .returningAll()
    .executeTakeFirstOrThrow();

  return ok({ invoiceToleranceConfig });
}
