import {
  Controller,
  Get,
  Post,
  Body,
  Param,
  Query,
  HttpCode,
  HttpStatus,
  NotFoundException,
  BadRequestException,
  UseInterceptors,
} from "@nestjs/common";
import { Public } from "../../common/decorators";
import {
  ApiTags,
  ApiOperation,
  ApiResponse,
  ApiQuery,
  ApiParam,
} from "@nestjs/swagger";
import { CacheInterceptor, CacheTTL } from "@nestjs/cache-manager";
import { MatchesService } from "./matches.service";
import {
  MatchQueryDto,
  Sport,
  LeagueWithMatchesDto,
  ActiveLeagueDto,
} from "./dto";

@ApiTags("Matches")
@Controller("matches")
export class MatchesController {
  constructor(private readonly matchesService: MatchesService) {}

  /**
   * POST /matches/query
   * Advanced match query with filters
   */
  @Public()
  @Post("query")
  @HttpCode(HttpStatus.OK)
  @ApiOperation({ summary: "Advanced match query with filters" })
  @ApiResponse({ status: 200, type: [LeagueWithMatchesDto] })
  async queryMatches(
    @Body() queryDto: MatchQueryDto,
  ): Promise<LeagueWithMatchesDto[]> {
    if (!queryDto.sport) {
      throw new BadRequestException("'sport' field is required");
    }

    const matchIds = await this.matchesService.findMatches(queryDto);

    if (matchIds.length === 0) {
      return [];
    }

    return this.matchesService.getMatchesAndStructureByIds(
      matchIds,
      queryDto.sport,
    );
  }

  /**
   * GET /matches
   * List matches with pagination
   */
  @Public()
  @Get()
  @ApiOperation({ summary: "List matches with pagination" })
  @ApiQuery({ name: "page", required: false, type: Number })
  @ApiQuery({ name: "limit", required: false, type: Number })
  @ApiQuery({ name: "sport", required: false, enum: Sport })
  @ApiResponse({
    status: 200,
    description: "Paginated list of matches",
    schema: {
      type: "object",
      properties: {
        data: { type: "array", items: { type: "object" } },
        meta: { type: "object" },
      },
    },
  })
  async listMatches(
    @Query("page") page?: string,
    @Query("limit") limit?: string,
    @Query("sport") sport?: Sport,
  ) {
    const pageNum = parseInt(page || "1", 10);
    const limitNum = parseInt(limit || "20", 10);
    const sportType = sport || Sport.FOOTBALL;

    return this.matchesService.listMatches(sportType, pageNum, limitNum);
  }

  /**
   * GET /matches/leagues/active
   * Get active leagues with match counts
   */
  @Public()
  @Get("leagues/active")
  @UseInterceptors(CacheInterceptor)
  @CacheTTL(60000) // 1 minute cache
  @ApiOperation({ summary: "Get active leagues with upcoming/live matches" })
  @ApiQuery({ name: "sport", required: false, enum: Sport })
  @ApiResponse({ status: 200, type: [ActiveLeagueDto] })
  async getActiveLeagues(
    @Query("sport") sport?: Sport,
  ): Promise<ActiveLeagueDto[]> {
    return this.matchesService.getActiveLeagues(sport || Sport.FOOTBALL);
  }

  /**
   * GET /matches/:id/odds-movement
   * Opening→closing odds movement per market/selection (from live_odds_history)
   */
  @Public()
  @Get(":id/odds-movement")
  @ApiOperation({ summary: "Opening→closing odds movement for a match" })
  @ApiParam({ name: "id", description: "Match ID" })
  @ApiResponse({ status: 200, description: "{ market: { selection: { open, close } } }" })
  async getOddsMovement(@Param("id") id: string) {
    if (!id) {
      throw new BadRequestException("Match ID is required");
    }
    return this.matchesService.getOddsMovement(id);
  }

  /**
   * GET /matches/:id
   * Get full match details
   */
  @Public()
  @Get(":id")
  @ApiOperation({ summary: "Get full match details by ID" })
  @ApiParam({ name: "id", description: "Match ID" })
  @ApiResponse({
    status: 200,
    description: "Match details with lineups, stats, odds, events",
    schema: { type: "object" },
  })
  @ApiResponse({ status: 404, description: "Match not found" })
  async getMatchDetails(@Param("id") id: string) {
    if (!id) {
      throw new BadRequestException("Match ID is required");
    }

    const match = await this.matchesService.getMatchDetailsById(id);

    if (!match) {
      throw new NotFoundException("Match not found");
    }

    return match;
  }
}
