import { Body, Controller, Get, Inject, NotFoundException, Param, Patch, Post, Req } from '@nestjs/common';
import { ApiOperation, ApiResponse, ApiTags } from '@nestjs/swagger';
import { Public } from '../auth/Public';
import { TeamService } from './TeamService';
import { CreateTeamInputDTO } from './dtos/CreateTeamInputDTO';
import { CreateTeamOutputDTO } from './dtos/CreateTeamOutputDTO';
import { GetAllTeamsOutputDTO } from './dtos/GetAllTeamsOutputDTO';
import { GetTeamsLeaderboardOutputDTO } from './dtos/GetTeamsLeaderboardOutputDTO';
import { GetDriverTeamOutputDTO } from './dtos/GetDriverTeamOutputDTO';
import { GetTeamDetailsOutputDTO } from './dtos/GetTeamDetailsOutputDTO';
import { GetTeamJoinRequestsOutputDTO } from './dtos/GetTeamJoinRequestsOutputDTO';
import { GetTeamMembersOutputDTO } from './dtos/GetTeamMembersOutputDTO';
import { GetTeamMembershipOutputDTO } from './dtos/GetTeamMembershipOutputDTO';
import { UpdateTeamInput } from './dtos/TeamDto';
import { UpdateTeamOutputDTO } from './dtos/UpdateTeamOutputDTO';

type RequestWithUser = Record<string, unknown> & {
  user?: {
    userId?: string;
  };
};

@ApiTags('teams')
@Controller('teams')
export class TeamController {
  constructor(@Inject(TeamService) private readonly teamService: TeamService) {}

  @Public()
  @Get('all')
  @ApiOperation({ summary: 'Get all teams' })
  @ApiResponse({ status: 200, description: 'List of all teams', type: GetAllTeamsOutputDTO })
  async getAll(): Promise<GetAllTeamsOutputDTO> {
    return await this.teamService.getAll();
  }

  @Public()
  @Get('leaderboard')
  @ApiOperation({ summary: 'Get teams leaderboard' })
  @ApiResponse({ status: 200, description: 'Teams leaderboard data', type: GetTeamsLeaderboardOutputDTO })
  async getLeaderboard(): Promise<GetTeamsLeaderboardOutputDTO> {
    return await this.teamService.getLeaderboard();
  }

  @Public()
  @Get(':teamId')
  @ApiOperation({ summary: 'Get team details' })
  @ApiResponse({ status: 200, description: 'Team details', type: GetTeamDetailsOutputDTO })
  @ApiResponse({ status: 404, description: 'Team not found' })
  async getDetails(@Param('teamId') teamId: string, @Req() req: RequestWithUser): Promise<GetTeamDetailsOutputDTO> {
    const userId = req.user?.userId;
    const result = await this.teamService.getDetails(teamId, userId);
    if (!result) {
      throw new NotFoundException('Team not found');
    }
    return result;
  }

  @Public()
  @Get(':teamId/members')
  @ApiOperation({ summary: 'Get team members' })
  @ApiResponse({ status: 200, description: 'Team members', type: GetTeamMembersOutputDTO })
  async getMembers(@Param('teamId') teamId: string): Promise<GetTeamMembersOutputDTO> {
    return await this.teamService.getMembers(teamId);
  }

  @Get(':teamId/join-requests')
  @ApiOperation({ summary: 'Get team join requests' })
  @ApiResponse({ status: 200, description: 'Team join requests', type: GetTeamJoinRequestsOutputDTO })
  async getJoinRequests(@Param('teamId') teamId: string): Promise<GetTeamJoinRequestsOutputDTO> {
    return await this.teamService.getJoinRequests(teamId);
  }

  @Post()
  @ApiOperation({ summary: 'Create a new team' })
  @ApiResponse({ status: 201, description: 'Team created', type: CreateTeamOutputDTO })
  async create(@Body() input: CreateTeamInputDTO, @Req() req: RequestWithUser): Promise<CreateTeamOutputDTO> {
    const userId = req.user?.userId;
    return await this.teamService.create(input, userId);
  }

  @Patch(':teamId')
  @ApiOperation({ summary: 'Update team' })
  @ApiResponse({ status: 200, description: 'Team updated', type: UpdateTeamOutputDTO })
  async update(@Param('teamId') teamId: string, @Body() input: UpdateTeamInput, @Req() req: RequestWithUser): Promise<UpdateTeamOutputDTO> {
    const userId = req.user?.userId;
    return await this.teamService.update(teamId, input, userId);
  }

  @Public()
  @Get('driver/:driverId')
  @ApiOperation({ summary: 'Get driver\'s team' })
  @ApiResponse({ status: 200, description: 'Driver\'s team', type: GetDriverTeamOutputDTO })
  @ApiResponse({ status: 404, description: 'Team not found' })
  async getDriverTeam(@Param('driverId') driverId: string): Promise<GetDriverTeamOutputDTO | null> {
    return await this.teamService.getDriverTeam(driverId);
  }

  @Public()
  @Get(':teamId/members/:driverId')
  @ApiOperation({ summary: 'Get team membership for a driver' })
  @ApiResponse({ status: 200, description: 'Team membership', type: GetTeamMembershipOutputDTO })
  @ApiResponse({ status: 404, description: 'Membership not found' })
  async getMembership(@Param('teamId') teamId: string, @Param('driverId') driverId: string): Promise<GetTeamMembershipOutputDTO | null> {
    return await this.teamService.getMembership(teamId, driverId);
  }

  @Post(':teamId/join')
  @ApiOperation({ summary: 'Join a team (actor derived from session)' })
  @ApiResponse({ status: 200, description: 'Joined team successfully' })
  async joinTeam(
    @Param('teamId') teamId: string,
    @Req() req: RequestWithUser,
  ): Promise<Record<string, unknown>> {
    const userId = req.user?.userId;
    return await this.teamService.joinTeam(teamId, userId);
  }
}
