import {
  Controller,
  Get,
  Post,
  Body,
  Param,
  Query,
  UseGuards,
  ParseUUIDPipe,
} from '@nestjs/common';
import {
  ApiTags,
  ApiOperation,
  ApiBearerAuth,
  ApiResponse,
  ApiParam,
  ApiQuery,
} from '@nestjs/swagger';
import { FunnelService } from './funnel.service';
import { JwtAuthGuard } from '../auth/guards/jwt-auth.guard';
import { RolesGuard } from '../auth/guards/roles.guard';
import { Roles, UserRole } from '../../common/decorators/roles.decorator';
import {
  CurrentUser,
  JwtPayload,
} from '../../common/decorators/current-user.decorator';
import {
  AssignClientDto,
  MoveStageDto,
  TransferClientDto,
  RefuseClientDto,
  FindFunnelDto,
} from './dto';

@ApiTags('Funnel')
@ApiBearerAuth()
@Controller('funnel')
@UseGuards(JwtAuthGuard)
export class FunnelController {
  constructor(private readonly funnelService: FunnelService) {}

  @Get()
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.TRAINER,
    UserRole.COORDINATOR,
    UserRole.MANAGER,
    UserRole.RECEPTIONIST,
    UserRole.CLUB_ADMIN,
  )
  @ApiOperation({
    summary: 'List funnel entries with pagination and filters',
    description:
      'TRAINER sees only own clients. COORDINATOR/MANAGER/RECEPTIONIST/CLUB_ADMIN see all.',
  })
  @ApiResponse({ status: 200, description: 'Paginated list of funnel entries' })
  async findByStage(
    @CurrentUser() user: JwtPayload,
    @Query() query: FindFunnelDto,
  ) {
    const params = this.applyTrainerFilter(user, query);
    return this.funnelService.findByStage(user.clubId, params);
  }

  @Get('stats')
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.COORDINATOR,
    UserRole.MANAGER,
    UserRole.CLUB_ADMIN,
  )
  @ApiOperation({
    summary: 'Get funnel conversion statistics',
    description:
      'Returns conversion rates: New->Assigned, Assigned->Completed, Completed->Regular.',
  })
  @ApiQuery({ name: 'dateFrom', required: false, description: 'ISO date string' })
  @ApiQuery({ name: 'dateTo', required: false, description: 'ISO date string' })
  @ApiResponse({ status: 200, description: 'Conversion statistics' })
  async getConversionStats(
    @CurrentUser() user: JwtPayload,
    @Query('dateFrom') dateFrom?: string,
    @Query('dateTo') dateTo?: string,
  ) {
    return this.funnelService.getConversionStats(
      user.clubId,
      dateFrom,
      dateTo,
    );
  }

  @Get('distribution')
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.TRAINER,
    UserRole.COORDINATOR,
    UserRole.MANAGER,
    UserRole.RECEPTIONIST,
    UserRole.CLUB_ADMIN,
  )
  @ApiOperation({
    summary: 'Get funnel entries count per stage',
    description: 'Returns the distribution of entries across funnel stages (for chart).',
  })
  @ApiResponse({ status: 200, description: 'Stage distribution counts' })
  async getDistribution(@CurrentUser() user: JwtPayload) {
    return this.funnelService.getDistribution(user.clubId);
  }

  @Get('client/:clientId')
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.TRAINER,
    UserRole.COORDINATOR,
    UserRole.MANAGER,
    UserRole.RECEPTIONIST,
    UserRole.CLUB_ADMIN,
  )
  @ApiOperation({
    summary: 'Get funnel history for a specific client',
    description: 'Returns all funnel transitions for the client, ordered by createdAt desc.',
  })
  @ApiParam({ name: 'clientId', description: 'Client UUID' })
  @ApiResponse({ status: 200, description: 'List of funnel entries for the client' })
  @ApiResponse({ status: 404, description: 'Client not found' })
  async findByClient(
    @CurrentUser() user: JwtPayload,
    @Param('clientId', ParseUUIDPipe) clientId: string,
  ) {
    return this.funnelService.findByClient(user.clubId, clientId);
  }

  @Post('assign')
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.COORDINATOR,
    UserRole.MANAGER,
    UserRole.RECEPTIONIST,
  )
  @ApiOperation({
    summary: 'Assign a client to a trainer',
    description:
      'Creates an ASSIGNED funnel entry and sets client.assignedTrainerId.',
  })
  @ApiResponse({ status: 201, description: 'Client assigned to trainer' })
  @ApiResponse({ status: 404, description: 'Client not found' })
  async assignClient(
    @CurrentUser() user: JwtPayload,
    @Body() dto: AssignClientDto,
  ) {
    return this.funnelService.assignClient(user.clubId, dto, user.sub);
  }

  @Post(':clientId/move')
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.TRAINER,
    UserRole.COORDINATOR,
    UserRole.MANAGER,
  )
  @ApiOperation({
    summary: 'Move a client to a new funnel stage',
    description:
      'TRAINER can move own clients only. COORDINATOR/MANAGER can move any client.',
  })
  @ApiParam({ name: 'clientId', description: 'Client UUID' })
  @ApiResponse({ status: 201, description: 'Client moved to new stage' })
  @ApiResponse({ status: 400, description: 'Invalid stage transition' })
  @ApiResponse({ status: 404, description: 'Client not found' })
  async moveStage(
    @CurrentUser() user: JwtPayload,
    @Param('clientId', ParseUUIDPipe) clientId: string,
    @Body() dto: MoveStageDto,
  ) {
    return this.funnelService.moveStage(user.clubId, clientId, dto);
  }

  @Post(':clientId/transfer')
  @UseGuards(RolesGuard)
  @Roles(UserRole.COORDINATOR, UserRole.MANAGER)
  @ApiOperation({
    summary: 'Transfer a client to another department',
    description:
      'Creates a TRANSFERRED funnel entry and resets the assigned trainer.',
  })
  @ApiParam({ name: 'clientId', description: 'Client UUID' })
  @ApiResponse({ status: 201, description: 'Client transferred' })
  @ApiResponse({ status: 404, description: 'Client not found' })
  async transferClient(
    @CurrentUser() user: JwtPayload,
    @Param('clientId', ParseUUIDPipe) clientId: string,
    @Body() dto: TransferClientDto,
  ) {
    // Override the clientId from the URL param
    return this.funnelService.transferClient(
      user.clubId,
      { ...dto, clientId },
      user.sub,
    );
  }

  @Post(':clientId/refuse')
  @UseGuards(RolesGuard)
  @Roles(
    UserRole.TRAINER,
    UserRole.COORDINATOR,
    UserRole.MANAGER,
  )
  @ApiOperation({
    summary: 'Refuse a client with a mandatory comment',
    description:
      'TRAINER can refuse own clients only. COORDINATOR/MANAGER can refuse any client.',
  })
  @ApiParam({ name: 'clientId', description: 'Client UUID' })
  @ApiResponse({ status: 201, description: 'Client refused' })
  @ApiResponse({ status: 404, description: 'Client not found' })
  async refuseClient(
    @CurrentUser() user: JwtPayload,
    @Param('clientId', ParseUUIDPipe) clientId: string,
    @Body() dto: RefuseClientDto,
  ) {
    return this.funnelService.refuseClient(user.clubId, clientId, dto);
  }

  /**
   * For TRAINER role, force the trainerId filter to their own user ID.
   * Other roles see all entries or use the provided filter.
   */
  private applyTrainerFilter(
    user: JwtPayload,
    query: FindFunnelDto,
  ): FindFunnelDto & { trainerFilter?: string } {
    if (user.role === UserRole.TRAINER) {
      return { ...query, trainerFilter: user.sub };
    }
    return query;
  }
}
