import { Body, Controller, Delete, ForbiddenException, Get, Headers, Param, Patch, Post } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, ApiResponse, ApiTags } from '@nestjs/swagger';
import { CoreGrpcService } from '../core-grpc.service';
import { getAuthorizedUserId } from '../document-access';
import {
  ChangePasswordDto,
  PasswordVerificationDto,
  SendPasswordVerificationOtpDto,
  SetPasswordDto,
  UpdateAvatarDto,
  UpdateContactsDto,
  UpdateProfileDto
} from '../dto/profile.dto';
@ApiTags('Профиль и биометрия')
@ApiBearerAuth()
@Controller('profile/users/:userId')
export class ProfileController {
  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: 'Получить профиль пользователя', description: 'Возвращает публичный профиль, аватар и основные/резервные контакты пользователя.' })
  @ApiParam({ name: 'userId', description: 'ID пользователя' })
  @ApiResponse({ status: 200, description: 'Профиль пользователя успешно получен' })
  @ApiResponse({ status: 404, description: 'Пользователь не найден' })
  getProfile(@Param('userId') userId: string) {
    return this.core.profile.GetProfile({ userId });
  }

  @Patch('avatar')
  @ApiOperation({ summary: 'Обновить аватар', description: 'Сохраняет URL или ключ объекта MinIO как аватар пользователя.' })
  @ApiParam({ name: 'userId', description: 'ID пользователя' })
  @ApiBody({ type: UpdateAvatarDto })
  @ApiResponse({ status: 200, description: 'Аватар обновлен' })
  updateAvatar(@Param('userId') userId: string, @Body() dto: UpdateAvatarDto) {
    return this.core.profile.UpdateAvatar({ userId, avatarUrl: dto.avatarUrl, avatarStorageKey: dto.avatarStorageKey });
  }

  @Patch()
  @ApiOperation({ summary: 'Обновить профиль', description: 'Обновляет firstName, lastName, bio, age и gender в UserProfile, а displayName синхронизирует с именем и фамилией.' })
  @ApiParam({ name: 'userId', description: 'ID пользователя' })
  @ApiBody({ type: UpdateProfileDto })
  @ApiResponse({ status: 200, description: 'Профиль обновлен' })
  updateProfile(@Param('userId') userId: string, @Body() dto: UpdateProfileDto) {
    return this.core.profile.UpdateProfile({ userId, ...dto });
  }

  @Patch('contacts')
  @ApiOperation({ summary: 'Обновить контакты', description: 'Обновляет основную и резервную почту/телефон в модели User.' })
  @ApiParam({ name: 'userId', description: 'ID пользователя' })
  @ApiBody({ type: UpdateContactsDto })
  @ApiResponse({ status: 200, description: 'Контакты обновлены' })
  @ApiResponse({ status: 400, description: 'Переданы некорректные контактные данные' })
  updateContacts(@Param('userId') userId: string, @Body() dto: UpdateContactsDto) {
    return this.core.profile.UpdateContacts({ userId, ...dto });
  }

  @Post('password')
  @ApiOperation({ summary: 'Установить пароль', description: 'Устанавливает пароль для аккаунта без ранее заданного пароля.' })
  @ApiParam({ name: 'userId', description: 'ID пользователя' })
  @ApiBody({ type: SetPasswordDto })
  @ApiResponse({ status: 201, description: 'Пароль установлен' })
  async setPassword(
    @Headers('authorization') authorization: string | undefined,
    @Param('userId') userId: string,
    @Body() dto: SetPasswordDto
  ) {
    await this.assertSelfAccess(authorization, userId);
    return this.core.profile.SetPassword({ userId, password: dto.password });
  }

  @Post('password/otp')
  @ApiOperation({ summary: 'Отправить OTP для смены пароля' })
  async sendPasswordVerificationOtp(
    @Headers('authorization') authorization: string | undefined,
    @Param('userId') userId: string,
    @Body() dto: SendPasswordVerificationOtpDto
  ) {
    await this.assertSelfAccess(authorization, userId);
    return this.core.profile.SendPasswordVerificationOtp({ userId, channel: dto.channel });
  }

  @Patch('password')
  @ApiOperation({ summary: 'Сменить пароль с подтверждением личности' })
  async changePassword(
    @Headers('authorization') authorization: string | undefined,
    @Param('userId') userId: string,
    @Body() dto: ChangePasswordDto
  ) {
    await this.assertSelfAccess(authorization, userId);
    return this.core.profile.ChangePassword({ userId, ...dto });
  }

  @Delete('password')
  @ApiOperation({ summary: 'Удалить пароль с подтверждением личности' })
  async removePassword(
    @Headers('authorization') authorization: string | undefined,
    @Param('userId') userId: string,
    @Body() dto: PasswordVerificationDto
  ) {
    await this.assertSelfAccess(authorization, userId);
    return this.core.profile.RemovePassword({ userId, ...dto });
  }

  @Post('self-delete')
  @ApiOperation({
    summary: 'Запросить удаление своего профиля',
    description:
      'Планирует удаление аккаунта через период ожидания ACCOUNT_DELETE_GRACE_DAYS. До истечения срока пользователь может отменить удаление.'
  })
  @ApiParam({ name: 'userId', description: 'ID пользователя' })
  @ApiResponse({ status: 201, description: 'Удаление запланировано' })
  async selfDelete(@Headers('authorization') authorization: string | undefined, @Param('userId') userId: string) {
    await this.assertSelfAccess(authorization, userId);
    return this.core.profile.RequestAccountDeletion({ userId });
  }

  @Post('self-delete/cancel')
  @ApiOperation({ summary: 'Отменить запланированное удаление профиля' })
  async cancelSelfDelete(@Headers('authorization') authorization: string | undefined, @Param('userId') userId: string) {
    await this.assertSelfAccess(authorization, userId);
    return this.core.profile.CancelAccountDeletion({ userId });
  }

  @Get('self-delete/status')
  @ApiOperation({ summary: 'Статус запланированного удаления профиля' })
  async selfDeleteStatus(@Headers('authorization') authorization: string | undefined, @Param('userId') userId: string) {
    await this.assertSelfAccess(authorization, userId);
    return this.core.profile.GetAccountDeletionStatus({ userId });
  }

  @Get('e2e-public-key')
  @ApiOperation({ summary: 'Получить публичный E2E-ключ пользователя' })
  async getE2EPublicKey(@Param('userId') userId: string) {
    return this.core.profile.GetE2EPublicKey({ userId });
  }

  @Patch('e2e-public-key')
  @ApiOperation({ summary: 'Сохранить свой публичный E2E-ключ' })
  async setE2EPublicKey(
    @Headers('authorization') authorization: string | undefined,
    @Param('userId') userId: string,
    @Body() dto: { publicKey: string }
  ) {
    await this.assertSelfAccess(authorization, userId);
    return this.core.profile.SetE2EPublicKey({ userId, publicKey: dto.publicKey });
  }
}

