import { Body, Controller, Delete, Get, Param, Patch, Post, Query, UseGuards } from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiOperation, ApiTags } from '@nestjs/swagger';
import { RequireModule } from 'src/auth/decorators/require-module.decorator';
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 { ModuleGuard } from 'src/auth/guards/module.guard';
import { PermissionGuard } from 'src/auth/guards/permission.guard';
import { SubmoduloGuard } from 'src/auth/guards/submodulo.guard';
import { AgregarDocumentosDto } from './dto/agregar-documentos.dto';
import { AnularViajeDto } from './dto/anular-viaje.dto';
import { CerrarViajeDto } from './dto/cerrar-viaje.dto';
import { CreateViajeDto } from './dto/create-viaje.dto';
import { ListViajesDto } from './dto/list-viajes.dto';
import { UpdateViajeDto } from './dto/update-viaje.dto';
import { ViajeCalculosService } from './viaje-calculos.service';
import { ViajeCobranzaService } from './viaje-cobranza.service';
import { ViajeCostosService } from './viaje-costos.service';
import { AsociarRendicionesDto } from './dto/asociar-rendiciones.dto';
import { ViajeDocumentosService } from './viaje-documentos.service';
import { ViajesService } from './viajes.service';

@ApiTags('Viajes de reparto')
@ApiBearerAuth()
@UseGuards(AuthGuard('jwt'), ModuleGuard, SubmoduloGuard, PermissionGuard)
@RequireModule('VENTAS')
@RequireSubmodulo('VENTAS_VIAJES')
@Controller({ path: 'viajes', version: '1' })
export class ViajesController {
  constructor(
    private readonly viajes: ViajesService,
    private readonly documentos: ViajeDocumentosService,
    private readonly calculos: ViajeCalculosService,
    private readonly cobranzas: ViajeCobranzaService,
    private readonly costos: ViajeCostosService,
  ) {}

  @Get()
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_VER')
  @ApiOperation({ summary: 'Listar viajes de reparto' })
  listar(@GetUser() user: LoginUserInfo, @Query() filtros: ListViajesDto) {
    return this.viajes.findAll(user.empresa_id, filtros, user.id);
  }

  @Post()
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_CREAR')
  @ApiOperation({ summary: 'Crear viaje de reparto' })
  crear(@GetUser() user: LoginUserInfo, @Body() dto: CreateViajeDto) {
    return this.viajes.create(dto, user.empresa_id, user.id);
  }

  @Get(':id')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_VER')
  @ApiOperation({ summary: 'Detalle del viaje con sus documentos' })
  async detalle(@GetUser() user: LoginUserInfo, @Param('id') id: string) {
    const viaje = await this.viajes.findOne(id, user.empresa_id);
    // `findOne` queda liviano porque lo usan exigirEditable y resumen; el número
    // y el cliente de cada documento sólo se resuelven para la pantalla.
    return { ...viaje, documentos: await this.documentos.detallar(viaje.documentos) };
  }

  @Patch(':id')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_EDITAR')
  @ApiOperation({ summary: 'Editar la cabecera del viaje' })
  editar(@GetUser() user: LoginUserInfo, @Param('id') id: string, @Body() dto: UpdateViajeDto) {
    return this.viajes.update(id, dto, user.empresa_id);
  }

  @Post(':id/cerrar')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_CERRAR')
  @ApiOperation({ summary: 'Cerrar el viaje (exige fecha y km de retorno)' })
  cerrar(@GetUser() user: LoginUserInfo, @Param('id') id: string, @Body() dto: CerrarViajeDto) {
    return this.viajes.cerrar(id, dto, user.empresa_id, user.id);
  }

  @Post(':id/en-ruta')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_EDITAR')
  @ApiOperation({ summary: 'Marcar el viaje en ruta (sale el camión)' })
  marcarEnRuta(@GetUser() user: LoginUserInfo, @Param('id') id: string) {
    return this.viajes.marcarEnRuta(id, user.empresa_id, user.id);
  }

  @Post(':id/reabrir')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_CERRAR')
  @ApiOperation({ summary: 'Reabrir un viaje cerrado' })
  reabrir(@GetUser() user: LoginUserInfo, @Param('id') id: string) {
    return this.viajes.reabrir(id, user.empresa_id, user.id);
  }

  @Post(':id/anular')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_ANULAR')
  @ApiOperation({ summary: 'Anular el viaje' })
  anular(@GetUser() user: LoginUserInfo, @Param('id') id: string, @Body() dto: AnularViajeDto) {
    // Libera documentos y rendiciones y guarda la lista de lo que tenía.
    return this.documentos.anularViaje(id, dto.motivo, user.empresa_id, user.id);
  }

