import { omitBy, isNil } from 'lodash-es';

import api from 'src/config/api';
import {
  ProdeAccessResponse,
  Competition,
  CompetitionDetail,
  FixtureResponse,
  MatchWithPrediction,
  MatchesPage,
  Prediction,
  SavePredictionRequest,
  TournamentPredictionResponse,
  SaveTournamentPredictionRequest,
  TournamentPrediction,
  TeamWithGroup,
  RankingPage,
  UserRankingSummary,
  PrizesResponse,
  CompetitionRules,
  RankingStatus,
  Match,
  MatchBreakdownResponse,
  MatchFilter,
  type UserStatsResponse,
} from 'src/types/prode';

export type { MatchFilter };

const BASE_URL = '/prode';

// Access
export const getProdeAccess = () =>
  api.get<ProdeAccessResponse>(`${BASE_URL}/access`);

// Competitions
export const getCompetitions = () =>
  api.get<Competition[]>(`${BASE_URL}/competitions`);

export const getCompetition = (competitionId: number) =>
  api.get<CompetitionDetail>(`${BASE_URL}/competitions/${competitionId}`);

// Fixture
export const getFixture = (
  competitionId: number,
  params?: { stageId?: number; groupId?: number; round?: number },
) =>
  api.get<FixtureResponse>(
    `${BASE_URL}/competitions/${competitionId}/fixture`,
    {
      params,
    },
  );

// Matches - API returns cursor-paginated MatchWithPrediction[]
export const getMatches = (
  competitionId: number,
  params?: { filter?: MatchFilter; stageId?: number; cursor?: string },
) =>
  api.get<MatchesPage>(`${BASE_URL}/competitions/${competitionId}/matches`, {
    params: omitBy(
      {
        status: params?.filter !== MatchFilter.All ? params?.filter : null,
        stageId: params?.stageId,
        cursor: params?.cursor,
      },
      isNil,
    ),
  });

export const getNextMatch = (competitionId: number) =>
  api.get<Match>(`${BASE_URL}/competitions/${competitionId}/next-match`);

export const getNextToPredict = (competitionId: number) =>
  api.get<MatchWithPrediction>(
    `${BASE_URL}/competitions/${competitionId}/next-to-predict`,
  );

// Results
export const getResults = (competitionId: number) =>
  api.get<MatchWithPrediction[]>(
    `${BASE_URL}/competitions/${competitionId}/results`,
  );

// Predictions
export const getPredictions = (competitionId: number) =>
  api.get<MatchWithPrediction[]>(
    `${BASE_URL}/competitions/${competitionId}/predictions`,
  );

export const savePrediction = (
  competitionId: number,
  data: SavePredictionRequest,
) =>
  api.post<Prediction>(
    `${BASE_URL}/competitions/${competitionId}/predictions`,
    data,
  );

// Tournament Predictions
export const getTournamentPrediction = (competitionId: number) =>
  api.get<TournamentPredictionResponse>(
    `${BASE_URL}/competitions/${competitionId}/tournament-prediction`,
  );

export const saveTournamentPrediction = (
  competitionId: number,
  data: SaveTournamentPredictionRequest,
) =>
  api.post<TournamentPrediction>(
    `${BASE_URL}/competitions/${competitionId}/tournament-prediction`,
    data,
  );

// Teams
export type TeamsPage = {
  data: TeamWithGroup[];
  nextCursor: string | null;
  hasMore: boolean;
};

export const getTeams = (
  competitionId: number,
  params?: { search?: string; cursor?: string; limit?: number },
) =>
  api.get<TeamsPage>(`${BASE_URL}/competitions/${competitionId}/teams`, {
    params: {
      ...(params?.search && { search: params.search }),
      ...(params?.cursor && { cursor: params.cursor }),
      ...(params?.limit && { limit: params.limit }),
    },
  });

// Ranking
export const getRanking = (
  competitionId: number,
  params?: { offset?: number; limit?: number },
) =>
  api.get<RankingPage>(`${BASE_URL}/competitions/${competitionId}/ranking`, {
    params,
  });

export const getUserRanking = (competitionId: number) =>
  api.get<UserRankingSummary>(
    `${BASE_URL}/competitions/${competitionId}/ranking/me`,
  );

// Prizes
export const getPrizes = (competitionId: number) =>
  api.get<PrizesResponse>(`${BASE_URL}/competitions/${competitionId}/prizes`);

// Rules
export const getRules = (competitionId: number) =>
  api.get<CompetitionRules>(`${BASE_URL}/competitions/${competitionId}/rules`);

// Ranking Status
export const getRankingStatus = (competitionId: number) =>
  api.get<RankingStatus>(
    `${BASE_URL}/competitions/${competitionId}/ranking-status`,
  );

// User Stats
export const getUserStats = (competitionId: number, userId: number) =>
  api.get<UserStatsResponse>(
    `${BASE_URL}/competitions/${competitionId}/stats/${userId}`,
  );

// Match Breakdown
export const getMatchBreakdown = (competitionId: number, matchId: number) =>
  api.get<MatchBreakdownResponse>(
    `${BASE_URL}/competitions/${competitionId}/matches/${matchId}/breakdown`,
  );

// Query Keys for React Query
export const prodeKeys = {
  all: ['prode'] as const,
  access: () => [...prodeKeys.all, 'access'] as const,
  competitions: () => [...prodeKeys.all, 'competitions'] as const,
  competition: (id: number) => [...prodeKeys.competitions(), id] as const,
  fixture: (competitionId: number, filters?: object) =>
    [...prodeKeys.competition(competitionId), 'fixture', filters] as const,
  matchesAll: (competitionId: number) =>
    [...prodeKeys.competition(competitionId), 'matches'] as const,
  matches: (
    competitionId: number,
    params?: { filter?: MatchFilter; stageId?: number },
  ) => [...prodeKeys.matchesAll(competitionId), params] as const,
  nextMatch: (competitionId: number) =>
    [...prodeKeys.competition(competitionId), 'next-match'] as const,
  nextToPredict: (competitionId: number) =>
    [...prodeKeys.competition(competitionId), 'next-to-predict'] as const,
  results: (competitionId: number) =>
    [...prodeKeys.competition(competitionId), 'results'] as const,
  predictions: (competitionId: number) =>
    [...prodeKeys.competition(competitionId), 'predictions'] as const,
  tournamentPrediction: (competitionId: number) =>
    [...prodeKeys.competition(competitionId), 'tournament-prediction'] as const,
  teamsBase: (competitionId: number) =>
    [...prodeKeys.competition(competitionId), 'teams'] as const,
  teams: (competitionId: number, search?: string) =>
    [...prodeKeys.teamsBase(competitionId), search] as const,
  ranking: (competitionId: number, params?: object) =>
    [...prodeKeys.competition(competitionId), 'ranking', params] as const,
  userRanking: (competitionId: number) =>
    [...prodeKeys.competition(competitionId), 'ranking-me'] as const,
  prizes: (competitionId: number) =>
    [...prodeKeys.competition(competitionId), 'prizes'] as const,
  rules: (competitionId: number) =>
    [...prodeKeys.competition(competitionId), 'rules'] as const,
  rankingStatus: (competitionId: number) =>
    [...prodeKeys.competition(competitionId), 'ranking-status'] as const,
  matchBreakdown: (competitionId: number, matchId: number) =>
    [
      ...prodeKeys.competition(competitionId),
      'matches',
      matchId,
      'breakdown',
    ] as const,
  userStats: (competitionId: number, userId: number) =>
    [...prodeKeys.competition(competitionId), 'stats', userId] as const,
};
