import { Injectable, UnauthorizedException, forwardRef, Inject } from '@nestjs/common';
import { InjectRepository } from '@nestjs/typeorm';
import { Repository } from 'typeorm';
import { JwtService } from '@nestjs/jwt';
import * as bcrypt from 'bcryptjs';
import { User } from '../entities/user.entity';
import { LoginDto } from './dto/auth.dto';
import { RbacService } from '../rbac/rbac.service';

// 内存中的登录失败计数器（按IP+用户名）
const loginAttempts = new Map<string, { count: number; lockedUntil?: Date }>();
const MAX_ATTEMPTS = 5;
const LOCK_MINUTES = 15;

@Injectable()
export class AuthService {
  constructor(
    @InjectRepository(User) private userRepo: Repository<User>,
    private jwtService: JwtService,
    @Inject(forwardRef(() => RbacService)) private rbacService: RbacService,
  ) {}

  async login(dto: LoginDto, ip?: string) {
    const attemptKey = `${ip || 'unknown'}:${dto.username}`;
    const attempt = loginAttempts.get(attemptKey);

    // 检查是否在锁定期
    if (attempt?.lockedUntil && attempt.lockedUntil > new Date()) {
      const remaining = Math.ceil((attempt.lockedUntil.getTime() - Date.now()) / 60000);
      throw new UnauthorizedException(`账号已被临时锁定，请 ${remaining} 分钟后重试`);
    }

    const user = await this.userRepo.findOne({
      where: { username: dto.username },
      relations: ['roles'],
    });
    if (!user) {
      this.recordFailedAttempt(attemptKey);
      throw new UnauthorizedException('用户名或密码错误');
    }
    if (!user.isActive || user.isArchived) {
      throw new UnauthorizedException('账号已失效，请联系管理员');
    }
    const valid = await bcrypt.compare(dto.password, user.passwordHash);
    if (!valid) {
      this.recordFailedAttempt(attemptKey);
      const att = loginAttempts.get(attemptKey);
      const remaining = MAX_ATTEMPTS - (att?.count || 0);
      if (remaining > 0) {
        throw new UnauthorizedException(`用户名或密码错误，还剩 ${remaining} 次尝试机会`);
      }
      throw new UnauthorizedException(`登录失败次数过多，账号已被锁定 ${LOCK_MINUTES} 分钟`);
    }

    // 登录成功，清除失败计数
    loginAttempts.delete(attemptKey);

    // 记录登录时间
    user.lastLoginAt = new Date();
    await this.userRepo.save(user);

    // 获取用户权限
    const permissions = await this.rbacService.getUserPermissions(user.id);
    const isSuperAdmin =
      user.roles?.some(
        (role) =>
          role.status === 1 &&
          (role.name === '超管' || role.name === 'super_admin' || role.code === 'super_admin'),
      ) ?? false;
    const payload = { sub: user.id, username: user.username, permissions, isSuperAdmin };

    // 获取角色名称列表
    const roleNames = user.roles ? user.roles.filter((r) => r.status === 1).map((r) => r.name) : [];

    return {
      access_token: this.jwtService.sign(payload),
      user: {
        id: user.id,
        username: user.username,
        name: user.name,
        roles: roleNames,
        permissions,
      },
    };
  }

  private recordFailedAttempt(key: string) {
    const attempt = loginAttempts.get(key) || { count: 0 };
    attempt.count++;
    if (attempt.count >= MAX_ATTEMPTS) {
      attempt.lockedUntil = new Date(Date.now() + LOCK_MINUTES * 60 * 1000);
    }
    loginAttempts.set(key, attempt);
  }

  async validateUser(payload: any) {
    return this.userRepo.findOne({ where: { id: payload.sub } });
  }
}
