import { and, eq, isNull } from "drizzle-orm";
import dayjs from "dayjs";
import { useDrizzle } from "@/lib/db.js";
import { idTag, transaction } from "@/db/schema.js";
import type {
  AuthorizeRequest,
  AuthorizeResponse,
  IdTagInfo,
  OcppConnectionContext,
} from "../types.ts";

/**
 * Shared helper — resolves idTagInfo from the database.
 * Used by Authorize, StartTransaction, and StopTransaction.
 *
 * @param checkBalance  When true (default), rejects tags with balance ≤ 0.
 *                      Pass false for StopTransaction where charging has already occurred.
 */
export async function resolveIdTagInfo(
  idTagValue: string,
  checkBalance = true,
  checkConcurrent = true,
): Promise<IdTagInfo> {
  const db = useDrizzle();
  const [tag] = await db.select().from(idTag).where(eq(idTag.idTag, idTagValue)).limit(1);

  if (!tag) return { status: "Invalid" };
  if (tag.status === "Blocked") return { status: "Blocked" };
  if (tag.expiryDate && dayjs(tag.expiryDate).isBefore(dayjs())) {
    return { status: "Expired", expiryDate: tag.expiryDate.toISOString() };
  }
  if (tag.status !== "Accepted") {
    return { status: tag.status as IdTagInfo["status"] };
  }

  // Enforce single active transaction per idTag.
  if (checkConcurrent) {
    const [activeTx] = await db
      .select({ id: transaction.id })
      .from(transaction)
      .where(and(eq(transaction.idTag, idTagValue), isNull(transaction.stopTimestamp)))
      .limit(1);
    if (activeTx) return { status: "ConcurrentTx" };
  }

  // Reject if balance is zero or negative
  if (checkBalance && tag.balance <= 0) {
    return { status: "Blocked" };
  }
  return {
    status: "Accepted",
    expiryDate: tag.expiryDate?.toISOString(),
    parentIdTag: tag.parentIdTag ?? undefined,
  };
}

export async function handleAuthorize(
  payload: AuthorizeRequest,
  _ctx: OcppConnectionContext,
): Promise<AuthorizeResponse> {
  const idTagInfo = await resolveIdTagInfo(payload.idTag);
  console.log(`[OCPP] Authorize idTag=${payload.idTag} -> ${idTagInfo.status}`);
  return { idTagInfo };
}
