import { Body, Controller, Delete, Get, Headers, Param, Patch, Post } from '@nestjs/common';
import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
import { JwtService } from '@nestjs/jwt';
import { firstValueFrom } from 'rxjs';
import { CoreGrpcService } from '../core-grpc.service';
import { assertDocumentsReadAccess, assertDocumentsWriteAccess } from '../document-access';
import { CreateDocumentDto, UpdateDocumentDto } from '../dto/documents.dto';

@ApiTags('Хранилище данных и документы')
@ApiBearerAuth()
@Controller('documents/users/:userId')
export class DocumentsController {
  constructor(
    private readonly core: CoreGrpcService,
    private readonly jwt: JwtService
  ) {}

  @Post()
  @ApiOperation({ summary: 'Создать документ', description: 'Создает документ пользователя с данными формы. Поля шифруются в SSO Core.' })
  @ApiParam({ name: 'userId', description: 'ID пользователя' })
  @ApiBody({ type: CreateDocumentDto })
  async create(
    @Headers('authorization') authorization: string | undefined,
    @Param('userId') userId: string,
    @Body() dto: CreateDocumentDto
  ) {
    await assertDocumentsWriteAccess(this.jwt, this.core, authorization, userId);
    return firstValueFrom(
      this.core.documents.CreateDocument({
        userId,
        type: dto.type,
        number: dto.number ?? '—',
        issuedAt: dto.issuedAt,
        expiresAt: dto.expiresAt,
        metadataJson: dto.metadataJson
      })
    );
  }

  @Get()
  @ApiOperation({ summary: 'Список документов', description: 'Возвращает все документы пользователя.' })
  @ApiParam({ name: 'userId', description: 'ID пользователя' })
  async list(@Headers('authorization') authorization: string | undefined, @Param('userId') userId: string) {
    await assertDocumentsReadAccess(this.jwt, this.core, authorization, userId);
    const result = (await firstValueFrom(this.core.documents.ListDocuments({ userId }))) as {
      documents?: unknown[];
    };
    return { documents: result.documents ?? [] };
  }

  @Get(':documentId')
  @ApiOperation({ summary: 'Получить документ', description: 'Возвращает один документ пользователя с расшифрованными полями.' })
  @ApiParam({ name: 'userId', description: 'ID пользователя' })
  @ApiParam({ name: 'documentId', description: 'ID документа' })
  async get(
    @Headers('authorization') authorization: string | undefined,
    @Param('userId') userId: string,
    @Param('documentId') documentId: string
  ) {
    await assertDocumentsReadAccess(this.jwt, this.core, authorization, userId);
    return firstValueFrom(this.core.documents.GetDocument({ userId, documentId }));
  }

  @Patch(':documentId')
  @ApiOperation({ summary: 'Обновить документ', description: 'Обновляет данные формы документа.' })
  @ApiParam({ name: 'userId', description: 'ID пользователя' })
  @ApiParam({ name: 'documentId', description: 'ID документа' })
  @ApiBody({ type: UpdateDocumentDto })
  async update(
    @Headers('authorization') authorization: string | undefined,
    @Param('userId') userId: string,
    @Param('documentId') documentId: string,
    @Body() dto: UpdateDocumentDto
  ) {
    await assertDocumentsWriteAccess(this.jwt, this.core, authorization, userId);
    return firstValueFrom(this.core.documents.UpdateDocument({ userId, documentId, ...dto }));
  }

  @Delete(':documentId')
  @ApiOperation({ summary: 'Удалить документ', description: 'Удаляет документ пользователя.' })
  @ApiParam({ name: 'userId', description: 'ID пользователя' })
  @ApiParam({ name: 'documentId', description: 'ID документа' })
  @ApiResponse({ status: 200, description: 'Документ удалён' })
  async delete(
    @Headers('authorization') authorization: string | undefined,
    @Param('userId') userId: string,
    @Param('documentId') documentId: string
  ) {
    await assertDocumentsWriteAccess(this.jwt, this.core, authorization, userId);
    return firstValueFrom(this.core.documents.DeleteDocument({ userId, documentId }));
  }
}
