import { BaseApiClient } from '../base/BaseApiClient';
import type { AllLeaguesWithCapacityDTO } from '../../types/generated/AllLeaguesWithCapacityDTO';
import type { TotalLeaguesDTO } from '../../types/generated/TotalLeaguesDTO';
import type { LeagueStandingsDTO } from '../../types/generated/LeagueStandingsDTO';
import type { LeagueScheduleDTO } from '../../types/generated/LeagueScheduleDTO';
import type { LeagueMembershipsDTO } from '../../types/generated/LeagueMembershipsDTO';
import type { CreateLeagueInputDTO } from '../../types/generated/CreateLeagueInputDTO';
import type { CreateLeagueOutputDTO } from '../../types/generated/CreateLeagueOutputDTO';
import type { SponsorshipDetailDTO } from '../../types/generated/SponsorshipDetailDTO';
import type { RaceDTO } from '../../types/generated/RaceDTO';
import type { GetLeagueAdminConfigOutputDTO } from '../../types/generated/GetLeagueAdminConfigOutputDTO';
import type { LeagueScoringPresetDTO } from '../../types/generated/LeagueScoringPresetDTO';
import type { LeagueSeasonSummaryDTO } from '../../types/generated/LeagueSeasonSummaryDTO';
import type { CreateLeagueScheduleRaceInputDTO } from '../../types/generated/CreateLeagueScheduleRaceInputDTO';
import type { CreateLeagueScheduleRaceOutputDTO } from '../../types/generated/CreateLeagueScheduleRaceOutputDTO';
import type { UpdateLeagueScheduleRaceInputDTO } from '../../types/generated/UpdateLeagueScheduleRaceInputDTO';
import type { LeagueScheduleRaceMutationSuccessDTO } from '../../types/generated/LeagueScheduleRaceMutationSuccessDTO';
import type { LeagueSeasonSchedulePublishOutputDTO } from '../../types/generated/LeagueSeasonSchedulePublishOutputDTO';
import type { LeagueRosterMemberDTO } from '../../types/generated/LeagueRosterMemberDTO';
import type { LeagueRosterJoinRequestDTO } from '../../types/generated/LeagueRosterJoinRequestDTO';
import type { ApproveJoinRequestOutputDTO } from '../../types/generated/ApproveJoinRequestOutputDTO';
import type { RejectJoinRequestOutputDTO } from '../../types/generated/RejectJoinRequestOutputDTO';
import type { UpdateLeagueMemberRoleOutputDTO } from '../../types/generated/UpdateLeagueMemberRoleOutputDTO';
import type { RemoveLeagueMemberOutputDTO } from '../../types/generated/RemoveLeagueMemberOutputDTO';
import type { AllLeaguesWithCapacityAndScoringDTO } from '../../types/AllLeaguesWithCapacityAndScoringDTO';

function isRecord(value: unknown): value is Record<string, unknown> {
  return typeof value === 'object' && value !== null;
}

function isRaceDTO(value: unknown): value is RaceDTO {
  if (!isRecord(value)) return false;
  return typeof value.id === 'string' && typeof value.name === 'string' && typeof value.date === 'string';
}

function parseRaceDTOArray(value: unknown): RaceDTO[] {
  if (!Array.isArray(value)) return [];
  return value.filter(isRaceDTO);
}

/**
 * Leagues API Client
 *
 * Handles all league-related API operations.
 */
export class LeaguesApiClient extends BaseApiClient {
  /** Get all leagues with capacity information */
  getAllWithCapacity(): Promise<AllLeaguesWithCapacityDTO> {
    return this.get<AllLeaguesWithCapacityDTO>('/leagues/all-with-capacity');
  }

  /** Get all leagues with capacity + scoring summary (for leagues page filters) */
  getAllWithCapacityAndScoring(): Promise<AllLeaguesWithCapacityAndScoringDTO> {
    return this.get<AllLeaguesWithCapacityAndScoringDTO>('/leagues/all-with-capacity-and-scoring');
  }

