import { Injectable, UnauthorizedException, ForbiddenException } from '@nestjs/common';
import { JwtService } from '@nestjs/jwt';
import { ConfigService } from '@nestjs/config';
import * as bcrypt from 'bcryptjs';
import { PrismaService } from '../../shared/prisma/prisma.service';
import { SystemConfigService } from '../../shared/config/system-config.service';

const MAX_LOGIN_FAILS = 5;
const LOCK_DURATION_MS = 15 * 60 * 1000;

export interface JwtPayload {
  sub: string;
  username: string;
  userType: string;
  role?: string;
}

@Injectable()
export class AuthService {
  constructor(
    private prisma: PrismaService,
    private jwt: JwtService,
    private config: ConfigService,
    private systemConfig: SystemConfigService,
  ) {}

  /** 平台管理员 / 代理统一登录（按 userType 签发对应 JWT） */
  async staffLogin(username: string, password: string) {
    const user = await this.prisma.user.findUnique({
      where: { username },
      select: { userType: true },
    });
    if (!user || (user.userType !== 'ADMIN' && user.userType !== 'AGENT')) {
      throw new UnauthorizedException('Invalid credentials');
    }
    const portal = user.userType === 'ADMIN' ? 'admin' : 'agent';
    return this.login(username, password, portal);
  }

  async login(username: string, password: string, portal: 'player' | 'admin' | 'agent') {
    const user = await this.prisma.user.findUnique({
      where: { username },
      include: { auth: true, adminRole: { include: { role: true } } },
    });

    if (!user || !user.auth) {
      throw new UnauthorizedException('Invalid credentials');
    }

    const expectedType = portal === 'admin' ? 'ADMIN' : portal === 'agent' ? 'AGENT' : 'PLAYER';
    if (user.userType !== expectedType) {
      throw new UnauthorizedException('Invalid credentials');
    }

    if (user.status === 'DISABLED') {
      throw new ForbiddenException('Account disabled');
    }

    if (portal === 'agent' && user.status === 'SUSPENDED') {
      throw new ForbiddenException('Agent account suspended');
    }

    if (portal === 'player' && user.parentId) {
      const agentSettings = await this.systemConfig.getAgentSuspendSettings();
      if (agentSettings.suspendBlockPlayerLogin) {
        const parentAgent = await this.prisma.user.findUnique({
          where: { id: user.parentId },
          select: { userType: true, status: true },
        });
        if (parentAgent?.userType === 'AGENT' && parentAgent.status !== 'ACTIVE') {
          throw new ForbiddenException('上级代理已停用，暂无法登录');
        }
      }
    }

    if (user.auth.lockedUntil && user.auth.lockedUntil > new Date()) {
      throw new ForbiddenException('Account locked, try again later');
    }

    const valid = await bcrypt.compare(password, user.auth.passwordHash);
    if (!valid) {
      const failCount = user.auth.loginFailCount + 1;
      const lockedUntil =
        failCount >= MAX_LOGIN_FAILS ? new Date(Date.now() + LOCK_DURATION_MS) : null;
      await this.prisma.userAuth.update({
        where: { userId: user.id },
        data: { loginFailCount: failCount, lockedUntil },
      });
      throw new UnauthorizedException('Invalid credentials');
    }

    await this.prisma.userAuth.update({
      where: { userId: user.id },
      data: { loginFailCount: 0, lockedUntil: null, lastLoginAt: new Date() },
    });

    const expiresIn =
      portal === 'admin'
        ? this.config.get('JWT_ADMIN_EXPIRES', '2h')
        : portal === 'agent'
          ? this.config.get('JWT_AGENT_EXPIRES', '8h')
          : this.config.get('JWT_PLAYER_EXPIRES', '24h');

    const payload: JwtPayload = {
      sub: user.id.toString(),
      username: user.username,
      userType: user.userType,
      role: user.adminRole?.role?.code,
    };

    const token = this.jwt.sign(payload, { expiresIn });

    return {
      token,
      user: {
        id: user.id.toString(),
        username: user.username,
        userType: user.userType,
        locale: user.locale,
        role: user.adminRole?.role?.code,
        agentLevel: user.userType === 'AGENT' ? user.agentLevel : null,
      },
    };
  }

  async changePassword(userId: bigint, oldPassword: string, newPassword: string) {
    const auth = await this.prisma.userAuth.findUnique({ where: { userId } });
    if (!auth) throw new UnauthorizedException('User not found');

    const settings = await this.systemConfig.getPlayerAccountSettings();
    if (!settings.allowPasswordChange) {
      throw new ForbiddenException('当前平台未开放玩家自行修改密码');
    }

    const valid = await bcrypt.compare(oldPassword, auth.passwordHash);
    if (!valid) throw new UnauthorizedException('Invalid old password');

    const hash = await bcrypt.hash(newPassword, 10);
    await this.prisma.userAuth.update({
      where: { userId },
      data: { passwordHash: hash },
    });
    await this.prisma.userPreference.updateMany({
      where: { userId },
      data: { managedPassword: null },
    });
    return { success: true };
  }

  async hashPassword(password: string): Promise<string> {
    return bcrypt.hash(password, 10);
  }
}
