import {
  BadRequestException,
  Body,
  Controller,
  Get,
  NotFoundException,
  Param,
  ParseIntPipe,
  Patch,
  Post,
  Put,
  Query,
  Request,
  Res,
  UploadedFile,
  UseGuards,
  UseInterceptors,
} from "@nestjs/common";
import { FileInterceptor } from "@nestjs/platform-express";
import { ApiBearerAuth, ApiOperation, ApiTags } from "@nestjs/swagger";
import { Response } from "express";
import { existsSync } from "fs";
import { join } from "path";
import { RequirePermission } from "../auth/decorators/require-permission.decorator";
import { JwtAuthGuard } from "../auth/guards/jwt-auth.guard";
import { PermissionGuard } from "../auth/guards/permission.guard";
import { RequiereFlag } from "../taller-parametros/requiere-flag.decorator";
import { RequiereFlagGuard } from "../taller-parametros/requiere-flag.guard";
import { TenantGuard } from "../tenancy/tenant.guard";
import { TenantReleaseInterceptor } from "../tenancy/tenant-release.interceptor";
import { CatalogosService } from "./catalogos.service";
import { CreateCatalogoVehicularDto } from "./dto/create-catalogo-vehicular.dto";
import { CreateCosaTraeDto } from "./dto/create-cosa-trae.dto";
import { CreateTipoDanoDto } from "./dto/create-tipo-dano.dto";
import { CreateTipoVehiculoDto } from "./dto/create-tipo-vehiculo.dto";
import { CatalogoVehicularTipo } from "./entities/catalogo-vehicular.entity";

@ApiTags("catalogos")
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, TenantGuard, PermissionGuard, RequiereFlagGuard)
@UseInterceptors(TenantReleaseInterceptor)
@RequirePermission("catalogos", "read")
@Controller("catalogos")
export class CatalogosController {
  constructor(private readonly catalogosService: CatalogosService) {}

  @Get("tipos-vehiculo")
  @ApiOperation({ summary: "Listar tipos de vehiculo activos" })
  async findAllTiposVehiculo(@Query("activo") activo?: string) {
    return this.catalogosService.findAllTiposVehiculo(this.parseActivo(activo));
  }

  @RequiereFlag("modulos.usa_cargas_masivas")
  @Get("plantillas/ficha-vehicular")
  @ApiOperation({ summary: "Descargar plantilla de carga masiva vehicular" })
  async downloadFichaVehicularTemplate(@Res() res: Response) {
    const filePath = join(process.cwd(), "plantillas", "carros.xlsx");
    if (!existsSync(filePath)) {
      throw new NotFoundException("Plantilla de ficha vehicular no encontrada");
    }

    return res.download(filePath, "plantilla-ficha-vehicular.xlsx");
  }

  @Post("tipos-vehiculo")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Crear tipo de vehiculo" })
  async createTipoVehiculo(
    @Body() dto: CreateTipoVehiculoDto,
    @Request() req: any,
  ) {
    return this.catalogosService.createTipoVehiculo(dto, req.user?.id);
  }

  @Put("tipos-vehiculo/:id")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Actualizar tipo de vehiculo" })
  async updateTipoVehiculo(
    @Param("id") id: number,
    @Body() dto: CreateTipoVehiculoDto,
    @Request() req: any,
  ) {
    return this.catalogosService.updateTipoVehiculo(id, dto, req.user?.id);
  }

  @Patch("tipos-vehiculo/:id/inactivar")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Inactivar tipo de vehiculo" })
  async inactivateTipoVehiculo(@Param("id") id: number, @Request() req: any) {
    return this.catalogosService.inactivateTipoVehiculo(id, req.user?.id);
  }

  @Patch("tipos-vehiculo/:id/activar")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Activar tipo de vehiculo" })
  async activateTipoVehiculo(@Param("id") id: number, @Request() req: any) {
    return this.catalogosService.activateTipoVehiculo(id, req.user?.id);
  }

