import {
  Body,
  Controller,
  Delete,
  Get,
  Param,
  Patch,
  Post,
  Put,
  Query,
  Request,
  UseGuards,
  UseInterceptors,
} from "@nestjs/common";
import { ApiBearerAuth, ApiOperation, ApiTags } from "@nestjs/swagger";
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 { ChangeEstadoDto } from "./dto/change-estado.dto";
import { CreateDanoDto } from "./dto/create-dano.dto";
import { CreateFirmaDto } from "./dto/create-firma.dto";
import { CreateFotoDto } from "./dto/create-foto.dto";
import { CreateOtDto } from "./dto/create-ot.dto";
import { SearchOtDto } from "./dto/search-ot.dto";
import { UpdateOtDto } from "./dto/update-ot.dto";
import { OtsService } from "./ots.service";

@ApiTags("ots")
@ApiBearerAuth()
@UseGuards(JwtAuthGuard, TenantGuard, PermissionGuard, RequiereFlagGuard)
@UseInterceptors(TenantReleaseInterceptor)
@RequirePermission("ots", "read")
@Controller("ots")
export class OtsController {
  constructor(private readonly otsService: OtsService) {}

  @Get()
  @ApiOperation({ summary: "Listar OTs con filtros y paginación" })
  async findAll(@Query() query: SearchOtDto, @Request() req: any) {
    return this.otsService.findAll(query, req.user);
  }

  @Get(":id")
  @ApiOperation({ summary: "Obtener OT por ID con todos los detalles" })
  async findById(@Param("id") id: number, @Request() req: any) {
    return this.otsService.findById(id, req.user);
  }

  // Solo la vista: logEvento sigue escribiendo siempre, apagar la bitacora
  // no puede dejar al taller sin rastro de lo que paso en cada OT.
  @RequiereFlag("modulos.usa_bitacora")
  @Get(":id/eventos")
  @RequirePermission("logs", "read")
  @ApiOperation({ summary: "Obtener bitácora de eventos de la OT" })
  async getEventos(@Param("id") id: number, @Request() req: any) {
    await this.otsService.findById(id, req.user);
    return this.otsService.getEventos(id);
  }

  @Get("numero/:numeroOt")
  @ApiOperation({ summary: "Obtener OT por número" })
  async findByNumero(@Param("numeroOt") numeroOt: string, @Request() req: any) {
    return this.otsService.findByNumero(numeroOt, req.user);
  }

  @Get(":id/facturacion-pos")
  @ApiOperation({ summary: "Estado de la facturacion POS de esta OT: si aplica, si exige pago y los datos de la factura si ya se emitio" })
  async getFacturacionPos(@Param("id") id: number, @Request() req: any) {
    await this.otsService.findById(id, req.user);
    return this.otsService.getFacturacionPos(id);
  }

  @Post(":id/facturacion-pos/reintentar")
  @RequirePermission("ots", "write")
  @ApiOperation({ summary: "Reintentar el envio a POSTouch de una OT en TERMINADA cuyo envio automatico fallo" })
  async reintentarFacturacionPos(@Param("id") id: number, @Request() req: any) {
    return this.otsService.reintentarFacturacionPos(id, req.user?.id);
  }

  // Permiso propio (`confirmarPago`) y no `ots:write`: quien captura OTs no
  // necesariamente puede dar por cobrado un vehiculo. Ver el comentario de
  // OtsService.confirmarPago.
  @Post(":id/confirmar-pago")
  @RequirePermission("confirmarPago", "write")
  @ApiOperation({ summary: "Confirmar manualmente que el cliente pago una OT ya facturada en POSTouch" })
  async confirmarPago(@Param("id") id: number, @Request() req: any) {
    return this.otsService.confirmarPago(id, req.user?.id, req.user);
  }

  @Post()
  @RequirePermission("ots", "write")
  @ApiOperation({ summary: "Crear nueva OT" })
  async create(@Body() dto: CreateOtDto, @Request() req: any) {
    return this.otsService.create(dto, req.user?.id, req.user);
  }

  @Put(":id")
  @RequirePermission("ots", "write")
  @ApiOperation({ summary: "Actualizar OT" })
  async update(
    @Param("id") id: number,
    @Body() dto: UpdateOtDto,
    @Request() req: any,
  ) {
    return this.otsService.update(id, dto, req.user?.id, req.user);
  }

  @Patch(":id/estado")
  @RequirePermission("ots", "write")
  @ApiOperation({ summary: "Cambiar estado de OT" })
  async changeEstado(
    @Param("id") id: number,
    @Body() dto: ChangeEstadoDto,
    @Request() req: any,
  ) {
    return this.otsService.changeEstado(
      id,
      dto.estado,
      dto.fechaSalida,
      req.user?.id,
      req.user,
      {
        kmSalida: dto.kmSalida,
        nivelGasolinaSalida: dto.nivelGasolinaSalida,
        recomendacionesEntrega: dto.recomendacionesEntrega,
        entregadoPor: dto.entregadoPor,
        firmaEntrega: dto.firmaEntrega,
      },
    );
  }

  @Post(":id/danos")
  @RequirePermission("ots", "write")
  @ApiOperation({ summary: "Agregar daño a OT" })
  async addDano(
    @Param("id") id: number,
    @Body() dto: CreateDanoDto,
    @Request() req: any,
  ) {
    return this.otsService.addDano(id, dto, req.user?.id, req.user);
  }

  @Delete(":id/danos/:danoId")
  @RequirePermission("ots", "write")
  @ApiOperation({ summary: "Eliminar daño de OT" })
  async removeDano(
    @Param("id") id: number,
    @Param("danoId") danoId: number,
    @Request() req: any,
  ) {
    return this.otsService.removeDano(id, danoId, req.user);
  }

  @Post(":id/fotos")
  @RequirePermission("ots", "write")
  @ApiOperation({ summary: "Agregar foto a OT" })
  async addFoto(
    @Param("id") id: number,
    @Body() dto: CreateFotoDto,
    @Request() req: any,
  ) {
    return this.otsService.addFoto(id, dto, req.user?.id, req.user);
  }

  @Delete(":id/fotos/:fotoId")
  @RequirePermission("ots", "write")
  @ApiOperation({ summary: "Eliminar foto de OT" })
  async removeFoto(
    @Param("id") id: number,
    @Param("fotoId") fotoId: number,
    @Request() req: any,
  ) {
    return this.otsService.removeFoto(id, fotoId, req.user);
  }

  @Post(":id/firmas")
  @RequirePermission("ots", "write")
  @ApiOperation({ summary: "Guardar firmas de OT" })
  async saveFirmas(
    @Param("id") id: number,
    @Body() dto: CreateFirmaDto,
    @Request() req: any,
  ) {
    return this.otsService.saveFirmas(id, dto, req.user?.id, req.user);
  }

  @Post(":id/pdf")
  @RequirePermission("ots", "write")
  @ApiOperation({ summary: "Asociar PDF escáner a OT" })
  async savePdf(
    @Param("id") id: number,
    @Body("pdfUrl") pdfUrl: string,
    @Request() req: any,
  ) {
    return this.otsService.savePdfEscaner(id, pdfUrl, req.user?.id, req.user);
  }
}
