import { Body, Controller, Get, Param, Patch, Post, Query, UseGuards, ValidationPipe } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiBody, ApiOperation, ApiQuery, ApiTags } from '@nestjs/swagger';
import { RequirePermission } from 'src/auth/decorators/require-permission.decorator';
import { RequireSubmodulo } from 'src/auth/decorators/require-submodulo.decorator';
import type { LoginUserInfo } from 'src/auth/dto/login.dto';
import { GetUser } from 'src/auth/get-user.decorator';
import { PermissionGuard } from 'src/auth/guards/permission.guard';
import { SubmoduloGuard } from 'src/auth/guards/submodulo.guard';
import { PrismaService } from 'src/prisma/prisma.service';
import { CreateOportunidadDto } from './dto/create-oportunidad.dto';
import { MoverEtapaDto } from './dto/mover-etapa.dto';
import { PerderOportunidadDto } from './dto/perder-oportunidad.dto';
import { UpdateOportunidadDto } from './dto/update-oportunidad.dto';
import { OportunidadesService } from './oportunidades.service';

@ApiTags('CRM · Oportunidades')
@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'), SubmoduloGuard)
@RequireSubmodulo('CRM_OPORTUNIDADES')
@Controller({ path: 'crm', version: '1' })
export class OportunidadesController {
  constructor(
    private readonly service: OportunidadesService,
    private readonly prisma: PrismaService,
  ) {}

  /**
   * El alcance se calcula por request: hay que saber si el usuario tiene
   * VER_AJENAS para decidir si ve el pipeline entero o sólo lo suyo.
   */
  private async alcance(user: LoginUserInfo) {
    const verAjenas = await this.prisma.perfiles_privilegios.findFirst({
      where: {
        privilegios: { codigo: 'CRM_OPO_OPORTUNIDAD_VER_AJENAS' },
        perfiles: { usuario_perfiles: { some: { user_id: user.id } } },
      },
      select: { id: true },
    });
    return this.service.resolverAlcance(user.empresa_id, user.id, !!verAjenas);
  }

  @Get('pipelines/:pipelineId/kanban')
  @UseGuards(PermissionGuard)
  @RequirePermission('CRM', 'CRM_OPO_OPORTUNIDAD_VER')
  @ApiOperation({ summary: 'Tablero por etapa, con total y total ponderado de cada columna' })
  async kanban(@Param('pipelineId') pipelineId: string, @GetUser() user: LoginUserInfo) {
    return this.service.kanban(pipelineId, user.empresa_id, await this.alcance(user));
  }

  @Get('oportunidades')
  @UseGuards(PermissionGuard)
  @RequirePermission('CRM', 'CRM_OPO_OPORTUNIDAD_VER')
  @ApiQuery({ name: 'pipeline_id', required: false })
  @ApiQuery({ name: 'estado', required: false })
  @ApiQuery({ name: 'texto', required: false })
  async findAll(
    @GetUser() user: LoginUserInfo,
    @Query('pipeline_id') pipeline_id?: string,
    @Query('estado') estado?: string,
    @Query('texto') texto?: string,
  ) {
    return this.service.findAll(user.empresa_id, await this.alcance(user), { pipeline_id, estado, texto });
  }

  @Get('oportunidades/:id')
  @UseGuards(PermissionGuard)
  @RequirePermission('CRM', 'CRM_OPO_OPORTUNIDAD_VER')
  async findOne(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.service.findOne(id, user.empresa_id, await this.alcance(user));
  }

  @Post('oportunidades')
  @UseGuards(PermissionGuard)
  @RequirePermission('CRM', 'CRM_OPO_OPORTUNIDAD_CREAR')
  @ApiOperation({
    summary: 'Crea la oportunidad',
    description: 'Los precios de los ítems con producto salen de la lista del cliente, no del body.',
  })
  @ApiBody({ type: CreateOportunidadDto })
  create(@Body(ValidationPipe) dto: CreateOportunidadDto, @GetUser() user: LoginUserInfo) {
    return this.service.create(dto, user.empresa_id, user.id);
  }

  @Patch('oportunidades/:id')
  @UseGuards(PermissionGuard)
  @RequirePermission('CRM', 'CRM_OPO_OPORTUNIDAD_EDITAR')
  @ApiBody({ type: UpdateOportunidadDto })
  async update(
    @Param('id') id: string,
    @Body(ValidationPipe) dto: UpdateOportunidadDto,
    @GetUser() user: LoginUserInfo,
  ) {
    return this.service.update(id, dto, user.empresa_id, await this.alcance(user), user.id);
  }

  @Patch('oportunidades/:id/etapa')
  @UseGuards(PermissionGuard)
  @RequirePermission('CRM', 'CRM_OPO_OPORTUNIDAD_EDITAR')
  @ApiOperation({
    summary: 'Mueve de etapa validando los campos obligatorios del destino',
    description:
      'A la etapa ganada devuelve 409 con { requiere: "cierre" }: ganar implica emitir ' +
      'documentos y eso lo hace el asistente de cierre, no un drag & drop.',
  })
  @ApiBody({ type: MoverEtapaDto })
  async moverEtapa(
    @Param('id') id: string,
    @Body(ValidationPipe) dto: MoverEtapaDto,
    @GetUser() user: LoginUserInfo,
  ) {
    return this.service.moverEtapa(id, dto, user.empresa_id, await this.alcance(user), user.id);
  }

  @Post('oportunidades/:id/perder')
  @UseGuards(PermissionGuard)
  @RequirePermission('CRM', 'CRM_OPO_OPORTUNIDAD_ANULAR')
  @ApiOperation({ summary: 'Marca la oportunidad perdida. El motivo es obligatorio.' })
  @ApiBody({ type: PerderOportunidadDto })
  async perder(
    @Param('id') id: string,
    @Body(ValidationPipe) dto: PerderOportunidadDto,
    @GetUser() user: LoginUserInfo,
  ) {
    return this.service.perder(id, dto, user.empresa_id, await this.alcance(user), user.id);
  }

  @Post('oportunidades/:id/reabrir')
  @UseGuards(PermissionGuard)
  @RequirePermission('CRM', 'CRM_OPO_OPORTUNIDAD_REVERTIR')
  @ApiOperation({ summary: 'Reabre una perdida. Una ganada no se reabre: ya generó documentos.' })
  async reabrir(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.service.reabrir(id, user.empresa_id, await this.alcance(user), user.id);
  }
}
