import { database } from "~/database/context";
import * as schema from "~/database/schema";
import { eq, and, inArray } from "drizzle-orm";

export interface CreateEventResultData {
  scoringEventId: string;
  participantId: string;
  placement?: number;
  qualifyingPointsAwarded?: number;
  eliminated?: boolean;
  rawScore?: number;
}

export interface UpdateEventResultData {
  placement?: number;
  qualifyingPointsAwarded?: number;
  eliminated?: boolean;
  rawScore?: number;
}

/**
 * Create an event result for a participant
 */
export async function createEventResult(
  data: CreateEventResultData,
  providedDb?: ReturnType<typeof database>
) {
  const db = providedDb || database();

  const [result] = await db
    .insert(schema.eventResults)
    .values({
      scoringEventId: data.scoringEventId,
      participantId: data.participantId,
      placement: data.placement,
      qualifyingPointsAwarded: data.qualifyingPointsAwarded?.toString(),
      eliminated: data.eliminated,
      rawScore: data.rawScore?.toString(),
    })
    .returning();

  return result;
}

/**
 * Create multiple event results in bulk
 * Useful for entering all results for a tournament at once
 */
export async function createEventResultsBulk(
  results: CreateEventResultData[],
  providedDb?: ReturnType<typeof database>
) {
  const db = providedDb || database();

  const inserted = await db
    .insert(schema.eventResults)
    .values(
      results.map((r) => ({
        scoringEventId: r.scoringEventId,
        participantId: r.participantId,
        placement: r.placement,
        qualifyingPointsAwarded: r.qualifyingPointsAwarded?.toString(),
        eliminated: r.eliminated,
        rawScore: r.rawScore?.toString(),
      }))
    )
    .returning();

  return inserted;
}

/**
 * Get an event result by ID
 */
export async function getEventResultById(
  resultId: string,
  providedDb?: ReturnType<typeof database>
) {
  const db = providedDb || database();

  return await db.query.eventResults.findFirst({
    where: eq(schema.eventResults.id, resultId),
    with: {
      participant: {
        with: {
          sportsSeason: {
            with: {
              sport: true,
            },
          },
        },
      },
      scoringEvent: true,
    },
  });
}

/**
 * Get all results for a scoring event
 */
export async function getEventResults(
  eventId: string,
  providedDb?: ReturnType<typeof database>
) {
  const db = providedDb || database();

  return await db.query.eventResults.findMany({
    where: eq(schema.eventResults.scoringEventId, eventId),
    orderBy: schema.eventResults.placement,
    with: {
      participant: {
        with: {
          sportsSeason: {
            with: {
              sport: true,
            },
          },
        },
      },
    },
  });
}

/**
 * Get all event results for a participant across all events
 */
export async function getParticipantEventResults(
  participantId: string,
  providedDb?: ReturnType<typeof database>
) {
  const db = providedDb || database();

  return await db.query.eventResults.findMany({
    where: eq(schema.eventResults.participantId, participantId),
    with: {
      scoringEvent: true,
    },
    orderBy: schema.eventResults.createdAt,
  });
}

/**
 * Update an event result
 */
export async function updateEventResult(
  resultId: string,
  data: UpdateEventResultData,
  providedDb?: ReturnType<typeof database>
) {
  const db = providedDb || database();

  const [updated] = await db
    .update(schema.eventResults)
    .set({
      placement: data.placement,
      qualifyingPointsAwarded: data.qualifyingPointsAwarded?.toString(),
      eliminated: data.eliminated,
      rawScore: data.rawScore?.toString(),
      updatedAt: new Date(),
    })
    .where(eq(schema.eventResults.id, resultId))
    .returning();

  return updated;
}

/**
 * Delete an event result
 */
export async function deleteEventResult(
  resultId: string,
  providedDb?: ReturnType<typeof database>
) {
  const db = providedDb || database();

  await db.delete(schema.eventResults).where(eq(schema.eventResults.id, resultId));
}

/**
 * Delete all results for a scoring event
 */
export async function deleteEventResults(
  eventId: string,
  providedDb?: ReturnType<typeof database>
) {
  const db = providedDb || database();

  await db
    .delete(schema.eventResults)
    .where(eq(schema.eventResults.scoringEventId, eventId));
}

/**
 * Check if a participant has a result for a specific event
 */
export async function hasParticipantResult(
  eventId: string,
  participantId: string,
  providedDb?: ReturnType<typeof database>
): Promise<boolean> {
  const db = providedDb || database();

  const result = await db.query.eventResults.findFirst({
    where: and(
      eq(schema.eventResults.scoringEventId, eventId),
      eq(schema.eventResults.participantId, participantId)
    ),
  });

  return !!result;
}

/**
 * Get results for multiple participants in a specific event
 * Useful for checking drafted participants' performance
 */
export async function getEventResultsForParticipants(
  eventId: string,
  participantIds: string[],
  providedDb?: ReturnType<typeof database>
) {
  const db = providedDb || database();

  if (participantIds.length === 0) return [];

  return await db.query.eventResults.findMany({
    where: and(
      eq(schema.eventResults.scoringEventId, eventId),
      inArray(schema.eventResults.participantId, participantIds)
    ),
    with: {
      participant: {
        with: {
          sportsSeason: {
            with: {
              sport: true,
            },
          },
        },
      },
    },
  });
}
