import {
    Body,
    Controller,
    Delete,
    Get,
    HttpException,
    HttpStatus,
    Param,
    Post,
    Put,
    Query,
    UploadedFile,
    UseGuards,
    UseInterceptors,
} from '@nestjs/common';
import { AuthGuard } from '@nestjs/passport';
import { FileInterceptor } from '@nestjs/platform-express';
import { PutObjectCommand, S3Client } from '@aws-sdk/client-s3';
import { ApiBearerAuth, ApiBody, ApiConsumes, ApiCreatedResponse, ApiExcludeEndpoint, ApiParam } from '@nestjs/swagger';
import { envs } from 'src/config/envs';
import type { LoginUserInfo } from 'src/auth/dto/login.dto';
import { GetUser } from 'src/auth/get-user.decorator';
import { CreateSucursaleDto } from './dto/create-sucursal.dto';
import { response_create_sucursal, response_sucursal_all, response_sucursal_find } from './dto/doc-swagger';
import { UpdateSucursaleDto } from './dto/update-sucursale.dto';
import { SucursalesService } from './sucursales.service';

@Controller({ version: '1', path: 'sucursales' })
export class SucursalesController {
  constructor(private readonly sucursalesService: SucursalesService) {}

  @Post()
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiBody({ type: CreateSucursaleDto })
  @ApiCreatedResponse(response_create_sucursal)
  async create(@Body() createSucursaleDto: CreateSucursaleDto, @GetUser() user: LoginUserInfo) {
    return this.sucursalesService.create(createSucursaleDto, user.empresa_id, user?.id);
  }

  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiParam({ name: 'page', type: 'string', required: false, description: 'Pagina actual' })
  @ApiParam({ name: 'limit', type: 'string', required: false, description: 'Limit' })
  @ApiCreatedResponse(response_sucursal_all)
  @Get()
  async findAll(@Query('page') page?: string, @Query('limit') limit?: string, @GetUser() user?: LoginUserInfo) {
    try {
      const {
        items,
        total,
        page: currentPage,
        limit: pageLimit,
        lastPage,
      } = await this.sucursalesService.findAllByEmpresa(
        user?.empresa_id,
        Number(page) || 1,
        Number(limit) || 10,
        user?.id,
      );

      return {
        message: 'Sucursales obtenidas 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 sucursales',
          error: errorMessage,
        },
        HttpStatus.INTERNAL_SERVER_ERROR,
      );
    }
  }

  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiParam({ name: 'id', type: 'string', required: true, description: 'ID de la sucursal' })
  @ApiCreatedResponse(response_sucursal_find)
  @Get(':id')
  findOne(@Param('id') id: string) {
    return this.sucursalesService.findOne(id);
  }

  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiParam({ name: 'id', type: 'string', required: true, description: 'ID de la sucursal' })
  @Get(':id/detalle')
  findOneWithRelations(@Param('id') id: string) {
    return this.sucursalesService.findOneWithRelations(id);
  }

  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiParam({ name: 'id', type: 'string', required: true, description: 'ID del usuario' })
  @ApiBody({ type: UpdateSucursaleDto })
  @Put(':id')
  update(@Param('id') id: string, @Body() updateSucursaleDto: UpdateSucursaleDto, @GetUser() user: LoginUserInfo) {
    return this.sucursalesService.update(id, updateSucursaleDto, user?.id);
  }
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiParam({ name: 'id', type: 'string', required: true, description: 'ID del usuario' })
  @ApiCreatedResponse(response_sucursal_find)
  @Put('activar-desactivar/:id')
  activarDesactivar(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.sucursalesService.activarDesactivar(id, user?.id);
  }

  @ApiExcludeEndpoint()
  @Delete(':id')
  remove(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.sucursalesService.remove(id, user?.id);
  }

  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiParam({ name: 'id', type: 'string', required: true, description: 'ID de la sucursal' })
  @Put(':id/set-default')
  setDefault(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.sucursalesService.setDefault(id, user?.id);
  }

  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiParam({ name: 'id', type: 'string', required: true, description: 'ID de la sucursal' })
  @Put(':id/unset-default')
  unsetDefault(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.sucursalesService.unsetDefault(id, user?.id);
  }

  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiParam({ name: 'id', type: 'string', required: true, description: 'ID de la sucursal' })
  @Get(':id/config')
  getConfig(@Param('id') id: string) {
    return this.sucursalesService.getConfig(id);
  }

  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiParam({ name: 'id', type: 'string', required: true, description: 'ID de la sucursal' })
  @ApiBody({
    description: 'Configuración de la sucursal',
    schema: { type: 'object', properties: { envio_lote_middleware: { type: 'boolean' } } },
  })
  @Put(':id/config')
  updateConfig(@Param('id') id: string, @Body() config: Record<string, unknown>) {
    return this.sucursalesService.updateConfig(id, config);
  }

  /**
   * Logo propio de la sucursal, para las empresas que operan locales con
   * identidad visual distinta. Sin esto el KUDE sale siempre con el de la
   * empresa.
   *
   * Mismo flujo que el logo de empresa (`POST /empresas/:id/logo`): sube a
   * DigitalOcean Spaces y guarda la URL pública. La clave lleva el id de la
   * sucursal, así que subir de nuevo pisa el anterior y no deja huérfanos.
   */
  @Post(':id/logo')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiConsumes('multipart/form-data')
  @ApiParam({ name: 'id', type: 'string', required: true, description: 'ID de la sucursal' })
  @ApiBody({
    schema: { type: 'object', properties: { file: { type: 'string', format: 'binary' } } },
  })
  @UseInterceptors(FileInterceptor('file'))
  async uploadLogo(
    @Param('id') id: string,
    @UploadedFile() file: Express.Multer.File,
    @GetUser() user: LoginUserInfo,
  ) {
    try {
      const sucursal = await this.sucursalesService.findOne(id);
      const empresaSucursal = (sucursal as { data?: { empresa_id?: string } })?.data?.empresa_id;
      if (empresaSucursal && empresaSucursal !== user.empresa_id) {
        throw new HttpException(
          { success: false, message: 'No tienes permisos para esta sucursal', error: 'Error' },
          HttpStatus.FORBIDDEN,
        );
      }

      if (!file?.buffer) {
        throw new HttpException(
          { success: false, message: 'Archivo inválido', error: 'Error' },
          HttpStatus.BAD_REQUEST,
        );
      }

      const maxBytes = 5 * 1024 * 1024; // 5MB, igual que el logo de empresa
      if (file.size > maxBytes) {
        throw new HttpException(
          { success: false, message: 'El archivo excede el tamaño máximo permitido (5MB)', error: 'Error' },
          HttpStatus.BAD_REQUEST,
        );
      }

      const allowedMimeTypes = new Set(['image/png', 'image/jpeg', 'image/jpg', 'image/webp']);
      if (!file.mimetype || !allowedMimeTypes.has(file.mimetype)) {
        throw new HttpException(
          { success: false, message: 'Tipo de archivo no permitido. Solo PNG, JPG, JPEG o WEBP.', error: 'Error' },
          HttpStatus.BAD_REQUEST,
        );
      }

      const s3Client = new S3Client({
        endpoint: envs.doSpacesEndpoint,
        region: envs.doSpacesRegion,
        credentials: {
          accessKeyId: envs.doSpacesKey,
          secretAccessKey: envs.doSpacesSecret,
        },
      });

      const ext = file.originalname.split('.').pop() || 'png';
      const fileName = `logos/sucursales/${id}.${ext}`;

      await s3Client.send(
        new PutObjectCommand({
          Bucket: envs.doSpacesBucket,
          Key: fileName,
          Body: file.buffer,
          ContentType: file.mimetype,
          ACL: 'public-read',
        }),
      );

      // Cache-buster: la clave es fija por sucursal, así que sin esto el
      // navegador y el generador de PDF seguirían mostrando el logo anterior.
      const logoUrl = `${envs.doSpacesPublicUrl}/${fileName}?v=${Date.now()}`;
      return this.sucursalesService.updateLogo(id, logoUrl, user?.id);
    } catch (error) {
      if (error instanceof HttpException) throw error;
      const message = error instanceof Error ? error.message : 'Error al subir logo';
      throw new HttpException({ success: false, message, error: 'Error' }, HttpStatus.BAD_REQUEST);
    }
  }

  /**
   * Quita el logo propio: la sucursal vuelve a usar el de la empresa.
   */
  @Delete(':id/logo')
  @UseGuards(AuthGuard('jwt'))
  @ApiBearerAuth()
  @ApiParam({ name: 'id', type: 'string', required: true, description: 'ID de la sucursal' })
  removeLogo(@Param('id') id: string, @GetUser() user: LoginUserInfo) {
    return this.sucursalesService.updateLogo(id, null, user?.id);
  }
}
