import type { Route } from "./+types/admin.sports-seasons.$id.events.$eventId";
import { logger } from "~/lib/logger";
import { findSportsSeasonById } from "~/models/sports-season";
import { findParticipantsBySportsSeasonId } from "~/models/participant";
import {
  getScoringEventById,
  completeScoringEvent,
  updateScoringEvent,
} from "~/models/scoring-event";
import {
  getEventResults,
  createEventResult,
  updateEventResult,
  deleteEventResult,
  type CreateEventResultData,
  type UpdateEventResultData,
} from "~/models/event-result";
import { findParticipantResultsBySportsSeasonId } from "~/models/participant-result";
import {
  upsertParticipantSeasonResult,
  getSeasonResults,
} from "~/models/participant-season-result";
import { processSeasonStandings, processQualifyingEvent } from "~/models/scoring-calculator";
import { getQPStandings, getQPConfig } from "~/models/qualifying-points";
import { database } from "~/database/context";
import * as schema from "~/database/schema";
import { eq } from "drizzle-orm";

export async function loader({ params }: Route.LoaderArgs) {
  const sportsSeason = await findSportsSeasonById(params.id);

  if (!sportsSeason) {
    throw new Response("Sports season not found", { status: 404 });
  }

  const event = await getScoringEventById(params.eventId);

  if (!event) {
    throw new Response("Event not found", { status: 404 });
  }

  const participants = await findParticipantsBySportsSeasonId(params.id);
  const results = await getEventResults(params.eventId);
  const participantResults = await findParticipantResultsBySportsSeasonId(params.id);

  // For final_standings events, also get season results
  let seasonResults = null;
  if (event.eventType === "final_standings") {
    seasonResults = await getSeasonResults(params.id);
  }

  // For qualifying events, get QP config
  let qpConfig = null;
  if (event.isQualifyingEvent) {
    qpConfig = await getQPConfig(params.id);
  }

  // For qualifying sports seasons, get QP standings
  let qpStandings = null;
  if (sportsSeason.scoringPattern === "qualifying_points") {
    qpStandings = await getQPStandings(params.id);
  }

  return {
    sportsSeason: sportsSeason as typeof sportsSeason & {
      sport: { id: string; name: string; type: string; slug: string };
    },
    event,
    participants,
    results,
    participantResults,
    seasonResults,
    qpConfig,
    qpStandings,
  };
}

