import {
    Body,
    Controller,
    Delete,
    Get,
    HttpException,
    HttpStatus,
    Param,
    Post,
    Put,
    Query,
    UseGuards,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { ApiBearerAuth, ApiBody, ApiCreatedResponse, ApiExcludeEndpoint, ApiParam } 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/require-permission.decorator';
import { PermissionGuard } from 'src/auth/guards/permission.guard';
import { ConfigurarPinDto } from './dto/configurar-pin.dto';
import { CreateUserDto } from './dto/create-user.dto';
import { response_user_all, response_user_find } from './dto/doc-swagger';
import { UpdateUserDto } from './dto/update-user.dto';
import { AsignarEmpresaDto, RevocarEmpresaDto } from './dto/usuario-empresa.dto';
import { ValidarPinDto } from './dto/validar-pin.dto';
import { UsersService } from './users.service';

@Controller({ path: 'users', version: '1' })
@UseGuards(AuthGuard('jwt'), PermissionGuard)
@ApiBearerAuth()
export class UsersController {
  constructor(private readonly usersService: UsersService) {}

  @Post()
  @RequirePermission('ADMINISTRACION', 'ADM_USR_USUARIO_CREAR')
  @ApiBody({ type: CreateUserDto })
  @ApiCreatedResponse(response_user_find)
  async create(@Body() createUserDto: CreateUserDto, @GetUser() user: LoginUserInfo) {
    return this.usersService.create(createUserDto, user?.id, user?.empresa_id);
  }

  @RequirePermission('ADMINISTRACION', 'ADM_USR_USUARIO_VER')
  @ApiParam({ name: 'page', type: 'string', required: false, description: 'Pagina actual' })
  @ApiParam({ name: 'limit', type: 'string', required: false, description: 'Limit' })
  @ApiParam({ name: 'empresa_id', type: 'string', required: false, description: 'Filtrar por empresa' })
  @ApiCreatedResponse(response_user_all)
  @Get()
  async findAll(
    @Query('page') page: string,
    @Query('limit') limit: string,
    @GetUser() user: LoginUserInfo,
    @Query('empresa_id') empresa_id?: string,
  ) {
    try {
      const {
        items,
        total,
        page: currentPage,
        limit: pageLimit,
        lastPage,
      } = await this.usersService.findAll(Number(page) || 1, Number(limit) || 10, empresa_id, user?.id, user?.empresa_id);

      return {
        message: 'Usuarios obtenidos exitosamente',
        data: items,
        total,
        page: currentPage,
        limit: pageLimit,
        lastPage,
      };
    } catch (error) {
      const errorMessage = error instanceof Error ? error.message : 'Error desconocido';
      throw new HttpException(
        {
          success: false,
          message: 'Error al obtener empresas',
          error: errorMessage,
        },
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  @RequirePermission('ADMINISTRACION', 'ADM_USR_USUARIO_VER')
  @ApiParam({ name: 'id', type: 'string', required: true, description: 'ID del usuario' })
  @ApiCreatedResponse(response_user_find)
  @Get(':id')
  findOne(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.usersService.findOne(id, user?.id, user?.empresa_id);
  }

  @RequirePermission('ADMINISTRACION', 'ADM_USR_USUARIO_EDITAR')
  @ApiParam({ name: 'id', type: 'string', required: true, description: 'ID del usuario' })
  @ApiBody({ type: UpdateUserDto })
  @Put(':id')
  @ApiCreatedResponse(response_user_find)
  update(@Param('id') id: string, @Body() updateUserDto: UpdateUserDto, @GetUser() user: LoginUserInfo) {
    return this.usersService.update(id, updateUserDto, user?.id, user?.empresa_id);
  }

  @RequirePermission('ADMINISTRACION', 'ADM_USR_USUARIO_EDITAR')
  @ApiParam({ name: 'id', type: 'string', required: true, description: 'ID del usuario' })
  @ApiCreatedResponse(response_user_find)
  @Put('activar-desactivar/:id')
  activarDesactivar(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.usersService.activarDesactivar(id, user?.id, user?.empresa_id);
  }

  @RequirePermission('ADMINISTRACION', 'ADM_USR_USUARIO_ELIMINAR')
  @ApiParam({ name: 'id', type: 'string', required: true, description: 'ID del usuario' })
  @ApiExcludeEndpoint()
  @Delete(':id')
  remove(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.usersService.remove(id, user?.id, user?.empresa_id);
  }

  // ==================== GESTIÓN DE ACCESO A EMPRESAS ====================

  @RequirePermission('ADMINISTRACION', 'ADM_USR_USUARIO_VER')
  @ApiParam({ name: 'usuario_id', type: 'string', required: true, description: 'ID del usuario' })
  @Get(':usuario_id/empresas')
  getEmpresasAsignadas(@Param('usuario_id') usuarioId: string) {
    return this.usersService.getEmpresasAsignadas(usuarioId);
  }

  @RequirePermission('ADMINISTRACION', 'ADM_USR_USUARIO_EDITAR')
  @ApiBody({ type: AsignarEmpresaDto })
  @Post('asignar-empresa')
  asignarEmpresa(@Body() dto: AsignarEmpresaDto, @GetUser() user: LoginUserInfo) {
    return this.usersService.asignarEmpresa(dto.usuario_id, dto.empresa_id, dto.rol, user.id, user?.id);
  }

  @RequirePermission('ADMINISTRACION', 'ADM_USR_USUARIO_EDITAR')
  @ApiBody({ type: RevocarEmpresaDto })
  @Post('revocar-empresa')
  revocarEmpresa(@Body() dto: RevocarEmpresaDto, @GetUser() user: LoginUserInfo) {
    return this.usersService.revocarEmpresa(dto.usuario_id, dto.empresa_id, user?.id);
  }

  @RequirePermission('ADMINISTRACION', 'ADM_USR_USUARIO_EDITAR')
  @ApiBody({ type: RevocarEmpresaDto })
  @Put('toggle-acceso-empresa')
  toggleAccesoEmpresa(@Body() dto: RevocarEmpresaDto, @GetUser() user: LoginUserInfo) {
    return this.usersService.toggleAccesoEmpresa(dto.usuario_id, dto.empresa_id, user?.id);
  }

  // ==================== PIN SUPERVISOR ====================
  // Estos endpoints son SELF-SERVICE / operacionales (los usa el POS con cualquier
  // usuario autenticado): no llevan @RequirePermission a propósito. El de configurar
  // PIN de OTRO usuario (:id) sí es administrativo.

  @ApiBody({ type: ConfigurarPinDto })
  @Post('configurar-pin')
  configurarPin(@Body() dto: ConfigurarPinDto, @GetUser() user: LoginUserInfo) {
    // Siempre sobre el propio usuario del token.
    return this.usersService.configurarPin(user.id, dto.pin, user.id, user.empresa_id);
  }

  @RequirePermission('ADMINISTRACION', 'ADM_USR_USUARIO_EDITAR')
  @ApiBody({ type: ConfigurarPinDto })
  @Post(':id/configurar-pin')
  configurarPinUsuario(@Param('id') id: string, @Body() dto: ConfigurarPinDto, @GetUser() user: LoginUserInfo) {
    return this.usersService.configurarPin(id, dto.pin, user.id, user.empresa_id);
  }

  @ApiBody({ type: ValidarPinDto })
  @Post('validar-pin-supervisor')
  validarPinSupervisor(@Body() dto: ValidarPinDto, @GetUser() user: LoginUserInfo) {
    return this.usersService.validarPinSupervisor(dto, user.empresa_id, user.id);
  }

  @Get('verificar-pin/:id')
  verificarTienePin(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    const userId = id === 'me' ? user.id : id;
    return this.usersService.verificarTienePin(userId);
  }
}
