import { logger } from "@/lib/logger";
import type { Match, MatchInput } from "@/features/matches/types";
import type PocketBase from "pocketbase";
import { transformMatch } from "../util/transform-types";

export function createMatchesService(pb: PocketBase) {
  return {
    createBatch() {
      return pb.createBatch();
    },

    async getMatch(id: string): Promise<Match | null> {
      const result = await pb.collection("matches").getOne(id, {
        expand: "tournament, home, away, home.players, away.players",
      });
      return transformMatch(result);
    },

    async getChildMatches(matchId: string): Promise<{ winner: Match | undefined, loser: Match | undefined }> {
      const match = await this.getMatch(matchId);
      if (!match) throw new Error("Match not found")
      
      const result = await pb.collection("matches").getFullList({
        filter: `tournament="${match.tournament.id}" && (home_from_lid = ${match.lid} || away_from_lid = ${match.lid}) && bye = false`,
        expand: "tournament, home, away, home.players, away.players",
      });

      const winnerMatch = result.find(m => (m.home_from_lid === match.lid && !m.home_from_loser) || (m.away_from_lid === match.lid && !m.away_from_loser));
      const loserMatch = result.find(m => (m.home_from_lid === match.lid && m.home_from_loser) || (m.away_from_lid === match.lid && m.away_from_loser));

      return {
        winner: winnerMatch ? transformMatch(winnerMatch) : undefined,
        loser: loserMatch ? transformMatch(loserMatch) : undefined
      }
    },

    async createMatch(data: MatchInput): Promise<Match> {
      const result = await pb.collection("matches").create<Match>(data);
      return result;
    },

    async createMatches(matches: MatchInput[]): Promise<Match[]> {
      logger.info("PocketBase | Creating multiple matches", {
        count: matches.length,
      });
      const results = await Promise.all(
        matches.map((match) => pb.collection("matches").create<Match>(match))
      );
      return results;
    },

    async updateMatch(id: string, data: Partial<MatchInput>): Promise<Match> {
      logger.info("PocketBase | Updating match", { id, data });
      const result = await pb.collection("matches").update<Match>(id, data, {
        expand: 'home, away, tournament, home.players, away.players'
      });
      return transformMatch(result);
    },

    async deleteMatch(id: string): Promise<void> {
      logger.info("PocketBase | Deleting match", id);
      await pb.collection("matches").delete(id);
    },

    async deleteMatchesByTournament(tournamentId: string): Promise<void> {
      logger.info("PocketBase | Deleting matches for tournament", tournamentId);
      const matches = await pb.collection("matches").getFullList({
        filter: `tournament = "${tournamentId}"`,
        fields: "id",
      });

      await Promise.all(
        matches.map((match) => pb.collection("matches").delete(match.id))
      );
    },

    async getMatchesBetweenPlayers(player1Id: string, player2Id: string): Promise<Match[]> {
      logger.info("PocketBase | Getting matches between players", { player1Id, player2Id });

      const player1Teams = await pb.collection("teams").getFullList({
        filter: `players ~ "${player1Id}"`,
        fields: "id",
      });

      const player2Teams = await pb.collection("teams").getFullList({
        filter: `players ~ "${player2Id}"`,
        fields: "id",
      });

      const player1TeamIds = player1Teams.map(t => t.id);
      const player2TeamIds = player2Teams.map(t => t.id);

      if (player1TeamIds.length === 0 || player2TeamIds.length === 0) {
        return [];
      }

      const allTeamIds = [...new Set([...player1TeamIds, ...player2TeamIds])];
      const batchSize = 10;
      const allMatches: any[] = [];

      for (let i = 0; i < allTeamIds.length; i += batchSize) {
        const batch = allTeamIds.slice(i, i + batchSize);
        const teamFilters = batch.map(id => `home="${id}" || away="${id}"`).join(' || ');

        const results = await pb.collection("matches").getFullList({
          filter: teamFilters,
          expand: "tournament, home, away, home.players, away.players",
          sort: "-created",
        });

        allMatches.push(...results);
      }

      const uniqueMatches = Array.from(
        new Map(allMatches.map(m => [m.id, m])).values()
      );

      return uniqueMatches
        .filter(match => {
          const homeTeamId = typeof match.home === 'string' ? match.home : match.home?.id;
          const awayTeamId = typeof match.away === 'string' ? match.away : match.away?.id;

          const player1InHome = player1TeamIds.includes(homeTeamId);
          const player1InAway = player1TeamIds.includes(awayTeamId);
          const player2InHome = player2TeamIds.includes(homeTeamId);
          const player2InAway = player2TeamIds.includes(awayTeamId);

          return (player1InHome && player2InAway) || (player1InAway && player2InHome);
        })
        .map(match => transformMatch(match));
    },

    async getMatchesBetweenTeams(team1Id: string, team2Id: string): Promise<Match[]> {
      logger.info("PocketBase | Getting matches between teams", { team1Id, team2Id });

      const filter = `(home="${team1Id}" && away="${team2Id}") || (home="${team2Id}" && away="${team1Id}")`;

      const results = await pb.collection("matches").getFullList({
        filter,
        expand: "tournament, home, away, home.players, away.players",
        sort: "-created",
      });

      return results.map(match => transformMatch(match));
    },

    async getMatchesByTournament(tournamentId: string): Promise<Match[]> {
      const results = await pb.collection("matches").getFullList({
        filter: `tournament = "${tournamentId}"`,
        expand: "tournament, home, away, home.players, away.players",
        sort: "lid",
      });
      return results.map(match => transformMatch(match));
    },

    async getMatchesByGroup(groupId: string): Promise<Match[]> {
      logger.info("PocketBase | Getting matches for group", { groupId });

      const results = await pb.collection("matches").getFullList({
        filter: `group = "${groupId}"`,
        expand: "tournament, home, away, home.players, away.players",
        sort: "created",
      });

      return results.map(match => transformMatch(match));
    },
  };
}