export async function action({ request, params }: Route.ActionArgs) {
  const formData = await request.formData();
  const intent = formData.get("intent");

  if (intent === "mark-qualifying") {
    try {
      const event = await getScoringEventById(params.eventId);
      if (!event) {
        return { error: "Event not found" };
      }

      // Update the event to mark it as a qualifying event
      const db = database();
      await db.update(schema.scoringEvents)
        .set({ isQualifyingEvent: true })
        .where(eq(schema.scoringEvents.id, params.eventId));

      return { success: "Event marked as qualifying event!" };
    } catch (error) {
      logger.error("Error marking event as qualifying:", error);
      return { error: "Failed to mark event as qualifying" };
    }
  }

  if (intent === "process-qp") {
    try {
      await processQualifyingEvent(params.eventId);
      return { success: "Qualifying points processed and awarded!" };
    } catch (error) {
      logger.error("Error processing qualifying points:", error);
      return { error: error instanceof Error ? error.message : "Failed to process qualifying points" };
    }
  }

  if (intent === "complete") {
    try {
      const event = await getScoringEventById(params.eventId);
      if (!event) {
        return { error: "Event not found" };
      }

      await completeScoringEvent(params.eventId);

      // If this is a final_standings event, process season standings
      if (event.eventType === "final_standings") {
        await processSeasonStandings(params.id);
        return { success: "Event completed and fantasy placements assigned to top 8!" };
      }

      // If this is a qualifying event, process qualifying points
      if (event.isQualifyingEvent) {
        await processQualifyingEvent(params.eventId);
        return { success: "Event completed and qualifying points awarded!" };
      }

      return { success: "Event marked as completed" };
    } catch (error) {
      logger.error("Error completing event:", error);
      return { error: "Failed to complete event" };
    }
  }

  if (intent === "uncomplete") {
    try {
      await updateScoringEvent(params.eventId, { isComplete: false });
      return { success: "Event marked as not updated" };
    } catch (error) {
      logger.error("Error uncompleting event:", error);
      return { error: "Failed to update event" };
    }
  }

  if (intent === "update-event") {
    const name = formData.get("name");
    const eventStartsAtRaw = formData.get("eventStartsAt");

    if (typeof name !== "string" || !name.trim()) {
      return { error: "Event name is required" };
    }

    // eventStartsAt is a UTC ISO string from the client; empty string means "clear it"
    const eventStartsAt: Date | null | undefined =
      typeof eventStartsAtRaw === "string"
        ? eventStartsAtRaw
          ? new Date(eventStartsAtRaw)
          : null
        : undefined;

    // Derive eventDate from eventStartsAt; null when cleared
    const eventDate: Date | null | undefined =
      eventStartsAt !== undefined
        ? eventStartsAt
          ? new Date(eventStartsAt.toISOString().split("T")[0])
          : null
        : undefined;

    try {
      await updateScoringEvent(params.eventId, {
        name: name.trim(),
        eventDate,
        eventStartsAt,
      });
      return { success: "Event updated" };
    } catch (error) {
      logger.error("Error updating event:", error);
      return { error: "Failed to update event" };
    }
  }

  if (intent === "add-result") {
    const participantId = formData.get("participantId");
    const placement = formData.get("placement");

    if (typeof participantId !== "string" || !participantId) {
      return { error: "Participant is required" };
    }

    if (typeof placement !== "string" || !placement) {
      return { error: "Placement is required" };
    }

    const placementNum = parseInt(placement, 10);
    if (isNaN(placementNum) || placementNum < 1 || placementNum > 100) {
      return { error: "Placement must be between 1 and 100" };
    }

    const resultData: CreateEventResultData = {
      scoringEventId: params.eventId,
      participantId,
      placement: placementNum,
    };

    try {
      await createEventResult(resultData);
      return { success: "Result added successfully" };
    } catch (error) {
      logger.error("Error adding result:", error);
      return { error: "Failed to add result" };
    }
  }

  if (intent === "update-result") {
    const resultId = formData.get("resultId");
    const placement = formData.get("placement");

    if (typeof resultId !== "string" || !resultId) {
      return { error: "Result ID is required" };
    }

    if (typeof placement !== "string" || !placement) {
      return { error: "Placement is required" };
    }

    const placementNum = parseInt(placement, 10);
    if (isNaN(placementNum) || placementNum < 1 || placementNum > 100) {
      return { error: "Placement must be between 1 and 100" };
    }

    const updateData: UpdateEventResultData = {
      placement: placementNum,
    };

    try {
      await updateEventResult(resultId, updateData);
      return { success: "Result updated successfully" };
    } catch (error) {
      logger.error("Error updating result:", error);
      return { error: "Failed to update result" };
    }
  }

  if (intent === "delete-result") {
    const resultId = formData.get("resultId");

    if (typeof resultId !== "string" || !resultId) {
      return { error: "Result ID is required" };
    }

    try {
      await deleteEventResult(resultId);
      return { success: "Result deleted successfully" };
    } catch (error) {
      logger.error("Error deleting result:", error);
      return { error: "Failed to delete result" };
    }
  }

  if (intent === "update-standings") {
    // Bulk update season standings for final_standings events
    try {
      // Parse all form fields and collect participants with points
      const participantPoints: Array<{ participantId: string; points: number }> = [];

      for (const [key, value] of formData.entries()) {
        if (key.startsWith("points-")) {
          const participantId = key.replace("points-", "");
          const points = value ? parseFloat(value as string) : 0;

          if (points > 0) {
            participantPoints.push({ participantId, points });
          }
        }
      }

      // Sort by points descending to determine positions
      participantPoints.sort((a, b) => b.points - a.points);

      // Assign positions based on sorted order and update
      for (let i = 0; i < participantPoints.length; i++) {
        const { participantId, points } = participantPoints[i];
        const position = i + 1; // Position is 1-based

        await upsertParticipantSeasonResult(
          {
            participantId,
            sportsSeasonId: params.id,
            currentPoints: points,
            currentPosition: position,
          }
        );
      }

      // Also update participants with 0 or no points (they don't have a position)
      for (const [key, value] of formData.entries()) {
        if (key.startsWith("points-")) {
          const participantId = key.replace("points-", "");
          const points = value ? parseFloat(value as string) : 0;

          if (points === 0) {
            await upsertParticipantSeasonResult(
              {
                participantId,
                sportsSeasonId: params.id,
                currentPoints: 0,
                currentPosition: undefined,
              }
            );
          }
        }
      }

      return { success: `Updated standings for ${participantPoints.length} participants (positions auto-calculated from points)` };
    } catch (error) {
      logger.error("Error updating season standings:", error);
      return { error: "Failed to update season standings" };
    }
  }

  return { error: "Invalid action" };
}
