import {
  Controller,
  Get,
  Post,
  Patch,
  Delete,
  Param,
  Body,
  Query,
  UseGuards,
  HttpCode,
  HttpStatus,
  ParseUUIDPipe,
} from '@nestjs/common';
import { ApiTags, ApiBearerAuth, ApiOperation, ApiResponse } from '@nestjs/swagger';
import { Prisma } from '@prisma/client';
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 } from '../../../common/decorators/current-user.decorator';
import { DealManager } from '../entities/deal/deal.manager';
import { DealPermissions } from '../entities/deal/deal.permissions';
import { CreateDealDto } from '../dto/create-deal.dto';
import { UpdateDealDto } from '../dto/update-deal.dto';
import { MoveDealDto } from '../dto/move-deal.dto';
import { LoseDealDto } from '../dto/lose-deal.dto';
import { FindDealsDto } from '../dto/find-deals.dto';

@ApiTags('CRM Deals')
@ApiBearerAuth()
@Controller('crm/deals')
@UseGuards(JwtAuthGuard)
export class DealsController {
  constructor(
    private readonly dealManager: DealManager,
    private readonly dealPermissions: DealPermissions,
  ) {}

  @Get()
  @ApiOperation({ summary: 'List deals (table or kanban view)' })
  @ApiResponse({ status: 200 })
  async findAll(@CurrentUser() user: any, @Query() query: FindDealsDto) {
    const clubId = user.role === UserRole.SUPER_ADMIN ? null : user.clubId;

    const where: Record<string, any> = {
      ...(clubId ? { clubId } : {}),
      deletedAt: null,
      ...this.dealPermissions.filterByRole(user.sub, user.role, clubId),
      ...(query.pipelineId ? { pipelineId: query.pipelineId } : {}),
      ...(query.stageId ? { stageId: query.stageId } : {}),
      ...(query.assigneeId ? { assigneeId: query.assigneeId } : {}),
      ...(query.source ? { source: query.source } : {}),
      ...(query.search
        ? {
            OR: [
              {
                title: {
                  contains: query.search,
                  mode: Prisma.QueryMode.insensitive,
                },
              },
              {
                contactName: {
                  contains: query.search,
                  mode: Prisma.QueryMode.insensitive,
                },
              },
              // Search by deal number (e.g. "#42" or "42")
              ...(/^#?\d+$/.test(query.search.trim())
                ? [{ number: parseInt(query.search.trim().replace('#', ''), 10) }]
                : []),
            ],
          }
        : {}),
      ...(query.dateFrom || query.dateTo
        ? {
            createdAt: {
              ...(query.dateFrom ? { gte: new Date(query.dateFrom) } : {}),
              ...(query.dateTo ? { lte: new Date(query.dateTo) } : {}),
            },
          }
        : {}),
    };

    if (query.view === 'kanban' && query.pipelineId) {
      return this.dealManager.getKanban(where, query.pipelineId);
    }

    return this.dealManager.getList(where, {
      cursor: query.cursor,
      limit: query.limit,
    });
  }

  @Get(':id')
  @ApiOperation({ summary: 'Get deal by ID (UUID) or number (int)' })
  @ApiResponse({ status: 200 })
  async findById(@Param('id') id: string, @CurrentUser() user: any) {
    if (/^\d+$/.test(id)) {
      const clubId = user.role === UserRole.SUPER_ADMIN ? null : user.clubId;
      return this.dealManager.getByNumber(parseInt(id, 10), clubId);
    }
    return this.dealManager.getById(id);
  }

  @Post()
  @UseGuards(RolesGuard)
  @Roles(UserRole.SUPER_ADMIN, UserRole.CLUB_ADMIN, UserRole.MANAGER)
  @ApiOperation({ summary: 'Create a deal' })
  @ApiResponse({ status: 201 })
  async create(@CurrentUser() user: any, @Body() dto: CreateDealDto) {
    const clubId = user.role === UserRole.SUPER_ADMIN ? null : user.clubId;
    return this.dealManager.add({ ...dto, clubId, createdById: user.sub }, { userId: user.sub });
  }

  @Patch(':id')
  @UseGuards(RolesGuard)
  @Roles(UserRole.SUPER_ADMIN, UserRole.CLUB_ADMIN, UserRole.MANAGER)
  @ApiOperation({ summary: 'Update a deal' })
  async update(
    @Param('id', ParseUUIDPipe) id: string,
    @CurrentUser() user: any,
    @Body() dto: UpdateDealDto,
  ) {
    return this.dealManager.update(id, dto, {
      userId: user.sub,
      role: user.role,
      clubId: user.clubId,
    } as any);
  }

  @Delete(':id')
  @UseGuards(RolesGuard)
  @Roles(UserRole.SUPER_ADMIN, UserRole.CLUB_ADMIN)
  @HttpCode(HttpStatus.NO_CONTENT)
  @ApiOperation({ summary: 'Soft-delete a deal' })
  async remove(@Param('id', ParseUUIDPipe) id: string, @CurrentUser() user: any) {
    await this.dealManager.delete(id, { userId: user.sub });
  }

  @Post(':id/move')
  @HttpCode(HttpStatus.OK)
  @UseGuards(RolesGuard)
  @Roles(UserRole.SUPER_ADMIN, UserRole.CLUB_ADMIN, UserRole.MANAGER)
  @ApiOperation({ summary: 'Move deal to another stage' })
  async move(
    @Param('id', ParseUUIDPipe) id: string,
    @CurrentUser() user: any,
    @Body() dto: MoveDealDto,
  ) {
    return this.dealManager.move(id, dto, user.sub);
  }

  @Post(':id/win')
  @HttpCode(HttpStatus.OK)
  @UseGuards(RolesGuard)
  @Roles(UserRole.SUPER_ADMIN, UserRole.CLUB_ADMIN, UserRole.MANAGER)
  @ApiOperation({ summary: 'Mark deal as won' })
  async win(@Param('id', ParseUUIDPipe) id: string, @CurrentUser() user: any) {
    return this.dealManager.win(id, user.sub);
  }

  @Post(':id/lose')
  @HttpCode(HttpStatus.OK)
  @UseGuards(RolesGuard)
  @Roles(UserRole.SUPER_ADMIN, UserRole.CLUB_ADMIN, UserRole.MANAGER)
  @ApiOperation({ summary: 'Mark deal as lost' })
  async lose(
    @Param('id', ParseUUIDPipe) id: string,
    @CurrentUser() user: any,
    @Body() dto: LoseDealDto,
  ) {
    return this.dealManager.lose(id, dto, user.sub);
  }
}
