import type { Transaction } from "../generated/kysely-tailordb";
import {
  ChannelNotFoundError,
  CrossCompanyReferenceError,
  ExternalOrderIdRequiredError,
} from "../lib/errors.generated";
import { encodeJson } from "../lib/domain";
import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/module";

export interface RecordChannelOrderInput {
  companyId: string;
  channelId: string;
  externalOrderId: string;
  externalCustomerId?: string;
  customerId?: string | null;
  currencyId?: string | null;
  rawPayload?: Record<string, unknown> | null;
  normalizedPayload?: Record<string, unknown> | null;
  syncJobId?: string | null;
}

export async function run(db: Transaction, input: RecordChannelOrderInput, ctx: CommandContext) {
  void ctx;
  if (!input.externalOrderId) {
    return err(new ExternalOrderIdRequiredError(input.channelId));
  }
  const channel = await db
    .selectFrom("Channel")
    .selectAll()
    .where("id", "=", input.channelId)
    .executeTakeFirst();
  if (!channel) {
    return err(new ChannelNotFoundError(input.channelId));
  }
  if (channel.companyId !== input.companyId) {
    return err(new CrossCompanyReferenceError(input.channelId));
  }
  const existing = await db
    .selectFrom("ChannelOrder")
    .selectAll()
    .where("companyId", "=", input.companyId)
    .where("channelId", "=", input.channelId)
    .where("externalOrderId", "=", input.externalOrderId)
    .executeTakeFirst();

  if (existing) {
    const updated = await db
      .updateTable("ChannelOrder")
      .set({
        externalCustomerId: input.externalCustomerId ?? existing.externalCustomerId,
        customerId: input.customerId ?? existing.customerId,
        currencyId: input.currencyId ?? existing.currencyId,
        rawPayload: input.rawPayload ? encodeJson(input.rawPayload) : existing.rawPayload,
        normalizedPayload: input.normalizedPayload
          ? encodeJson(input.normalizedPayload)
          : existing.normalizedPayload,
        syncJobId: input.syncJobId ?? existing.syncJobId,
        status:
          existing.status === "CANCELLED_BY_CHANNEL" || existing.salesOrderId
            ? existing.status
            : "PENDING_CONVERSION",
        updatedAt: new Date(),
      })
      .where("id", "=", existing.id)
      .returningAll()
      .executeTakeFirst();
    return ok({ channelOrder: updated! });
  }

  const channelOrder = await db
    .insertInto("ChannelOrder")
    .values({
      companyId: input.companyId,
      channelId: input.channelId,
      externalOrderId: input.externalOrderId,
      externalCustomerId: input.externalCustomerId ?? null,
      customerId: input.customerId ?? null,
      salesOrderId: null,
      status: "PENDING_CONVERSION",
      orderDate: new Date(),
      currencyId: input.currencyId ?? null,
      rawPayload: input.rawPayload ? encodeJson(input.rawPayload) : null,
      normalizedPayload: input.normalizedPayload ? encodeJson(input.normalizedPayload) : null,
      errorSummary: null,
      retryContext: null,
      syncJobId: input.syncJobId ?? null,
      createdAt: new Date(),
      updatedAt: null,
    })
    .returningAll()
    .executeTakeFirst();
  return ok({ channelOrder: channelOrder! });
}
