import { eq, desc, and, inArray, sql } from "drizzle-orm";
import { database } from "~/database/context";
import * as schema from "~/database/schema";
import { findUserById, getUserDisplayName } from "~/models/user";

export type AuditLogEntry = typeof schema.commissionerAuditLog.$inferSelect;
export type NewAuditLogEntry = typeof schema.commissionerAuditLog.$inferInsert;
export type AuditAction = typeof schema.auditActionEnum.enumValues[number];

export interface AuditLogPage {
  entries: AuditLogEntry[];
  total: number;
  hasMore: boolean;
}

export async function createAuditLogEntry(
  data: NewAuditLogEntry
): Promise<AuditLogEntry> {
  const db = database();
  const [entry] = await db
    .insert(schema.commissionerAuditLog)
    .values(data)
    .returning();
  return entry;
}

export async function getAuditLogForSeason(
  seasonId: string,
  options?: { limit?: number; offset?: number; actions?: AuditAction[] }
): Promise<AuditLogPage> {
  const db = database();
  const limit = options?.limit ?? 50;
  const offset = options?.offset ?? 0;

  const whereClause =
    options?.actions && options.actions.length > 0
      ? and(
          eq(schema.commissionerAuditLog.seasonId, seasonId),
          inArray(schema.commissionerAuditLog.action, options.actions)
        )
      : eq(schema.commissionerAuditLog.seasonId, seasonId);

  const [entries, countRows] = await Promise.all([
    db
      .select()
      .from(schema.commissionerAuditLog)
      .where(whereClause)
      .orderBy(desc(schema.commissionerAuditLog.createdAt))
      .limit(limit)
      .offset(offset),
    db
      .select({ count: sql<number>`count(*)::int` })
      .from(schema.commissionerAuditLog)
      .where(whereClause),
  ]);

  const total = countRows[0]?.count ?? 0;
  return { entries, total, hasMore: offset + entries.length < total };
}

/**
 * Convenience wrapper that resolves the actor display name from the users table
 * and writes a single audit log record. Call this after the main action succeeds.
 */
export async function logCommissionerAction(params: {
  seasonId: string;
  leagueId: string;
  actorUserId: string;
  action: AuditAction;
  affectedTeamIds?: string[];
  details?: Record<string, unknown>;
}): Promise<void> {
  const user = await findUserById(params.actorUserId);
  const actorDisplayName = user
    ? (getUserDisplayName(user) ?? params.actorUserId)
    : params.actorUserId;

  await createAuditLogEntry({
    seasonId: params.seasonId,
    leagueId: params.leagueId,
    actorUserId: params.actorUserId,
    actorDisplayName,
    action: params.action,
    affectedTeamIds: params.affectedTeamIds ?? [],
    details: params.details ?? {},
  });
}
