import { ForbiddenException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { firstValueFrom } from 'rxjs';
import { CoreGrpcService } from './core-grpc.service';
import { assertSessionUnlocked, verifyAccessToken } from './session-auth';

interface RequesterProfile {
  id: string;
  isSuperAdmin: boolean;
  canViewUserDocuments?: boolean;
}

async function getRequesterProfile(jwt: JwtService, core: CoreGrpcService, authorization?: string): Promise<RequesterProfile> {
  const payload = await verifyAccessToken(jwt, authorization);
  await assertSessionUnlocked(core, payload);

  if (payload.isSuperAdmin) {
    return { id: payload.sub, isSuperAdmin: true, canViewUserDocuments: true };
  }

  const profile = (await firstValueFrom(core.auth.GetMe({ userId: payload.sub }))) as RequesterProfile & { id: string };
  return { id: profile.id, isSuperAdmin: profile.isSuperAdmin, canViewUserDocuments: profile.canViewUserDocuments };
}

export async function assertDocumentsReadAccess(
  jwt: JwtService,
  core: CoreGrpcService,
  authorization: string | undefined,
  targetUserId: string
) {
  const requester = await getRequesterProfile(jwt, core, authorization);
  if (requester.id === targetUserId) {
    return requester.id;
  }
  if (!requester.canViewUserDocuments && !requester.isSuperAdmin) {
    throw new ForbiddenException('Нет доступа к документам пользователя');
  }
  return requester.id;
}

export async function assertDocumentsWriteAccess(
  jwt: JwtService,
  core: CoreGrpcService,
  authorization: string | undefined,
  targetUserId: string
) {
  const requester = await getRequesterProfile(jwt, core, authorization);
  if (requester.id !== targetUserId) {
    throw new ForbiddenException('Нельзя изменять документы другого пользователя');
  }
  return requester.id;
}

export async function getAuthorizedUserId(jwt: JwtService, core: CoreGrpcService, authorization?: string) {
  const requester = await getRequesterProfile(jwt, core, authorization);
  return requester.id;
}
