import { Body, Controller, Delete, ForbiddenException, Get, Headers, Param, Patch, Post, Query } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { ApiBearerAuth, ApiBody, ApiOperation, ApiParam, 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 { AddFamilyMemberDto, CreateFamilyGroupDto, RespondFamilyInviteDto, SendFamilyInviteDto, UpdateFamilyGroupDto } from '../dto/identity.dto';

@ApiTags('Семья')
@ApiBearerAuth()
@Controller('family')
export class FamilyController {
  constructor(
    private readonly core: CoreGrpcService,
    private readonly jwt: JwtService
  ) {}

  private async auth(authorization?: string) {
    return getAuthorizedUserId(this.jwt, this.core, authorization);
  }

  @Post('groups')
  @ApiOperation({ summary: 'Создать семейную группу' })
  @ApiBody({ type: CreateFamilyGroupDto })
  async createGroup(@Headers('authorization') authorization: string | undefined, @Body() dto: CreateFamilyGroupDto) {
    const userId = await this.auth(authorization);
    if (dto.ownerId !== userId) {
      throw new ForbiddenException('Можно создавать семью только от своего имени');
    }
    return firstValueFrom(this.core.family.CreateFamilyGroup(dto));
  }

  @Get('users/:userId/groups')
  @ApiOperation({ summary: 'Список семей пользователя' })
  async listGroups(@Headers('authorization') authorization: string | undefined, @Param('userId') userId: string) {
    const requesterId = await this.auth(authorization);
    if (requesterId !== userId) {
      throw new ForbiddenException('Можно просматривать только свои семьи');
    }
    return firstValueFrom(
      this.core.family.ListFamilyGroups({ userId }).pipe(
        map((response) => {
          const payload = response as { groups?: unknown[] };
          return { groups: payload.groups ?? [] };
        })
      )
    );
  }

  @Get('groups/:groupId')
  @ApiOperation({ summary: 'Получить семейную группу' })
  async getGroup(@Headers('authorization') authorization: string | undefined, @Param('groupId') groupId: string) {
    const requesterId = await this.auth(authorization);
    return firstValueFrom(this.core.family.GetFamilyGroup({ requesterId, groupId }));
  }

  @Patch('groups/:groupId')
  @ApiOperation({ summary: 'Обновить семейную группу' })
  async updateGroup(
    @Headers('authorization') authorization: string | undefined,
    @Param('groupId') groupId: string,
    @Body() dto: UpdateFamilyGroupDto
  ) {
    const requesterId = await this.auth(authorization);
    return firstValueFrom(this.core.family.UpdateFamilyGroup({ requesterId, groupId, name: dto.name }));
  }

  @Delete('groups/:groupId')
  @ApiOperation({ summary: 'Удалить семейную группу' })
  async deleteGroup(@Headers('authorization') authorization: string | undefined, @Param('groupId') groupId: string) {
    const requesterId = await this.auth(authorization);
    return firstValueFrom(this.core.family.DeleteFamilyGroup({ requesterId, groupId }));
  }

  @Post('groups/:groupId/members')
  @ApiOperation({ summary: 'Добавить участника семьи' })
  async addMember(
    @Headers('authorization') authorization: string | undefined,
    @Param('groupId') groupId: string,
    @Body() dto: AddFamilyMemberDto
  ) {
    await this.auth(authorization);
    return firstValueFrom(this.core.family.AddFamilyMember({ groupId, ...dto }));
  }

  @Delete('members/:memberId')
  @ApiOperation({ summary: 'Удалить участника семьи' })
  async removeMember(@Headers('authorization') authorization: string | undefined, @Param('memberId') memberId: string) {
    const requesterId = await this.auth(authorization);
    return firstValueFrom(this.core.family.RemoveFamilyMember({ requesterId, memberId }));
  }

  @Get('groups/:groupId/invite-search')
  @ApiOperation({ summary: 'Поиск пользователей для приглашения в семью' })
  async searchInviteUsers(
    @Headers('authorization') authorization: string | undefined,
    @Param('groupId') groupId: string,
    @Query('q') query: string
  ) {
    const requesterId = await this.auth(authorization);
    return firstValueFrom(this.core.family.SearchFamilyInviteUsers({ requesterId, groupId, query: query ?? '' }));
  }

  @Post('groups/:groupId/invites')
  @ApiOperation({ summary: 'Пригласить участника в семью' })
  async sendInvite(
    @Headers('authorization') authorization: string | undefined,
    @Param('groupId') groupId: string,
    @Body() dto: SendFamilyInviteDto
  ) {
    const requesterId = await this.auth(authorization);
    return firstValueFrom(
      this.core.family.SendFamilyInvite({
        requesterId,
        groupId,
        target: dto.target,
        inviteeUserId: dto.inviteeUserId
      })
    );
  }

  @Get('invites')
  @ApiOperation({ summary: 'Список приглашений' })
  async listInvites(@Headers('authorization') authorization: string | undefined) {
    const userId = await this.auth(authorization);
    return firstValueFrom(
      this.core.family.ListFamilyInvites({ userId }).pipe(
        map((response) => {
          const payload = response as { invites?: unknown[] };
          return { invites: payload.invites ?? [] };
        })
      )
    );
  }

  @Post('invites/:inviteId/respond')
  @ApiOperation({ summary: 'Принять или отклонить приглашение' })
  async respondInvite(
    @Headers('authorization') authorization: string | undefined,
    @Param('inviteId') inviteId: string,
    @Body() dto: RespondFamilyInviteDto
  ) {
    const userId = await this.auth(authorization);
    return firstValueFrom(this.core.family.RespondFamilyInvite({ userId, inviteId, accept: dto.accept }));
  }

  @Get('groups/:groupId/presence')
  @ApiOperation({ summary: 'Онлайн-статус участников семьи' })
  async getPresence(@Headers('authorization') authorization: string | undefined, @Param('groupId') groupId: string) {
    const requesterId = await this.auth(authorization);
    return firstValueFrom(this.core.family.GetFamilyPresence({ requesterId, groupId }));
  }

}

