import { Body, Controller, Delete, ForbiddenException, Get, Headers, Param, Post } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
import { firstValueFrom } from 'rxjs';
import { map } from 'rxjs/operators';
import { CoreGrpcService } from '../core-grpc.service';
import { getAuthorizedUserId } from '../document-access';
import { UpsertAddressDto } from '../dto/addresses.dto';

@ApiTags('Адреса')
@ApiBearerAuth()
@Controller('addresses/users/:userId')
export class AddressesController {
  constructor(
    private readonly core: CoreGrpcService,
    private readonly jwt: JwtService
  ) {}

  private async assertSelfAccess(authorization: string | undefined, userId: string) {
    const requesterId = await getAuthorizedUserId(this.jwt, this.core, authorization);
    if (requesterId !== userId) {
      throw new ForbiddenException('Можно управлять только своими адресами');
    }
    return requesterId;
  }

  @Get()
  @ApiOperation({ summary: 'Список адресов пользователя' })
  @ApiParam({ name: 'userId', description: 'ID пользователя' })
  async list(@Headers('authorization') authorization: string | undefined, @Param('userId') userId: string) {
    await this.assertSelfAccess(authorization, userId);
    return firstValueFrom(
      this.core.addresses.ListAddresses({ userId }).pipe(
        map((response) => {
          const payload = response as { addresses?: unknown[] };
          return { addresses: payload.addresses ?? [] };
        })
      )
    );
  }

  @Post()
  @ApiOperation({ summary: 'Создать или обновить адрес' })
  @ApiParam({ name: 'userId', description: 'ID пользователя' })
  @ApiBody({ type: UpsertAddressDto })
  async upsert(
    @Headers('authorization') authorization: string | undefined,
    @Param('userId') userId: string,
    @Body() dto: UpsertAddressDto
  ) {
    await this.assertSelfAccess(authorization, userId);
    return firstValueFrom(this.core.addresses.UpsertAddress({ userId, ...dto }));
  }

  @Delete(':addressId')
  @ApiOperation({ summary: 'Удалить адрес' })
  @ApiParam({ name: 'userId', description: 'ID пользователя' })
  @ApiParam({ name: 'addressId', description: 'ID адреса' })
  @ApiResponse({ status: 200, description: 'Адрес удалён' })
  async delete(
    @Headers('authorization') authorization: string | undefined,
    @Param('userId') userId: string,
    @Param('addressId') addressId: string
  ) {
    await this.assertSelfAccess(authorization, userId);
    return firstValueFrom(this.core.addresses.DeleteAddress({ userId, addressId }));
  }
}
