import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Patch,
  Post,
  Query,
  UseGuards,
  UseInterceptors,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import {
  ApiBearerAuth,
  ApiOperation,
  ApiQuery,
  ApiTags,
} from '@nestjs/swagger';
import type { LoginUserInfo } from 'src/auth/dto/login.dto';
import { GetUser } from 'src/auth/get-user.decorator';
import { RequirePermission } from 'src/auth/decorators';
import { PermissionGuard } from 'src/auth/guards/permission.guard';
import { Auditable } from 'src/audit/auditable.decorator';
import { AuditInterceptor } from 'src/audit/audit.interceptor';
import { CreateGastoDto } from './dto/create-gasto.dto';
import { CreateTipoGastoDto } from './dto/create-tipo-gasto.dto';
import { UpdateGastoDto } from './dto/update-gasto.dto';
import { UpdateTipoGastoDto } from './dto/update-tipo-gasto.dto';
import { GastosService } from './gastos.service';

@ApiTags('Gastos')
@ApiBearerAuth()
// PermissionGuard ya valida Capa 1 (módulo COMPRAS en el plan) + Capa 2 (privilegio del
// perfil), así que no hace falta SubmoduloGuard. Los métodos sin @RequirePermission
// (ej. el catálogo de tipos) quedan solo con auth: es una referencia compartida que también
// consumen Rendiciones y Requisiciones, que no tienen por qué exigir permiso de Gastos.
@UseGuards(AuthGuard('jwt'), PermissionGuard)
@Controller({ path: 'gastos', version: '1' })
export class GastosController {
  constructor(private readonly gastosService: GastosService) {}

  @Post()
  @RequirePermission('COMPRAS', 'TES_GAS_GASTO_CREAR')
  @ApiOperation({ summary: 'Registrar un gasto con cabecera + ítems' })
  @Auditable('gasto')
  @UseInterceptors(AuditInterceptor)
  create(@Body() dto: CreateGastoDto, @GetUser() user: LoginUserInfo) {
    return this.gastosService.create(dto, user.empresa_id, user.id);
  }

  @Get()
  @RequirePermission('COMPRAS', 'TES_GAS_GASTO_VER')
  @ApiOperation({ summary: 'Listar gastos (paginado con filtros)' })
  @ApiQuery({ name: 'page', required: false })
  @ApiQuery({ name: 'limit', required: false })
  @ApiQuery({ name: 'fecha_desde', required: false })
  @ApiQuery({ name: 'fecha_hasta', required: false })
  @ApiQuery({ name: 'proveedor_id', required: false })
  @ApiQuery({ name: 'tipo_gasto_id', required: false })
  @ApiQuery({ name: 'deducible', required: false, description: 'true|false' })
  @ApiQuery({ name: 'estado', required: false })
  @ApiQuery({ name: 'search', required: false })
  findAll(
    @GetUser() user: LoginUserInfo,
    @Query('page') page?: string,
    @Query('limit') limit?: string,
    @Query('fecha_desde') fecha_desde?: string,
    @Query('fecha_hasta') fecha_hasta?: string,
    @Query('proveedor_id') proveedor_id?: string,
    @Query('tipo_gasto_id') tipo_gasto_id?: string,
    @Query('deducible') deducible?: string,
    @Query('estado') estado?: string,
    @Query('search') search?: string,
  ) {
    return this.gastosService.findAll(user.empresa_id, {
      page,
      limit,
      fecha_desde,
      fecha_hasta,
      proveedor_id,
      tipo_gasto_id,
      deducible,
      estado,
      search,
    });
  }

  @Get('tipos')
  // Catálogo de referencia compartido (Gastos, Rendiciones, Requisiciones). Solo lectura,
  // acotado a la empresa del usuario. Sin @RequirePermission → accesible a cualquier usuario
  // autenticado, para no romper Rendiciones/Requisiciones que no tienen permiso de Gastos.
  @ApiOperation({ summary: 'Catálogo de tipos de gasto (globales + por empresa)' })
  listarTipos(@GetUser() user: LoginUserInfo) {
    return this.gastosService.listarTiposGasto(user.empresa_id);
  }

  @Post('tipos')
  @RequirePermission('COMPRAS', 'TES_GAS_GASTO_CREAR')
  @ApiOperation({ summary: 'Crear tipo de gasto para la empresa' })
  @Auditable('tipo_gasto')
  @UseInterceptors(AuditInterceptor)
  crearTipo(@Body() dto: CreateTipoGastoDto, @GetUser() user: LoginUserInfo) {
    return this.gastosService.crearTipoGasto(dto, user.empresa_id);
  }

  @Patch('tipos/:id')
  @RequirePermission('COMPRAS', 'TES_GAS_GASTO_CREAR')
  @ApiOperation({ summary: 'Editar tipo de gasto de la empresa' })
  @Auditable('tipo_gasto')
  @UseInterceptors(AuditInterceptor)
  actualizarTipo(
    @Param('id') id: string,
    @Body() dto: UpdateTipoGastoDto,
    @GetUser() user: LoginUserInfo,
  ) {
    return this.gastosService.actualizarTipoGasto(id, dto, user.empresa_id);
  }

  @Delete('tipos/:id')
  @RequirePermission('COMPRAS', 'TES_GAS_GASTO_ANULAR')
  @ApiOperation({ summary: 'Desactivar tipo de gasto de la empresa' })
  @Auditable('tipo_gasto')
  @UseInterceptors(AuditInterceptor)
  eliminarTipo(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.gastosService.eliminarTipoGasto(id, user.empresa_id);
  }

  @Get(':id')
  @RequirePermission('COMPRAS', 'TES_GAS_GASTO_VER')
  @ApiOperation({ summary: 'Detalle de un gasto' })
  findOne(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.gastosService.findOne(id, user.empresa_id);
  }

  @Patch(':id')
  @RequirePermission('COMPRAS', 'TES_GAS_GASTO_CREAR')
  @ApiOperation({ summary: 'Editar cabecera e ítems del gasto' })
  @Auditable('gasto')
  @UseInterceptors(AuditInterceptor)
  update(
    @Param('id') id: string,
    @Body() dto: UpdateGastoDto,
    @GetUser() user: LoginUserInfo,
  ) {
    return this.gastosService.update(id, dto, user.empresa_id, user.id);
  }

  @Patch(':id/anular')
  @RequirePermission('COMPRAS', 'TES_GAS_GASTO_ANULAR')
  @ApiOperation({ summary: 'Anular un gasto (revierte asiento contable)' })
  @Auditable('gasto')
  @UseInterceptors(AuditInterceptor)
  anular(
    @Param('id') id: string,
    @Body() body: { motivo?: string },
    @GetUser() user: LoginUserInfo,
  ) {
    return this.gastosService.anular(id, user.empresa_id, user.id, body?.motivo);
  }

  @Post(':id/reintentar-contabilidad')
  @RequirePermission('COMPRAS', 'TES_GAS_GASTO_CREAR')
  @ApiOperation({ summary: 'Reintentar integración contable de gasto' })
  reintentarContabilidad(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.gastosService.reintentarContabilidad(id, user.empresa_id);
  }

  @Post(':id/reintentar-tesoreria')
  @RequirePermission('COMPRAS', 'TES_GAS_GASTO_CREAR')
  @ApiOperation({ summary: 'Reintentar registro del egreso de gasto en Tesorería' })
  reintentarTesoreria(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.gastosService.reintentarTesoreria(id, user.empresa_id);
  }
}