  @Get("cosas-trae")
  @ApiOperation({ summary: "Listar cosas que trae activas" })
  async findAllCosasTrae(@Query("activo") activo?: string) {
    return this.catalogosService.findAllCosasTrae(this.parseActivo(activo));
  }

  @RequiereFlag("ot.usa_cosas_trae", { soloEscritura: true })
  @Post("cosas-trae")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Crear cosa que trae" })
  async createCosaTrae(@Body() dto: CreateCosaTraeDto) {
    return this.catalogosService.createCosaTrae(dto);
  }

  @RequiereFlag("ot.usa_cosas_trae", { soloEscritura: true })
  @Put("cosas-trae/:id")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Actualizar cosa que trae" })
  async updateCosaTrae(
    @Param("id") id: number,
    @Body() dto: CreateCosaTraeDto,
  ) {
    return this.catalogosService.updateCosaTrae(id, dto);
  }

  @RequiereFlag("ot.usa_cosas_trae", { soloEscritura: true })
  @Patch("cosas-trae/:id/inactivar")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Inactivar cosa que trae" })
  async inactivateCosaTrae(@Param("id") id: number) {
    return this.catalogosService.inactivateCosaTrae(id);
  }

  @RequiereFlag("ot.usa_cosas_trae", { soloEscritura: true })
  @Patch("cosas-trae/:id/activar")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Activar cosa que trae" })
  async activateCosaTrae(@Param("id") id: number) {
    return this.catalogosService.activateCosaTrae(id);
  }

  @Get("tipos-dano")
  @ApiOperation({ summary: "Listar tipos de daño activos" })
  async findAllTiposDano(@Query("activo") activo?: string) {
    return this.catalogosService.findAllTiposDano(this.parseActivo(activo));
  }

  @RequiereFlag("ot.usa_danos", { soloEscritura: true })
  @Post("tipos-dano")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Crear tipo de daño" })
  async createTipoDano(@Body() dto: CreateTipoDanoDto) {
    return this.catalogosService.createTipoDano(dto);
  }

  @RequiereFlag("ot.usa_danos", { soloEscritura: true })
  @Put("tipos-dano/:id")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Actualizar tipo de daño" })
  async updateTipoDano(
    @Param("id") id: number,
    @Body() dto: CreateTipoDanoDto,
  ) {
    return this.catalogosService.updateTipoDano(id, dto);
  }

  @RequiereFlag("ot.usa_danos", { soloEscritura: true })
  @Patch("tipos-dano/:id/inactivar")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Inactivar tipo de daño" })
  async inactivateTipoDano(@Param("id") id: number) {
    return this.catalogosService.inactivateTipoDano(id);
  }

  @RequiereFlag("ot.usa_danos", { soloEscritura: true })
  @Patch("tipos-dano/:id/activar")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Activar tipo de daño" })
  async activateTipoDano(@Param("id") id: number) {
    return this.catalogosService.activateTipoDano(id);
  }

  @Get("vehicular")
  @ApiOperation({ summary: "Listar catalogo vehicular por tipo y filtros" })
  async listVehicular(
    @Query("tipo") tipo: CatalogoVehicularTipo,
    @Query("marca") marca?: string,
    @Query("modelo") modelo?: string,
    @Query("motor") motor?: string,
    @Query("tipoVehiculoId") tipoVehiculoId?: string,
    @Query("activo") activo?: string,
  ) {
    const parsedTipoVehiculoId = tipoVehiculoId
      ? Number(tipoVehiculoId)
      : undefined;
    return this.catalogosService.listCatalogosVehiculares(tipo, {
      marca,
      modelo,
      motor,
      tipoVehiculoId: parsedTipoVehiculoId,
      activo: this.parseActivo(activo),
    });
  }

  @Post("vehicular")
  @RequirePermission("catalogos", "write")
  @ApiOperation({
    summary: "Crear item de catalogo vehicular (marca/modelo/motor/cilindraje)",
  })
  async createVehicular(@Body() dto: CreateCatalogoVehicularDto) {
    return this.catalogosService.createCatalogoVehicular(dto);
  }

