import {
  BadRequestException,
  ForbiddenException,
  Injectable,
  UnauthorizedException,
} from '@nestjs/common';
import { User, UserStatus } from '../generated/prisma/index';
import { PrismaService } from '../prisma/prisma.service';
import { verifyPassword } from './password.service';
import { getPermissions, rolePermissions } from './role-permissions';
import { TokenService } from './token.service';

export type LoginDto = {
  email?: string;
  password?: string;
};

@Injectable()
export class AuthService {
  constructor(
    private readonly prisma: PrismaService,
    private readonly tokenService: TokenService,
  ) {}

  async login(loginDto: LoginDto) {
    const email = loginDto.email?.trim().toLowerCase();
    const password = loginDto.password;

    if (!email || !password) {
      throw new BadRequestException('Email and password are required');
    }

    const user = await this.prisma.user.findUnique({
      where: { email },
    });

    if (!user || !(await verifyPassword(password, user.passwordHash))) {
      throw new UnauthorizedException('Invalid email or password');
    }

    if (user.status !== UserStatus.ACTIVE) {
      throw new ForbiddenException('User account is inactive');
    }

    return this.createSession(user);
  }

  async getSession(authorizationHeader?: string) {
    const payload = this.tokenService.verify(authorizationHeader);
    const user = await this.prisma.user.findUnique({
      where: { id: payload.sub },
    });

    if (!user) {
      throw new UnauthorizedException('User not found');
    }

    if (user.status !== UserStatus.ACTIVE) {
      throw new ForbiddenException('User account is inactive');
    }

    return {
      user: this.toPublicUser(user),
      permissions: getPermissions(user.role),
    };
  }

  getRolePermissions() {
    return {
      roles: {
        ADMIN: rolePermissions.ADMIN,
        MANAGER: rolePermissions.MANAGER,
        STAFF: rolePermissions.STAFF,
        EMPLOYEE: rolePermissions.EMPLOYEE,
        USER: rolePermissions.USER,
      },
    };
  }

  private createSession(user: User) {
    const accessToken = this.tokenService.sign({
      sub: user.id,
      email: user.email,
      name: user.name,
      role: user.role,
      status: user.status,
    });

    return {
      accessToken,
      tokenType: 'Bearer',
      expiresIn: this.tokenService.ttlSeconds,
      user: this.toPublicUser(user),
      permissions: getPermissions(user.role),
    };
  }

  private toPublicUser(user: User) {
    return {
      id: user.id,
      email: user.email,
      name: user.name,
      role: user.role,
      status: user.status,
    };
  }
}
