import { logger } from "@/lib/logger";
import type {
  Tournament,
  TournamentInfo,
  TournamentInput,
  TournamentUpdateInput,
} from "@/features/tournaments/types";
import type { Team } from "@/features/teams/types";
import PocketBase from "pocketbase";
import { transformFreeAgent, transformTournament, transformTournamentInfo } from "@/lib/pocketbase/util/transform-types";
import { transformTeam } from "@/lib/pocketbase/util/transform-types";
import { PlayerInfo } from "@/features/players/types";

export function createTournamentsService(pb: PocketBase) {
  return {
    async getTournament(id: string, isAdmin: boolean = false): Promise<Tournament> {
      const [tournamentResult, teamStatsResult, groupsResult] = await Promise.all([
        pb.collection("tournaments").getOne(id, {
          expand: "teams, teams.players, matches, matches.tournament, matches.home, matches.away, matches.home.players, matches.away.players",
        }),
        pb.collection("team_stats_per_tournament").getFullList({
          filter: `tournament_id = "${id}"`,
          sort: "-wins,-total_cups_made"
        }),
        pb.collection("groups").getFullList({
          filter: `tournament = "${id}"`,
          sort: "order",
          expand: "teams, teams.players"
        })
      ]);

      tournamentResult.team_stats = teamStatsResult;
      tournamentResult.groups = groupsResult;

      return transformTournament(tournamentResult, isAdmin);
    },
    async getMostRecentTournament(): Promise<Tournament> {
      const mostRecent = await pb
        .collection("tournaments")
        .getFirstListItem('', {
          fields: "id",
          sort: "-start_time",
        });

      const [result, teamStatsResult] = await Promise.all([
        pb.collection("tournaments").getOne(mostRecent.id, {
          expand: "teams, teams.players, matches, matches.tournament, matches.home, matches.away, matches.home.players, matches.away.players",
        }),
        pb.collection("team_stats_per_tournament").getFullList({
          filter: `tournament_id = "${mostRecent.id}"`,
          sort: "-wins,-total_cups_made"
        }),
      ]);

      result.team_stats = teamStatsResult;

      return transformTournament(result);
    },
    async listTournaments(): Promise<TournamentInfo[]> {
      const result = await pb
        .collection("tournaments")
        .getFullList({
          expand: "teams,teams.players,matches",
          sort: "-start_time",
        });

      let allTeamStats: any[] = [];
      if (result.length > 0) {
        const statsFilter = result
          .map((tournament) => `tournament_id = "${tournament.id}"`)
          .join(" || ");
        allTeamStats = await pb.collection("team_stats_per_tournament").getFullList({
          filter: statsFilter,
          sort: "-wins,-total_cups_made"
        });
      }

      const statsByTournament = new Map<string, any[]>();
      for (const stat of allTeamStats) {
        const key = stat.tournament_id as string;
        const group = statsByTournament.get(key);
        if (group) {
          group.push(stat);
        } else {
          statsByTournament.set(key, [stat]);
        }
      }

      for (const tournament of result) {
        tournament.team_stats = statsByTournament.get(tournament.id) ?? [];
      }

      return result.map(transformTournamentInfo);
    },
    async createTournament(data: TournamentInput): Promise<Tournament> {
      const result = await pb
        .collection("tournaments")
        .create<Tournament>(data);
      return transformTournament(result);
    },
    async updateTournament(
      id: string,
      data: Partial<TournamentUpdateInput>
    ): Promise<Tournament> {
      const result = await pb
        .collection("tournaments")
        .update<Tournament>(id, data);
      return transformTournament(result);
    },
    async enrollTeam(
      tournamentId: string,
      teamId: string
    ): Promise<Tournament> {
      const result = await pb
        .collection("tournaments")
        .update<Tournament>(
          tournamentId,
          { "teams+": teamId },
          { expand: "teams, teams.players" }
        );

      await pb
        .collection("teams")
        .update(teamId, { "tournaments+": tournamentId });

      return transformTournament(result);
    },
    async unenrollTeam(
      tournamentId: string,
      teamId: string
    ): Promise<Tournament> {
      const result = await pb
        .collection("tournaments")
        .update<Tournament>(
          tournamentId,
          { "teams-": teamId },
          { expand: "teams, teams.players" }
        );

      await pb
        .collection("teams")
        .update(teamId, { "tournaments-": tournamentId });

      return transformTournament(result);
    },
    async updateTournamentMatches(
      tournamentId: string,
      matchIds: string[]
    ): Promise<Tournament> {
      logger.info("PocketBase | Updating tournament matches", { tournamentId, matchCount: matchIds.length });
      const result = await pb
        .collection("tournaments")
        .update<Tournament>(tournamentId, {
          matches: matchIds
        });
      return transformTournament(result);
    },
    async getUnenrolledTeams(tournamentId: string): Promise<Team[]> {
      try {
        const tournament = await pb
          .collection("tournaments")
          .getOne(tournamentId, {
            fields: "teams",
          });

        const enrolledTeamIds = tournament.teams || [];
        if (enrolledTeamIds.length === 0) {
          const allTeams = await pb.collection("teams").getFullList({
            expand: "players",
          });
          return allTeams.map(transformTeam);
        }

        const filter = enrolledTeamIds
          .map((teamId: string) => `id != "${teamId}"`)
          .join(" && ");

        const availableTeams = await pb.collection("teams").getFullList({
          filter,
          expand: "players",
        });

        return availableTeams.map(transformTeam);
      } catch (error) {
        logger.error("PocketBase | Error getting unenrolled teams", error);
        throw error;
      }
    },
    async enrollFreeAgent(playerId: string, phone: string, tournamentId: string): Promise<void> {
      await pb.collection("free_agents").create({
        tournament: tournamentId,
        player: playerId,
        phone: phone
      });
    },

    async unenrollFreeAgent(playerId: string, tournamentId: string): Promise<void> {
      const result = await pb.collection("free_agents").getFirstListItem(
        `player = "${playerId}" && tournament = "${tournamentId}"`
      );
      await pb.collection("free_agents").delete(result.id);
    },
    async getFreeAgents(tournamentId: string): Promise<{ id: string, phone: string, player: PlayerInfo | undefined }[]> {
      try {
        const free_agents = await pb
          .collection("free_agents")
          .getFullList({ filter: `tournament = "${tournamentId}"`,
            expand: 'player'
          });

        return free_agents.map(transformFreeAgent);
      } catch (error) {
        logger.error("PocketBase | Error getting unenrolled teams", error);
        throw error;
      }
    },
  };
}
