import bcrypt from 'bcryptjs';
import { AppDataSource, User, UserToken, SystemConfig } from '../models/index.js';
import { AppError } from '../middleware/error.js';
import {
  generateAccessToken,
  generateRefreshToken,
  verifyRefreshToken,
  type JwtPayload,
} from '../middleware/auth.js';
import { ERROR_CODES, HTTP_STATUS } from '@media-manager/shared';
import type { RegisterRequest, UpdateProfileRequest, User as UserType } from '@media-manager/shared';

export class AuthService {
  private userRepository = AppDataSource.getRepository(User);
  private tokenRepository = AppDataSource.getRepository(UserToken);
  private configRepository = AppDataSource.getRepository(SystemConfig);

  /**
   * 用户登录
   */
  async login(
    username: string,
    password: string,
    ip: string,
    deviceInfo: string,
    rememberMe?: boolean
  ) {
    // 查找用户
    const user = await this.userRepository.findOne({
      where: [{ username }, { email: username }],
    });

    if (!user) {
      throw new AppError('用户名或密码错误', HTTP_STATUS.UNAUTHORIZED, ERROR_CODES.INVALID_CREDENTIALS);
    }

    // 检查用户状态
    if (user.status !== 'active') {
      throw new AppError('账号已被禁用', HTTP_STATUS.FORBIDDEN, ERROR_CODES.FORBIDDEN);
    }

    // 验证密码
    const isPasswordValid = await bcrypt.compare(password, user.passwordHash);
    if (!isPasswordValid) {
      throw new AppError('用户名或密码错误', HTTP_STATUS.UNAUTHORIZED, ERROR_CODES.INVALID_CREDENTIALS);
    }

    // 生成 Token
    const payload: JwtPayload = {
      userId: user.id,
      username: user.username,
      role: user.role,
    };

    const accessToken = generateAccessToken(payload);
    const refreshToken = generateRefreshToken(payload);

    // 保存刷新令牌
    const expiresAt = new Date();
    expiresAt.setDate(expiresAt.getDate() + (rememberMe ? 30 : 7));

    const tokenEntity = this.tokenRepository.create({
      userId: user.id,
      refreshToken,
      deviceInfo,
      ipAddress: ip,
      expiresAt,
    });
    await this.tokenRepository.save(tokenEntity);

    // 更新最后登录信息
    await this.userRepository.update(user.id, {
      lastLoginAt: new Date(),
      lastLoginIp: ip,
    });

    return {
      accessToken,
      refreshToken,
      expiresIn: 900, // 15 minutes
      user: this.formatUser(user),
    };
  }

  /**
   * 用户注册
   */
  async register(data: RegisterRequest) {
    // 检查是否开放注册
    // 优先使用环境变量，如果没有设置则从数据库读取
    let isRegistrationAllowed = false;
    
    const envValue = process.env.ALLOW_REGISTRATION;
    if (envValue !== undefined) {
      // 环境变量已设置，使用环境变量的值
      isRegistrationAllowed = envValue === 'true';
    } else {
      // 环境变量未设置，从数据库读取
      const dbConfig = await this.configRepository.findOne({
        where: { configKey: 'allow_registration' },
      });
      isRegistrationAllowed = dbConfig?.configValue === 'true';
    }

    if (!isRegistrationAllowed) {
      throw new AppError('注册功能已关闭', HTTP_STATUS.FORBIDDEN, ERROR_CODES.REGISTRATION_DISABLED);
    }

    // 检查用户名是否已存在
    const existingUser = await this.userRepository.findOne({
      where: [{ username: data.username }, { email: data.email }],
    });

    if (existingUser) {
      throw new AppError('用户名或邮箱已存在', HTTP_STATUS.CONFLICT, ERROR_CODES.USER_EXISTS);
    }

    // 获取默认角色
    const defaultRole = await this.configRepository.findOne({
      where: { configKey: 'default_user_role' },
    });

    // 创建用户
    const passwordHash = await bcrypt.hash(data.password, 10);
    const user = this.userRepository.create({
      username: data.username,
      email: data.email || null,
      passwordHash,
      nickname: data.nickname || data.username,
      role: (defaultRole?.configValue as 'admin' | 'editor' | 'operator') || 'operator',
      status: 'active',
    });

    await this.userRepository.save(user);

    return {
      message: '注册成功',
      user: this.formatUser(user),
    };
  }

