import { getAuth } from "@clerk/react-router/server";
import { database } from "~/database/context";
import * as schema from "~/database/schema";
import { eq, and, sql } from "drizzle-orm";
import { isUserAdminByClerkId } from "~/models/user";
import { calculateDraftEligibility } from "~/lib/draft-eligibility";
import { getDraftPicksWithSports, getTeamDraftPicksWithSports } from "~/models/draft-pick";
import { getParticipantsForSeasonWithSports } from "~/models/participant";
import { getSeasonSportsSimple } from "~/models/season-sport";
import { calculatePickInfo, checkAndTriggerNextAutodraft } from "~/models/draft-utils";
import { getSocketIO } from "../../../server/socket";
import { logger } from "~/lib/logger";
import type { ActionFunctionArgs } from "react-router";

export async function action(args: ActionFunctionArgs) {
  const { request } = args;
  const { userId } = await getAuth(args);

  if (!userId) {
    return Response.json({ error: "Unauthorized" }, { status: 401 });
  }

  const formData = await request.formData();
  const seasonId = formData.get("seasonId") as string;
  const teamId = formData.get("teamId") as string;
  const participantId = formData.get("participantId") as string;
  const pickNumber = parseInt(formData.get("pickNumber") as string);

  if (!seasonId || !teamId || !participantId || !pickNumber) {
    return Response.json({ error: "Missing required fields" }, { status: 400 });
  }

  const db = database();

  // Get season details
  const season = await db.query.seasons.findFirst({
    where: eq(schema.seasons.id, seasonId),
  });

  if (!season) {
    return Response.json({ error: "Season not found" }, { status: 404 });
  }

  // Check if user is commissioner or site admin; capture both to set pickedByType accurately
  const [isAdmin, commissionerRecord] = await Promise.all([
    isUserAdminByClerkId(userId),
    db.query.commissioners.findFirst({
      where: and(
        eq(schema.commissioners.leagueId, season.leagueId),
        eq(schema.commissioners.userId, userId)
      ),
    }),
  ]);

  if (!isAdmin && !commissionerRecord) {
    return Response.json({ error: "Only commissioners can force a manual pick" }, { status: 403 });
  }

  if (season.status !== "draft") {
    return Response.json({ error: "Draft is not currently active" }, { status: 400 });
  }

  // Check if a pick already exists at this pick number slot (prevents duplicate picks at same slot)
  const existingPickAtSlot = await db.query.draftPicks.findFirst({
    where: and(
      eq(schema.draftPicks.seasonId, seasonId),
      eq(schema.draftPicks.pickNumber, pickNumber)
    ),
  });

  if (existingPickAtSlot) {
    return Response.json({ error: "A pick already exists at this slot" }, { status: 400 });
  }

  // Check if participant is already drafted
  const existingPick = await db.query.draftPicks.findFirst({
    where: and(
      eq(schema.draftPicks.seasonId, seasonId),
      eq(schema.draftPicks.participantId, participantId)
    ),
  });

  if (existingPick) {
    return Response.json({ error: "Participant already drafted" }, { status: 400 });
  }

  // Get participant details
  const participant = await db.query.participants.findFirst({
    where: eq(schema.participants.id, participantId),
    with: {
      sportsSeason: {
        with: {
          sport: true,
        },
      },
    },
  });

  if (!participant) {
    return Response.json({ error: "Participant not found" }, { status: 404 });
  }

  // Calculate round and pickInRound
  const draftSlots = await db.query.draftSlots.findMany({
    where: eq(schema.draftSlots.seasonId, seasonId),
    orderBy: schema.draftSlots.draftOrder,
    with: {
      team: true,
    },
  });

  const totalTeams = draftSlots.length;
  const { round: currentRound, pickInRound } = calculatePickInfo(pickNumber, totalTeams);

  // Validate that the submitted teamId is actually the team whose turn it is at pickNumber
  const expectedDraftSlot = draftSlots.find((slot) => slot.draftOrder === pickInRound);
  if (!expectedDraftSlot) {
    return Response.json({ error: "Invalid draft state" }, { status: 500 });
  }
  if (expectedDraftSlot.teamId !== teamId) {
    return Response.json({ error: "It is not this team's turn to pick at this slot" }, { status: 400 });
  }

  // ELIGIBILITY VALIDATION: Check if team can draft from this sport
  const allPicks = await getDraftPicksWithSports(seasonId);
  const teamPicks = await getTeamDraftPicksWithSports(teamId, seasonId);
  const allParticipants = await getParticipantsForSeasonWithSports(seasonId);
  const seasonSports = await getSeasonSportsSimple(seasonId);

  // Get all teams for the season
  const allTeams = draftSlots.map((slot) => ({ id: slot.teamId }));

  const eligibility = calculateDraftEligibility(
    teamId,
    teamPicks,
    allPicks,
    allParticipants,
    seasonSports,
    season.draftRounds,
    allTeams
  );

  const sportId = participant.sportsSeason.sport.id;
  if (!eligibility.eligibleSportIds.has(sportId)) {
    const reason = eligibility.ineligibleReasons[sportId] || "Cannot draft from this sport";
    return Response.json({ error: reason }, { status: 400 });
  }

  // Create the draft pick
  const [draftPick] = await db
    .insert(schema.draftPicks)
    .values({
      seasonId,
      teamId,
      participantId,
      pickNumber,
      round: currentRound,
      pickInRound,
      pickedByUserId: userId,
      pickedByType: commissionerRecord ? "commissioner" : "admin",
    })
    .returning();

  // Calculate next pick info (before updating season)
  const nextPickNumber = pickNumber + 1;
  const totalPicks = totalTeams * season.draftRounds;
  const isDraftComplete = nextPickNumber > totalPicks;

  // Standard mode: reset to the per-pick time (so the next turn starts fresh).
  // Chess clock: add the increment to the bank (same as any other pick type).
  const incrementTime = season.draftIncrementTime || 30;
  const timerSql = season.draftTimerMode === "standard"
    ? sql`${incrementTime}`
    : sql`${schema.draftTimers.timeRemaining} + ${incrementTime}`;

  const [updatedTimer] = await db
    .update(schema.draftTimers)
    .set({ timeRemaining: timerSql, updatedAt: new Date() })
    .where(
      and(
        eq(schema.draftTimers.seasonId, seasonId),
        eq(schema.draftTimers.teamId, teamId)
      )
    )
    .returning();
  const newTimeRemaining = updatedTimer?.timeRemaining ?? incrementTime;
  if (!updatedTimer) {
    await db.insert(schema.draftTimers).values({ seasonId, teamId, timeRemaining: newTimeRemaining });
  }

  // Emit timer update to all clients
  try {
    getSocketIO().to(`draft-${seasonId}`).emit("timer-update", {
      seasonId,
      teamId,
      timeRemaining: newTimeRemaining,
      currentPickNumber: nextPickNumber,
    });
  } catch (error) {
    logger.error("Socket.IO timer-update error:", error);
  }

  // Next team's timer is unchanged — their bank carries forward as-is.
  // The timer server loop will start counting down from their existing balance.

  // Update season's current pick number
  await db
    .update(schema.seasons)
    .set({
      currentPickNumber: isDraftComplete ? pickNumber : nextPickNumber,
      status: isDraftComplete ? "active" : season.status,
    })
    .where(eq(schema.seasons.id, seasonId));

  // Remove from ALL team queues in this season (participant is now drafted)
  await db
    .delete(schema.draftQueue)
    .where(
      and(
        eq(schema.draftQueue.seasonId, seasonId),
        eq(schema.draftQueue.participantId, participantId)
      )
    );

  // Notify all clients that this participant was removed from queues
  try {
    getSocketIO().to(`draft-${seasonId}`).emit("participant-removed-from-queues", {
      participantId,
    });
  } catch (error) {
    logger.error("Socket.IO participant-removed-from-queues error:", error);
  }

  // Emit socket event
  try {
    const io = getSocketIO();
    const team = draftSlots.find((slot) => slot.team.id === teamId)?.team;

    io.to(`draft-${seasonId}`).emit("pick-made", {
      pick: {
        ...draftPick,
        team,
        participant: {
          ...participant,
          sport: participant.sportsSeason.sport,
        },
        sport: participant.sportsSeason.sport,
      },
      nextPickNumber: isDraftComplete ? pickNumber : nextPickNumber,
      isDraftComplete,
    });

    if (isDraftComplete) {
      io.to(`draft-${seasonId}`).emit("draft-completed");
    }
  } catch (error) {
    logger.error("Socket.IO error:", error);
  }

  // Check if next team has autodraft enabled and trigger immediately
  if (!isDraftComplete) {
    const freshSeason = await db.query.seasons.findFirst({ where: eq(schema.seasons.id, seasonId) });
    if (!freshSeason?.draftPaused) {
      await checkAndTriggerNextAutodraft({
        seasonId,
        nextPickNumber,
        totalTeams,
        draftSlots,
        db,
      });
    }
  }

  return Response.json({
    success: true,
    pick: draftPick,
    nextPickNumber: isDraftComplete ? pickNumber : nextPickNumber,
    isDraftComplete,
  });
}