  @Get(':id/documentos-sugeridos')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_VER')
  @ApiOperation({ summary: 'Documentos del vendedor entre las fechas del viaje, sin los ya asignados' })
  sugeridos(@GetUser() user: LoginUserInfo, @Param('id') id: string) {
    return this.documentos.sugeridos(id, user.empresa_id, user.id);
  }

  @Post(':id/documentos')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_EDITAR')
  @ApiOperation({ summary: 'Enganchar documentos al viaje (lote)' })
  agregarDocumentos(@GetUser() user: LoginUserInfo, @Param('id') id: string, @Body() dto: AgregarDocumentosDto) {
    return this.documentos.agregar(id, dto.documentos, user.empresa_id, user.id);
  }

  @Delete(':id/documentos/:filaId')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_EDITAR')
  @ApiOperation({ summary: 'Desenganchar un documento del viaje' })
  quitarDocumento(@GetUser() user: LoginUserInfo, @Param('id') id: string, @Param('filaId') filaId: string) {
    return this.documentos.quitar(id, filaId, user.empresa_id);
  }

  @Delete(':id/documentos-anulados')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_EDITAR')
  @ApiOperation({ summary: 'Quitar del viaje los documentos que se anularon desde su pantalla' })
  quitarAnulados(@GetUser() user: LoginUserInfo, @Param('id') id: string) {
    return this.documentos.quitarAnulados(id, user.empresa_id);
  }

  @Get(':id/carga')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_VER')
  @ApiOperation({ summary: 'Carga del camión: planificado, remitido, facturado y diferencia por producto' })
  carga(@GetUser() user: LoginUserInfo, @Param('id') id: string) {
    return this.calculos.carga(id, user.empresa_id);
  }

  @Get(':id/matriz')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_VER')
  @ApiOperation({ summary: 'Matriz producto × cliente (fuente: planificado | entregado | comparado)' })
  matriz(
    @GetUser() user: LoginUserInfo,
    @Param('id') id: string,
    @Query('fuente') fuente?: 'planificado' | 'entregado' | 'comparado',
  ) {
    return this.calculos.matriz(id, user.empresa_id, fuente ?? 'entregado');
  }

  @Get(':id/resumen')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_VER')
  @ApiOperation({ summary: 'Resultado del viaje: vendido, cobrado, costo, margen y km' })
  resumen(@GetUser() user: LoginUserInfo, @Param('id') id: string) {
    return this.calculos.resumen(id, user.empresa_id, user.id);
  }

  @Get(':id/cobranza')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_VER')
  @ApiOperation({
    summary: 'Cobranza del viaje: por cliente, por medio, cheques, control de rendición y recibos sin enganchar',
  })
  cobranza(@GetUser() user: LoginUserInfo, @Param('id') id: string) {
    return this.cobranzas.cobranza(id, user.empresa_id, user.id);
  }

  @Get(':id/costos')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_VER')
  @ApiOperation({ summary: 'Costo del viaje (rendiciones por persona y tipo de gasto) y margen bruto con su cobertura' })
  verCostos(@GetUser() user: LoginUserInfo, @Param('id') id: string) {
    return this.costos.costos(id, user.empresa_id);
  }

  @Get(':id/rendiciones-sugeridas')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_VER')
  @ApiOperation({ summary: 'Rendiciones de viáticos libres para asociar, primero las de las fechas del viaje' })
  rendicionesSugeridas(@GetUser() user: LoginUserInfo, @Param('id') id: string) {
    return this.costos.sugeridas(id, user.empresa_id);
  }

  @Post(':id/rendiciones')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_EDITAR')
  @ApiOperation({ summary: 'Asociar rendiciones de viáticos al viaje' })
  asociarRendiciones(@GetUser() user: LoginUserInfo, @Param('id') id: string, @Body() dto: AsociarRendicionesDto) {
    return this.costos.asociar(id, user.empresa_id, dto.rendicion_ids, user.id);
  }

  @Delete(':id/rendiciones/:filaId')
  @RequirePermission('VENTAS', 'VEN_VJ_VIAJE_EDITAR')
  @ApiOperation({ summary: 'Quitar una rendición de viáticos del viaje' })
  quitarRendicion(@GetUser() user: LoginUserInfo, @Param('id') id: string, @Param('filaId') filaId: string) {
    return this.costos.quitar(id, user.empresa_id, filaId);
  }
}