  /** Get total number of leagues */
  getTotal(): Promise<TotalLeaguesDTO> {
    return this.get<TotalLeaguesDTO>('/leagues/total-leagues');
  }

  /** Get league standings */
  getStandings(leagueId: string): Promise<LeagueStandingsDTO> {
    return this.get<LeagueStandingsDTO>(`/leagues/${leagueId}/standings`);
  }

  /** Get league schedule */
  getSchedule(leagueId: string, seasonId?: string): Promise<LeagueScheduleDTO> {
    const qs = seasonId ? `?seasonId=${encodeURIComponent(seasonId)}` : '';
    return this.get<LeagueScheduleDTO>(`/leagues/${leagueId}/schedule${qs}`);
  }

  /** Get league memberships */
  getMemberships(leagueId: string): Promise<LeagueMembershipsDTO> {
    return this.get<LeagueMembershipsDTO>(`/leagues/${leagueId}/memberships`);
  }

  /** Create a new league */
  create(input: CreateLeagueInputDTO): Promise<CreateLeagueOutputDTO> {
    return this.post<CreateLeagueOutputDTO>('/leagues', input);
  }

  /** Remove a member from league */
  removeMember(leagueId: string, performerDriverId: string, targetDriverId: string): Promise<{ success: boolean }> {
    return this.patch<{ success: boolean }>(`/leagues/${leagueId}/members/${targetDriverId}/remove`, { performerDriverId });
  }

  /** Update a member's role in league */
  updateMemberRole(leagueId: string, performerDriverId: string, targetDriverId: string, newRole: string): Promise<{ success: boolean }> {
    return this.patch<{ success: boolean }>(`/leagues/${leagueId}/members/${targetDriverId}/role`, { performerDriverId, newRole });
  }

  /** Get league seasons */
  getSeasons(leagueId: string): Promise<LeagueSeasonSummaryDTO[]> {
    return this.get<LeagueSeasonSummaryDTO[]>(`/leagues/${leagueId}/seasons`);
  }

  /** Get season sponsorships */
  getSeasonSponsorships(seasonId: string): Promise<{ sponsorships: SponsorshipDetailDTO[] }> {
    return this.get<{ sponsorships: SponsorshipDetailDTO[] }>(`/leagues/seasons/${seasonId}/sponsorships`);
  }

  /** Get league config */
  getLeagueConfig(leagueId: string): Promise<GetLeagueAdminConfigOutputDTO> {
    return this.get<GetLeagueAdminConfigOutputDTO>(`/leagues/${leagueId}/config`);
  }

  /** Get league scoring presets */
  getScoringPresets(): Promise<{ presets: LeagueScoringPresetDTO[] }> {
    return this.get<{ presets: LeagueScoringPresetDTO[] }>(`/leagues/scoring-presets`);
  }

  /** Transfer league ownership */
  transferOwnership(leagueId: string, currentOwnerId: string, newOwnerId: string): Promise<{ success: boolean }> {
    return this.post<{ success: boolean }>(`/leagues/${leagueId}/transfer-ownership`, {
      currentOwnerId,
      newOwnerId,
    });
  }

  /** Publish a league season schedule (admin/owner only; actor derived from session) */
  publishSeasonSchedule(leagueId: string, seasonId: string): Promise<LeagueSeasonSchedulePublishOutputDTO> {
    return this.post<LeagueSeasonSchedulePublishOutputDTO>(`/leagues/${leagueId}/seasons/${seasonId}/schedule/publish`, {});
  }

  /** Unpublish a league season schedule (admin/owner only; actor derived from session) */
  unpublishSeasonSchedule(leagueId: string, seasonId: string): Promise<LeagueSeasonSchedulePublishOutputDTO> {
    return this.post<LeagueSeasonSchedulePublishOutputDTO>(`/leagues/${leagueId}/seasons/${seasonId}/schedule/unpublish`, {});
  }

