import {
  Controller,
  Get,
  Post,
  Patch,
  Delete,
  Body,
  Param,
  Query,
  Res,
  ParseUUIDPipe,
  HttpCode,
  HttpStatus,
  UseGuards,
  UseInterceptors,
  UploadedFile,
  ParseFilePipe,
  MaxFileSizeValidator,
} from '@nestjs/common';
import { FileInterceptor } from '@nestjs/platform-express';
import {
  ApiTags,
  ApiOperation,
  ApiBearerAuth,
  ApiParam,
  ApiConsumes,
  ApiQuery,
} from '@nestjs/swagger';
import { Response } from 'express';
import { ContractsService } from './contracts.service';
import { CreateContractDto } from './dto/create-contract.dto';
import { UpdateContractDto } from './dto/update-contract.dto';
import { QueryContractsDto } from './dto/query-contracts.dto';
import { CurrentUser, JwtPayload } from '../common/decorators';
import { TenantGuard } from '../auth/guards/tenant.guard';
import {
  paginatedResponse,
  singleResponse,
} from '../common/dto/pagination.dto';

@ApiTags('Contracts (Vertraege)')
@ApiBearerAuth('access-token')
@UseGuards(TenantGuard)
@Controller('companies/:companyId/contracts')
export class ContractsController {
  constructor(private readonly contractsService: ContractsService) {}

  @Post()
  @HttpCode(HttpStatus.CREATED)
  @ApiOperation({ summary: 'Vertrag anlegen' })
  @ApiParam({ name: 'companyId', type: 'string', format: 'uuid' })
  async create(
    @CurrentUser() user: JwtPayload,
    @Param('companyId', ParseUUIDPipe) companyId: string,
    @Body() dto: CreateContractDto,
  ) {
    const contract = await this.contractsService.create(
      user.tenantId!,
      companyId,
      user.sub,
      dto,
    );
    return singleResponse(contract);
  }

  @Get()
  @ApiOperation({ summary: 'Vertraege einer Firma auflisten (paginiert)' })
  @ApiParam({ name: 'companyId', type: 'string', format: 'uuid' })
  async findAll(
    @CurrentUser() user: JwtPayload,
    @Param('companyId', ParseUUIDPipe) companyId: string,
    @Query() query: QueryContractsDto,
  ) {
    const result = await this.contractsService.findAll(
      user.tenantId!,
      companyId,
      query,
    );
    return paginatedResponse(
      result.data,
      result.total,
      result.page,
      result.pageSize,
    );
  }

  @Get(':id')
  @ApiOperation({ summary: 'Vertrag-Details abrufen' })
  @ApiParam({ name: 'companyId', type: 'string', format: 'uuid' })
  @ApiParam({ name: 'id', type: 'string', format: 'uuid' })
  async findOne(
    @CurrentUser() user: JwtPayload,
    @Param('companyId', ParseUUIDPipe) companyId: string,
    @Param('id', ParseUUIDPipe) id: string,
  ) {
    const contract = await this.contractsService.findOne(
      user.tenantId!,
      companyId,
      id,
    );
    return singleResponse(contract);
  }

  @Patch(':id')
  @ApiOperation({ summary: 'Vertrag aktualisieren' })
  @ApiParam({ name: 'companyId', type: 'string', format: 'uuid' })
  @ApiParam({ name: 'id', type: 'string', format: 'uuid' })
  async update(
    @CurrentUser() user: JwtPayload,
    @Param('companyId', ParseUUIDPipe) companyId: string,
    @Param('id', ParseUUIDPipe) id: string,
    @Body() dto: UpdateContractDto,
  ) {
    const contract = await this.contractsService.update(
      user.tenantId!,
      companyId,
      id,
      dto,
    );
    return singleResponse(contract);
  }

  @Delete(':id')
  @ApiOperation({ summary: 'Vertrag loeschen' })
  @ApiParam({ name: 'companyId', type: 'string', format: 'uuid' })
  @ApiParam({ name: 'id', type: 'string', format: 'uuid' })
  async remove(
    @CurrentUser() user: JwtPayload,
    @Param('companyId', ParseUUIDPipe) companyId: string,
    @Param('id', ParseUUIDPipe) id: string,
  ) {
    const contract = await this.contractsService.remove(
      user.tenantId!,
      companyId,
      id,
    );
    return singleResponse(contract);
  }

