import {
  ok,
  type ReadonlyDB,
  buildPaginatedResult,
  DEFAULT_PAGE_SIZE,
} from "@tailor-platform/erp-kit/core";
import type {
  InventoryExecutionSourceDocumentType,
  InventoryExecutionStatus,
} from "../generated/enums";
import type { DB } from "../generated/kysely-tailordb";

export interface ListGoodsReceiptsInput {
  status?: InventoryExecutionStatus;
  sourceDocumentType?: InventoryExecutionSourceDocumentType;
  sourceDocumentId?: string;
  dateFrom?: Date;
  dateTo?: Date;
  limit?: number;
  offset?: number;
}

export async function run(db: ReadonlyDB<DB>, input: ListGoodsReceiptsInput) {
  const limit = input.limit ?? DEFAULT_PAGE_SIZE;
  const offset = input.offset ?? 0;

  let query = db
    .selectFrom("InventoryExecution")
    .selectAll()
    .where("executionType", "=", "GOODS_RECEIPT");
  if (input.status) query = query.where("status", "=", input.status);
  if (input.sourceDocumentType)
    query = query.where("sourceDocumentType", "=", input.sourceDocumentType);
  if (input.sourceDocumentId) query = query.where("sourceDocumentId", "=", input.sourceDocumentId);
  if (input.dateFrom) query = query.where("effectiveDate", ">=", input.dateFrom);
  if (input.dateTo) query = query.where("effectiveDate", "<=", input.dateTo);

  const executions = await query
    .orderBy("createdAt", "desc")
    .limit(limit + 1)
    .offset(offset)
    .execute();

  const paginatedResult = buildPaginatedResult(executions, limit);
  const executionIds = paginatedResult.items.map((execution) => execution.id);
  const lines =
    executionIds.length > 0
      ? await db
          .selectFrom("InventoryExecutionLine")
          .selectAll()
          .where("inventoryExecutionId", "in", executionIds)
          .execute()
      : [];

  const linesByExecutionId = new Map<string, typeof lines>();
  for (const line of lines) {
    const current = linesByExecutionId.get(line.inventoryExecutionId) ?? [];
    current.push(line);
    linesByExecutionId.set(line.inventoryExecutionId, current);
  }

  return ok({
    items: paginatedResult.items.map((inventoryExecution) => ({
      inventoryExecution,
      inventoryExecutionLines: linesByExecutionId.get(inventoryExecution.id) ?? [],
    })),
    hasNextPage: paginatedResult.hasNextPage,
  });
}
