import {
  Body,
  Controller,
  Delete,
  Get,
  Headers,
  Param,
  Post,
  Query,
  RawBodyRequest,
  Req,
  Res,
} from '@nestjs/common';
import { Request, Response } from 'express';
import { ApiBearerAuth, ApiTags } from '@nestjs/swagger';
import {
  IsBoolean,
  IsEnum,
  IsNumber,
  IsOptional,
  IsString,
  IsUUID,
  IsUrl,
} from 'class-validator';
import { DocumentCategory } from '@prisma/client';
import { DocumentsService } from './documents.service';
import { Roles } from '../../common/decorators/roles.decorator';
import { Public } from '../../common/decorators/public.decorator';
import { CurrentUser, AuthenticatedUser } from '../../common/decorators/current-user.decorator';

class UploadDocumentDto {
  @IsUUID() complexId!: string;
  @IsString() title!: string;
  @IsOptional() @IsEnum(DocumentCategory) category?: DocumentCategory;
  @IsOptional() @IsString() folder?: string;
  @IsOptional() @IsBoolean() isPublic?: boolean;
  @IsString() filename!: string;
  @IsUrl({ require_tld: false }) url!: string;
  @IsOptional() @IsString() mimeType?: string;
  @IsOptional() @IsNumber() sizeBytes?: number;
  @IsOptional() @IsString() contentBase64?: string;
}

class AddVersionDto {
  @IsString() filename!: string;
  @IsUrl({ require_tld: false }) url!: string;
  @IsOptional() @IsString() mimeType?: string;
  @IsOptional() @IsNumber() sizeBytes?: number;
  @IsOptional() @IsString() contentBase64?: string;
}

class RequestSignatureDto {
  @IsUUID() signerId!: string;
}

@ApiTags('documents')
@ApiBearerAuth()
@Controller('documents')
export class DocumentsController {
  constructor(private readonly service: DocumentsService) {}

  @Post()
  @Roles('SUPERADMIN', 'SYNDIC')
  upload(@CurrentUser() user: AuthenticatedUser, @Body() dto: UploadDocumentDto) {
    return this.service.upload(user, dto);
  }

  @Post(':id/versions')
  @Roles('SUPERADMIN', 'SYNDIC')
  addVersion(
    @CurrentUser() user: AuthenticatedUser,
    @Param('id') id: string,
    @Body() dto: AddVersionDto,
  ) {
    return this.service.addVersion(user, id, dto);
  }

  @Get()
  list(
    @CurrentUser() user: AuthenticatedUser,
    @Query('complexId') complexId?: string,
    @Query('category') category?: DocumentCategory,
  ) {
    return this.service.list(user, complexId, category);
  }

  @Get(':id')
  findOne(@CurrentUser() user: AuthenticatedUser, @Param('id') id: string) {
    return this.service.findOne(user, id);
  }

  @Post(':id/signatures')
  @Roles('SUPERADMIN', 'SYNDIC')
  requestSignature(
    @CurrentUser() user: AuthenticatedUser,
    @Param('id') id: string,
    @Body() dto: RequestSignatureDto,
  ) {
    return this.service.requestSignature(user, id, dto.signerId);
  }

  @Public()
  @Get('signature/stub-sign/:ref')
  async stubSign(@Param('ref') ref: string, @Res() res: Response) {
    const result = await this.service.completeStubSignature(ref);
    if (!result) {
      res.status(404).send('Unknown signature ref');
      return;
    }
    res
      .status(200)
      .type('html')
      .send(
        `<html><body style="font-family:sans-serif"><h2>✅ Document signé (stub)</h2><p>Ref: ${ref}</p></body></html>`,
      );
  }

  @Public()
  @Post('signature/callback')
  callback(@Req() req: RawBodyRequest<Request>, @Headers() headers: Record<string, string>) {
    const raw = req.rawBody?.toString('utf8') ?? JSON.stringify(req.body);
    return this.service.handleSignatureCallback(raw, headers);
  }

  @Delete(':id')
  @Roles('SUPERADMIN', 'SYNDIC')
  remove(@CurrentUser() user: AuthenticatedUser, @Param('id') id: string) {
    return this.service.remove(user, id);
  }
}