  /**
   * 刷新访问令牌
   */
  async refreshToken(refreshToken: string) {
    // 验证刷新令牌
    const payload = verifyRefreshToken(refreshToken);

    // 检查令牌是否在数据库中
    const tokenEntity = await this.tokenRepository.findOne({
      where: { refreshToken, userId: payload.userId },
    });

    if (!tokenEntity) {
      throw new AppError('无效的刷新令牌', HTTP_STATUS.UNAUTHORIZED, ERROR_CODES.TOKEN_INVALID);
    }

    // 检查是否过期
    if (new Date() > tokenEntity.expiresAt) {
      await this.tokenRepository.delete(tokenEntity.id);
      throw new AppError('刷新令牌已过期', HTTP_STATUS.UNAUTHORIZED, ERROR_CODES.TOKEN_EXPIRED);
    }

    // 获取最新用户信息
    const user = await this.userRepository.findOne({
      where: { id: payload.userId },
    });

    if (!user || user.status !== 'active') {
      throw new AppError('用户不存在或已被禁用', HTTP_STATUS.UNAUTHORIZED, ERROR_CODES.UNAUTHORIZED);
    }

    // 生成新的访问令牌
    const newPayload: JwtPayload = {
      userId: user.id,
      username: user.username,
      role: user.role,
    };

    const accessToken = generateAccessToken(newPayload);

    return {
      accessToken,
      expiresIn: 900,
    };
  }

  /**
   * 退出登录
   */
  async logout(refreshToken: string) {
    await this.tokenRepository.delete({ refreshToken });
  }

  /**
   * 获取当前用户信息
   */
  async getCurrentUser(userId: number): Promise<UserType> {
    const user = await this.userRepository.findOne({
      where: { id: userId },
    });

    if (!user) {
      throw new AppError('用户不存在', HTTP_STATUS.NOT_FOUND, ERROR_CODES.USER_NOT_FOUND);
    }

    return this.formatUser(user);
  }

  /**
   * 修改密码
   */
  async changePassword(userId: number, oldPassword: string, newPassword: string) {
    const user = await this.userRepository.findOne({
      where: { id: userId },
    });

    if (!user) {
      throw new AppError('用户不存在', HTTP_STATUS.NOT_FOUND, ERROR_CODES.USER_NOT_FOUND);
    }

    // 验证旧密码
    const isPasswordValid = await bcrypt.compare(oldPassword, user.passwordHash);
    if (!isPasswordValid) {
      throw new AppError('旧密码错误', HTTP_STATUS.BAD_REQUEST, ERROR_CODES.INVALID_CREDENTIALS);
    }

    // 更新密码
    const passwordHash = await bcrypt.hash(newPassword, 10);
    await this.userRepository.update(userId, { passwordHash });

    // 清除所有刷新令牌（强制重新登录）
    await this.tokenRepository.delete({ userId });
  }

  /**
   * 更新个人资料
   */
  async updateProfile(userId: number, data: UpdateProfileRequest): Promise<UserType> {
    const user = await this.userRepository.findOne({
      where: { id: userId },
    });

    if (!user) {
      throw new AppError('用户不存在', HTTP_STATUS.NOT_FOUND, ERROR_CODES.USER_NOT_FOUND);
    }

    // 如果更新邮箱，检查是否已存在
    if (data.email && data.email !== user.email) {
      const existingUser = await this.userRepository.findOne({
        where: { email: data.email },
      });
      if (existingUser) {
        throw new AppError('邮箱已被使用', HTTP_STATUS.CONFLICT, ERROR_CODES.USER_EXISTS);
      }
    }

    // 更新资料
    await this.userRepository.update(userId, {
      nickname: data.nickname ?? user.nickname,
      email: data.email ?? user.email,
      avatarUrl: data.avatarUrl ?? user.avatarUrl,
    });

    const updatedUser = await this.userRepository.findOne({
      where: { id: userId },
    });

    return this.formatUser(updatedUser!);
  }

  /**
   * 格式化用户数据
   */
  private formatUser(user: User): UserType {
    return {
      id: user.id,
      username: user.username,
      email: user.email,
      nickname: user.nickname,
      avatarUrl: user.avatarUrl,
      role: user.role,
      status: user.status,
      lastLoginAt: user.lastLoginAt?.toISOString() || null,
      lastLoginIp: user.lastLoginIp,
      createdAt: user.createdAt.toISOString(),
      updatedAt: user.updatedAt.toISOString(),
    };
  }
}
