import {
  ForbiddenException,
  HttpException,
  HttpStatus,
  Injectable,
  Logger,
} from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { Request } from 'express';
import { UserSessionEntity } from '../../modules/user_sessions/entities/user_session.entity';
import { UserEntity } from '../../modules/user/entities/user.entity';

@Injectable()
export class MobileSessionService {
  private readonly logger = new Logger(MobileSessionService.name);

  constructor(
    @InjectRepository(UserSessionEntity)
    private readonly sessionRepo: Repository<UserSessionEntity>,
  ) {}

  normalizeSessionToken(sessionToken?: string) {
    return sessionToken?.trim().replace(/ /g, '+');
  }

  extractSessionToken(req: Request): string | undefined {
    const authorization = req.headers.authorization;
    if (
      typeof authorization === 'string' &&
      authorization.startsWith('Bearer ')
    ) {
      return this.normalizeSessionToken(authorization.slice(7));
    }

    const headerToken = req.headers['x-session-token'];
    if (typeof headerToken === 'string' && headerToken.trim()) {
      return this.normalizeSessionToken(headerToken);
    }

    const queryToken = req.query?.sessionToken;
    if (typeof queryToken === 'string' && queryToken.trim()) {
      return this.normalizeSessionToken(queryToken);
    }

    const bodyToken = (req.body as Record<string, unknown> | undefined)
      ?.sessionToken;
    if (typeof bodyToken === 'string' && bodyToken.trim()) {
      return this.normalizeSessionToken(bodyToken);
    }

    return undefined;
  }

  async getUserFromSessionToken(sessionToken?: string): Promise<UserEntity> {
    const token = this.normalizeSessionToken(sessionToken);
    if (!token) {
      throw new HttpException(
        'Session token is required. Pass Authorization: Bearer <sessionToken> from OTP verify.',
        HttpStatus.UNAUTHORIZED,
      );
    }

    const session = await this.sessionRepo.findOne({
      where: { sessionToken: token, isActive: 1 },
      relations: ['user'],
    });

    if (!session?.user) {
      throw new HttpException('Invalid session', HttpStatus.UNAUTHORIZED);
    }

    if (session.expiresAt && session.expiresAt <= new Date()) {
      throw new HttpException('Session expired', HttpStatus.UNAUTHORIZED);
    }

    this.logger.log(`Mobile session resolved - userId: ${session.user.id}`);
    return session.user;
  }

  async getUserFromRequest(req: Request): Promise<UserEntity> {
    const token = this.extractSessionToken(req);
    return this.getUserFromSessionToken(token);
  }

  assertSeekerUser(user: UserEntity) {
    if (user.role !== 'seeker') {
      throw new ForbiddenException('Seeker session required');
    }
  }
}
