import { err, ok, type CommandContext } from "@tailor-platform/erp-kit/core";
import type { Transaction } from "../generated/kysely-tailordb";
import {
  CompanyNotFoundError,
  NameRequiredError,
  InvalidDateRangeError,
  OverlappingFiscalYearError,
} from "../lib/errors.generated";
import type { OrganizationQueries } from "../module";

export interface CreateFiscalYearInput {
  companyId: string;
  name: string;
  startDate: Date;
  endDate: Date;
}

/**
 * Function: createFiscalYear
 *
 * Creates a company-scoped fiscal year after validating the company, name,
 * date range, and overlap with existing fiscal years.
 */
export async function run<CF extends Record<string, unknown>>(
  db: Transaction,
  input: CreateFiscalYearInput & CF,
  ctx: CommandContext,
  organizationQueries: Pick<OrganizationQueries, "getCompany">,
) {
  // Validate company exists
  const { company } = (await organizationQueries.getCompany(db, { id: input.companyId }, ctx))
    .value;

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

  // Validate name is non-empty
  if (!input.name || input.name.trim() === "") {
    return err(new NameRequiredError(input.companyId));
  }

  // Validate start date is strictly before end date
  if (input.startDate >= input.endDate) {
    return err(new InvalidDateRangeError(input.companyId));
  }

  // Check for overlapping fiscal years for the same company
  const overlapping = await db
    .selectFrom("FiscalYear")
    .where("companyId", "=", input.companyId)
    .where("startDate", "<", input.endDate)
    .where("endDate", ">", input.startDate)
    .selectAll()
    .executeTakeFirst();

  if (overlapping) {
    return err(new OverlappingFiscalYearError(input.companyId));
  }

  // Create the fiscal year record
  const { companyId, name, startDate, endDate, ...customFields } = input;
  const fiscalYear = await db
    .insertInto("FiscalYear")
    .values({
      ...(customFields as Record<string, unknown>),
      companyId,
      name,
      startDate,
      endDate,
      yearEndCloseExecuted: false,
    })
    .returningAll()
    .executeTakeFirstOrThrow();

  return ok({ fiscalYear });
}