  @RequiereFlag("modulos.usa_cargas_masivas")
  @Post("vehicular/importar-excel")
  @RequirePermission("catalogos", "write")
  @UseInterceptors(
    FileInterceptor("file", {
      limits: { fileSize: 5 * 1024 * 1024 },
    }),
  )
  @ApiOperation({
    summary: "Carga masiva de ficha vehicular por tipo, marca y linea",
  })
  async importVehicularExcel(
    @UploadedFile() file: Express.Multer.File,
    @Request() req: any,
  ) {
    if (!file?.buffer?.length) {
      throw new BadRequestException("Debes adjuntar un archivo Excel");
    }
    if (!file.originalname?.toLowerCase().endsWith(".xlsx")) {
      throw new BadRequestException("Solo se permiten archivos .xlsx");
    }

    return this.catalogosService.importVehicularExcel(
      file.buffer,
      req.user?.id,
    );
  }

  @Put("vehicular/:id")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Actualizar item de catalogo vehicular" })
  async updateVehicular(
    @Param("id", ParseIntPipe) id: number,
    @Body() dto: Partial<CreateCatalogoVehicularDto>,
  ) {
    return this.catalogosService.updateCatalogoVehicular(id, dto);
  }

  @Patch("vehicular/:id/inactivar")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Inactivar item de catalogo vehicular" })
  async inactivateVehicular(@Param("id", ParseIntPipe) id: number) {
    return this.catalogosService.inactivateCatalogoVehicular(id);
  }

  @Patch("vehicular/:id/activar")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Activar item de catalogo vehicular" })
  async activateVehicular(@Param("id", ParseIntPipe) id: number) {
    return this.catalogosService.activateCatalogoVehicular(id);
  }

  // DEUDA DE SEGURIDAD (no arreglar aca — anotado para cuando este modulo se
  // convierta a tenant-aware): @RequirePermission("catalogos","write") exige
  // rol, pero ese rol es el que trae el JWT (hoy sin verificar contra
  // ninguna membresia de tenant real) y PermissionGuard le otorga
  // "catalogos:write" a CUALQUIER token con rol admin/super_admin via
  // DEFAULT_PERMISSIONS_BY_ROLE (permission.guard.ts) SIN mirar tenant ni
  // membresia. Confirmado corriendo el e2e de aislamiento: esta ruta
  // ejecuto un INSERT real (bloqueado solo por el cinturon de sesion
  // read-only de la prueba, no por ninguna regla de negocio) bajo un token
  // de tenant INEXISTENTE, SUSPENDIDO, y SIN MEMBRESIA — las tres variantes
  // negativas. Es ademas ESCRITURA MASIVA (siembra varias tablas de
  // catalogo de una sola llamada), no un alta puntual. Se cierra cuando
  // exista el TenantGuard y el rol se relea del usuario local del tenant en
  // cada request — mientras tanto, definir que permiso/rol especifico
  // necesita esta ruta es parte de la conversion de catalogos, no de auth.
  // Mismo defecto de fondo — "el rol en el JWT no esta atado a nada
  // verificado" — que motiva releer rol_plataforma en cada emision de token
  // (ver auth.service.ts, login()/refreshToken()) y que el 500 crudo por
  // tipoDanoId/cosaTraeId sin validar existencia (ver ots.service.ts,
  // addDano() y create()) — las tres son la misma familia de deuda.
  @Post("seed")
  @RequirePermission("catalogos", "write")
  @ApiOperation({ summary: "Sembrar datos iniciales (tipos, cosas, daños)" })
  async seed() {
    return this.catalogosService.seedCatalogos();
  }

  private parseActivo(value?: string): boolean | undefined {
    if (value === undefined) return true;
    if (value === "all") return undefined;
    return String(value).toLowerCase() !== "false";
  }
}
