import { ForbiddenException, UnauthorizedException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { firstValueFrom } from 'rxjs';
import { extractBearerToken } from './auth-token';
import { CoreGrpcService } from './core-grpc.service';

export interface AccessTokenPayload {
  sub: string;
  sessionId?: string;
  pinVerified?: boolean;
  isSuperAdmin?: boolean;
}

export async function verifyAccessToken(jwt: JwtService, authorization?: string): Promise<AccessTokenPayload> {
  const token = extractBearerToken(authorization);

  try {
    return await jwt.verifyAsync<AccessTokenPayload>(token, {
      secret: process.env.JWT_ACCESS_SECRET ?? 'docker-access-secret',
      issuer: 'id.lendry.ru'
    });
  } catch {
    throw new UnauthorizedException({
      statusCode: 401,
      message: 'Токен доступа недействителен или истёк',
      code: 'TOKEN_EXPIRED'
    });
  }
}

export async function assertSessionUnlocked(core: CoreGrpcService, payload: AccessTokenPayload) {
  if (!payload.sessionId) {
    return;
  }

  const validation = (await firstValueFrom(
    core.auth.ValidateSession({
      userId: payload.sub,
      sessionId: payload.sessionId,
      touchActivity: true
    })
  )) as { requiresPin: boolean; sessionId: string };

  if (validation.requiresPin) {
    throw new ForbiddenException({
      statusCode: 403,
      message: 'Требуется подтверждение PIN-кода',
      code: 'PIN_REQUIRED',
      sessionId: validation.sessionId
    });
  }
}

export async function resolveAuthorizedPayload(
  jwt: JwtService,
  core: CoreGrpcService,
  authorization?: string
): Promise<AccessTokenPayload> {
  const payload = await verifyAccessToken(jwt, authorization);
  await assertSessionUnlocked(core, payload);
  return payload;
}
