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

export type TournamentGroup = typeof schema.tournamentGroups.$inferSelect;
export type TournamentGroupMember = typeof schema.tournamentGroupMembers.$inferSelect;

/**
 * Create empty tournament groups for a scoring event
 */
export async function createGroupsForEvent(
  eventId: string,
  groupLabels: string[]
): Promise<TournamentGroup[]> {
  const db = database();
  const groups = await db
    .insert(schema.tournamentGroups)
    .values(
      groupLabels.map((label) => ({
        scoringEventId: eventId,
        groupName: label,
      }))
    )
    .returning();
  return groups;
}

/**
 * Add participants to a tournament group
 */
export async function addMembersToGroup(
  groupId: string,
  participantIds: string[]
): Promise<TournamentGroupMember[]> {
  const db = database();
  const members = await db
    .insert(schema.tournamentGroupMembers)
    .values(
      participantIds.map((participantId) => ({
        tournamentGroupId: groupId,
        participantId,
      }))
    )
    .returning();
  return members;
}

/**
 * Find all tournament groups for a scoring event with members and participant data
 */
export async function findGroupsByEventId(eventId: string) {
  const db = database();
  return await db.query.tournamentGroups.findMany({
    where: eq(schema.tournamentGroups.scoringEventId, eventId),
    orderBy: (groups, { asc }) => [asc(groups.groupName)],
    with: {
      members: {
        with: {
          participant: true,
        },
        orderBy: (members, { asc }) => [asc(members.createdAt)],
      },
    },
  });
}

/**
 * Toggle the eliminated status of a group member
 */
export async function toggleMemberEliminated(
  memberId: string
): Promise<TournamentGroupMember> {
  const db = database();

  // Get current state
  const member = await db.query.tournamentGroupMembers.findFirst({
    where: eq(schema.tournamentGroupMembers.id, memberId),
  });

  if (!member) {
    throw new Error("Tournament group member not found");
  }

  const [updated] = await db
    .update(schema.tournamentGroupMembers)
    .set({
      eliminated: !member.eliminated,
      updatedAt: new Date(),
    })
    .where(eq(schema.tournamentGroupMembers.id, memberId))
    .returning();

  return updated;
}

/**
 * Get participant IDs of non-eliminated group members (advancing teams)
 */
export async function getAdvancingParticipantIds(
  eventId: string
): Promise<string[]> {
  const db = database();
  const groups = await db.query.tournamentGroups.findMany({
    where: eq(schema.tournamentGroups.scoringEventId, eventId),
    with: {
      members: {
        where: eq(schema.tournamentGroupMembers.eliminated, false),
      },
    },
  });

  return groups.flatMap((g) => g.members.map((m) => m.participantId));
}

/**
 * Get participant IDs of eliminated group members
 */
export async function getEliminatedParticipantIds(
  eventId: string
): Promise<string[]> {
  const db = database();
  const groups = await db.query.tournamentGroups.findMany({
    where: eq(schema.tournamentGroups.scoringEventId, eventId),
    with: {
      members: {
        where: eq(schema.tournamentGroupMembers.eliminated, true),
      },
    },
  });

  return groups.flatMap((g) => g.members.map((m) => m.participantId));
}

/**
 * Delete all tournament groups for a scoring event (for regeneration)
 */
export async function deleteGroupsByEventId(eventId: string): Promise<void> {
  const db = database();
  // Members cascade-delete when groups are deleted
  await db
    .delete(schema.tournamentGroups)
    .where(eq(schema.tournamentGroups.scoringEventId, eventId));
}