  // --- Contract Files ---

  @Post(':contractId/files')
  @HttpCode(HttpStatus.CREATED)
  @UseInterceptors(FileInterceptor('file'))
  @ApiConsumes('multipart/form-data')
  @ApiOperation({ summary: 'Datei an Vertrag hochladen (PDF, Word, Excel)' })
  @ApiParam({ name: 'companyId', type: 'string', format: 'uuid' })
  @ApiParam({ name: 'contractId', type: 'string', format: 'uuid' })
  async uploadFile(
    @CurrentUser() user: JwtPayload,
    @Param('companyId', ParseUUIDPipe) companyId: string,
    @Param('contractId', ParseUUIDPipe) contractId: string,
    @UploadedFile(
      new ParseFilePipe({
        validators: [
          new MaxFileSizeValidator({ maxSize: 26_214_400 }), // 25 MB
        ],
      }),
    )
    file: Express.Multer.File,
  ) {
    const result = await this.contractsService.uploadFile(
      user.tenantId!,
      companyId,
      contractId,
      user.sub,
      file,
    );
    return singleResponse(result);
  }

  @Get(':contractId/files')
  @ApiOperation({ summary: 'Dateien eines Vertrags auflisten' })
  @ApiParam({ name: 'companyId', type: 'string', format: 'uuid' })
  @ApiParam({ name: 'contractId', type: 'string', format: 'uuid' })
  async listFiles(
    @CurrentUser() user: JwtPayload,
    @Param('companyId', ParseUUIDPipe) companyId: string,
    @Param('contractId', ParseUUIDPipe) contractId: string,
  ) {
    const files = await this.contractsService.listFiles(
      user.tenantId!,
      companyId,
      contractId,
    );
    return singleResponse(files);
  }

  @Get(':contractId/files/:fileId/download')
  @ApiOperation({ summary: 'Datei herunterladen / inline anzeigen' })
  @ApiParam({ name: 'companyId', type: 'string', format: 'uuid' })
  @ApiParam({ name: 'contractId', type: 'string', format: 'uuid' })
  @ApiParam({ name: 'fileId', type: 'string', format: 'uuid' })
  @ApiQuery({ name: 'inline', required: false, type: 'boolean' })
  async downloadFile(
    @CurrentUser() user: JwtPayload,
    @Param('companyId', ParseUUIDPipe) companyId: string,
    @Param('contractId', ParseUUIDPipe) contractId: string,
    @Param('fileId', ParseUUIDPipe) fileId: string,
    @Query('inline') inline: string | undefined,
    @Res() res: Response,
  ) {
    const { file, absPath } = await this.contractsService.getFile(
      user.tenantId!,
      companyId,
      contractId,
      fileId,
    );

    const disposition =
      inline === 'true'
        ? `inline; filename="${file.originalName}"`
        : `attachment; filename="${file.originalName}"`;

    res.setHeader('Content-Type', file.mimeType);
    res.setHeader('Content-Disposition', disposition);
    res.sendFile(absPath);
  }

  @Delete(':contractId/files/:fileId')
  @ApiOperation({ summary: 'Datei eines Vertrags loeschen' })
  @ApiParam({ name: 'companyId', type: 'string', format: 'uuid' })
  @ApiParam({ name: 'contractId', type: 'string', format: 'uuid' })
  @ApiParam({ name: 'fileId', type: 'string', format: 'uuid' })
  async deleteFile(
    @CurrentUser() user: JwtPayload,
    @Param('companyId', ParseUUIDPipe) companyId: string,
    @Param('contractId', ParseUUIDPipe) contractId: string,
    @Param('fileId', ParseUUIDPipe) fileId: string,
  ) {
    const result = await this.contractsService.deleteFile(
      user.tenantId!,
      companyId,
      contractId,
      fileId,
    );
    return singleResponse(result);
  }
}