  /** Create a schedule race for a league season (admin/owner only; actor derived from session) */
  createSeasonScheduleRace(
    leagueId: string,
    seasonId: string,
    input: CreateLeagueScheduleRaceInputDTO,
  ): Promise<CreateLeagueScheduleRaceOutputDTO> {
    const { example: _example, ...payload } = input;
    return this.post<CreateLeagueScheduleRaceOutputDTO>(`/leagues/${leagueId}/seasons/${seasonId}/schedule/races`, payload);
  }

  /** Update a schedule race for a league season (admin/owner only; actor derived from session) */
  updateSeasonScheduleRace(
    leagueId: string,
    seasonId: string,
    raceId: string,
    input: UpdateLeagueScheduleRaceInputDTO,
  ): Promise<LeagueScheduleRaceMutationSuccessDTO> {
    const { example: _example, ...payload } = input;
    return this.patch<LeagueScheduleRaceMutationSuccessDTO>(`/leagues/${leagueId}/seasons/${seasonId}/schedule/races/${raceId}`, payload);
  }

  /** Delete a schedule race for a league season (admin/owner only; actor derived from session) */
  deleteSeasonScheduleRace(
    leagueId: string,
    seasonId: string,
    raceId: string,
  ): Promise<LeagueScheduleRaceMutationSuccessDTO> {
    return this.delete<LeagueScheduleRaceMutationSuccessDTO>(`/leagues/${leagueId}/seasons/${seasonId}/schedule/races/${raceId}`);
  }

  /** Get races for a league */
  async getRaces(leagueId: string): Promise<{ races: RaceDTO[] }> {
    const response = await this.get<{ races?: unknown }>(`/leagues/${leagueId}/races`);
    return { races: parseRaceDTOArray(response?.races) };
  }

  /** Admin roster: list current members (admin/owner only; actor derived from session) */
  getAdminRosterMembers(leagueId: string): Promise<LeagueRosterMemberDTO[]> {
    return this.get<LeagueRosterMemberDTO[]>(`/leagues/${leagueId}/admin/roster/members`);
  }

  /** Admin roster: list pending join requests (admin/owner only; actor derived from session) */
  getAdminRosterJoinRequests(leagueId: string): Promise<LeagueRosterJoinRequestDTO[]> {
    return this.get<LeagueRosterJoinRequestDTO[]>(`/leagues/${leagueId}/admin/roster/join-requests`);
  }

  /** Admin roster: approve a join request (admin/owner only; actor derived from session) */
  approveRosterJoinRequest(leagueId: string, joinRequestId: string): Promise<ApproveJoinRequestOutputDTO> {
    return this.post<ApproveJoinRequestOutputDTO>(`/leagues/${leagueId}/admin/roster/join-requests/${joinRequestId}/approve`, {});
  }

  /** Admin roster: reject a join request (admin/owner only; actor derived from session) */
  rejectRosterJoinRequest(leagueId: string, joinRequestId: string): Promise<RejectJoinRequestOutputDTO> {
    return this.post<RejectJoinRequestOutputDTO>(`/leagues/${leagueId}/admin/roster/join-requests/${joinRequestId}/reject`, {});
  }

  /** Admin roster: update member role (admin/owner only; actor derived from session) */
  updateRosterMemberRole(leagueId: string, targetDriverId: string, newRole: string): Promise<UpdateLeagueMemberRoleOutputDTO> {
    return this.patch<UpdateLeagueMemberRoleOutputDTO>(`/leagues/${leagueId}/admin/roster/members/${targetDriverId}/role`, { newRole });
  }

  /** Admin roster: remove member (admin/owner only; actor derived from session) */
  removeRosterMember(leagueId: string, targetDriverId: string): Promise<RemoveLeagueMemberOutputDTO> {
    return this.patch<RemoveLeagueMemberOutputDTO>(`/leagues/${leagueId}/admin/roster/members/${targetDriverId}/remove`, {});
  }
}
