/* eslint-disable no-console, @typescript-eslint/no-explicit-any, @typescript-eslint/no-non-null-assertion */

import { createClient, RedisClientType } from 'redis';

import { AdminConfig } from './admin.types';
import { Favorite, IStorage, PlayRecord, SkipConfig } from './types';

// 搜索历史最大条数
const SEARCH_HISTORY_LIMIT = 20;

// 数据类型转换辅助函数
function ensureString(value: any): string {
  return String(value);
}

function ensureStringArray(value: any[]): string[] {
  return value.map((item) => String(item));
}

// 内存锁：用于防止同一用户的并发播放记录操作（迁移、清理等）
const playRecordLocks = new Map<string, Promise<void>>();

// 连接配置接口
export interface RedisConnectionConfig {
  url: string;
  clientName: string; // 用于日志显示，如 "Redis" 或 "Pika"
}

// 添加Redis操作重试包装器
function createRetryWrapper(clientName: string, getClient: () => RedisClientType) {
  return async function withRetry<T>(
    operation: () => Promise<T>,
    maxRetries = 3
  ): Promise<T> {
    for (let i = 0; i < maxRetries; i++) {
      try {
        return await operation();
      } catch (err: any) {
        const isLastAttempt = i === maxRetries - 1;
        const isConnectionError =
          err.message?.includes('Connection') ||
          err.message?.includes('ECONNREFUSED') ||
          err.message?.includes('ENOTFOUND') ||
          err.code === 'ECONNRESET' ||
          err.code === 'EPIPE';

        if (isConnectionError && !isLastAttempt) {
          console.log(
            `${clientName} operation failed, retrying... (${i + 1}/${maxRetries})`
          );
          console.error('Error:', err.message);

          // 等待一段时间后重试
          await new Promise((resolve) => setTimeout(resolve, 1000 * (i + 1)));

          // 尝试重新连接
          try {
            const client = getClient();
            if (!client.isOpen) {
              await client.connect();
            }
          } catch (reconnectErr) {
            console.error('Failed to reconnect:', reconnectErr);
          }

          continue;
        }

        throw err;
      }
    }

    throw new Error('Max retries exceeded');
  };
}

// 创建客户端的工厂函数
export function createRedisClient(config: RedisConnectionConfig, globalSymbol: symbol): RedisClientType {
  let client: RedisClientType | undefined = (global as any)[globalSymbol];

  if (!client) {
    if (!config.url) {
      throw new Error(`${config.clientName}_URL env variable not set`);
    }

    // 创建客户端配置
    const clientConfig: any = {
      url: config.url,
      socket: {
        // 重连策略：指数退避，最大30秒
        reconnectStrategy: (retries: number) => {
          console.log(`${config.clientName} reconnection attempt ${retries + 1}`);
          if (retries > 10) {
            console.error(`${config.clientName} max reconnection attempts exceeded`);
            return false; // 停止重连
          }
          return Math.min(1000 * Math.pow(2, retries), 30000); // 指数退避，最大30秒
        },
        connectTimeout: 10000, // 10秒连接超时
        // 设置no delay，减少延迟
        noDelay: true,
      },
      // 添加其他配置
      pingInterval: 30000, // 30秒ping一次，保持连接活跃
    };

    client = createClient(clientConfig);

    // 添加错误事件监听
    client.on('error', (err) => {
      console.error(`${config.clientName} client error:`, err);
    });

    client.on('connect', () => {
      console.log(`${config.clientName} connected`);
    });

    client.on('reconnecting', () => {
      console.log(`${config.clientName} reconnecting...`);
    });

    client.on('ready', () => {
      console.log(`${config.clientName} ready`);
    });

    // 初始连接，带重试机制
    const connectWithRetry = async () => {
      try {
        await client!.connect();
        console.log(`${config.clientName} connected successfully`);
      } catch (err) {
        console.error(`${config.clientName} initial connection failed:`, err);
        console.log('Will retry in 5 seconds...');
        setTimeout(connectWithRetry, 5000);
      }
    };

    connectWithRetry();

    (global as any)[globalSymbol] = client;
  }

  return client;
}

// 抽象基类，包含所有通用的Redis操作逻辑
export abstract class BaseRedisStorage implements IStorage {
  protected client: RedisClientType;
  protected withRetry: <T>(operation: () => Promise<T>, maxRetries?: number) => Promise<T>;

  constructor(config: RedisConnectionConfig, globalSymbol: symbol) {
    this.client = createRedisClient(config, globalSymbol);
    this.withRetry = createRetryWrapper(config.clientName, () => this.client);
  }

  // ---------- 播放记录 ----------
  private prHashKey(user: string) {
    return `u:${user}:pr`; // u:username:pr (hash结构)
  }

  // 旧版播放记录key（用于迁移）
  private prOldKey(user: string, key: string) {
    return `u:${user}:pr:${key}`; // u:username:pr:source+id
  }

  async getPlayRecord(
    userName: string,
    key: string
  ): Promise<PlayRecord | null> {
    const val = await this.withRetry(() =>
      this.client.hGet(this.prHashKey(userName), key)
    );
    return val ? (JSON.parse(val) as PlayRecord) : null;
  }

  async setPlayRecord(
    userName: string,
    key: string,
    record: PlayRecord
  ): Promise<void> {
    await this.withRetry(() =>
      this.client.hSet(this.prHashKey(userName), key, JSON.stringify(record))
    );
  }

  async getAllPlayRecords(
    userName: string
  ): Promise<Record<string, PlayRecord>> {
    const hashData = await this.withRetry(() =>
      this.client.hGetAll(this.prHashKey(userName))
    );

    const result: Record<string, PlayRecord> = {};
    for (const [key, value] of Object.entries(hashData)) {
      if (value) {
        result[key] = JSON.parse(value) as PlayRecord;
      }
    }
    return result;
  }

  async deletePlayRecord(userName: string, key: string): Promise<void> {
    await this.withRetry(() => this.client.hDel(this.prHashKey(userName), key));
  }

  // 清理超出限制的旧播放记录
  async cleanupOldPlayRecords(userName: string): Promise<void> {
    // 检查是否已有正在进行的操作
    const existingLock = playRecordLocks.get(userName);
    if (existingLock) {
      console.log(`用户 ${userName} 的播放记录操作正在进行中，跳过清理`);
      await existingLock;
      return;
    }

    // 创建新的操作Promise
    const cleanupPromise = this.doCleanup(userName);
    playRecordLocks.set(userName, cleanupPromise);

    try {
      await cleanupPromise;
    } finally {
      // 操作完成后清除锁
      playRecordLocks.delete(userName);
    }
  }

  // 实际执行清理的方法
  private async doCleanup(userName: string): Promise<void> {
    try {
      // 获取配置的最大播放记录数，默认100
      const maxRecords = parseInt(process.env.MAX_PLAY_RECORDS_PER_USER || '100', 10);
      const threshold = maxRecords + 10; // 超过最大值+10时才触发清理

      // 获取所有播放记录
      const allRecords = await this.getAllPlayRecords(userName);
      const recordCount = Object.keys(allRecords).length;

      // 如果记录数未超过阈值，不需要清理
      if (recordCount <= threshold) {
        return;
      }

      console.log(`用户 ${userName} 的播放记录数 ${recordCount} 超过阈值 ${threshold}，开始清理...`);

      // 将记录转换为数组并按 save_time 排序（从旧到新）
      const sortedRecords = Object.entries(allRecords).sort(
        ([, a], [, b]) => a.save_time - b.save_time
      );

      // 计算需要删除的记录数
      const deleteCount = recordCount - maxRecords;

      // 删除最旧的记录
      const recordsToDelete = sortedRecords.slice(0, deleteCount);
      for (const [key] of recordsToDelete) {
        await this.deletePlayRecord(userName, key);
      }

      console.log(`已删除用户 ${userName} 的 ${deleteCount} 条最旧播放记录`);
    } catch (error) {
      console.error(`清理用户 ${userName} 播放记录失败:`, error);
      // 清理失败不影响主流程，只记录错误
    }
  }

  // 迁移播放记录：从旧的多key结构迁移到新的hash结构
  async migratePlayRecords(userName: string): Promise<void> {
    // 检查是否已有正在进行的迁移
    const existingMigration = playRecordLocks.get(userName);
    if (existingMigration) {
      console.log(`用户 ${userName} 的播放记录正在迁移中，等待完成...`);
      await existingMigration;
      return;
    }

    // 创建新的迁移Promise
    const migrationPromise = this.doMigration(userName);
    playRecordLocks.set(userName, migrationPromise);

    try {
      await migrationPromise;
    } finally {
      // 迁移完成后清除锁
      playRecordLocks.delete(userName);
    }
  }

  // 实际执行迁移的方法
  private async doMigration(userName: string): Promise<void> {
    console.log(`开始迁移用户 ${userName} 的播放记录...`);

    // 1. 检查是否已经迁移过
    const userInfo = await this.getUserInfoV2(userName);
    if (userInfo?.playrecord_migrated) {
      console.log(`用户 ${userName} 的播放记录已经迁移过，跳过`);
      return;
    }

    // 2. 获取旧结构的所有播放记录key
    const pattern = `u:${userName}:pr:*`;
    const oldKeys: string[] = await this.withRetry(() => this.client.keys(pattern));

    if (oldKeys.length === 0) {
      console.log(`用户 ${userName} 没有旧的播放记录，标记为已迁移`);
      // 即使没有数据也标记为已迁移
      await this.withRetry(() =>
        this.client.hSet(this.userInfoKey(userName), 'playrecord_migrated', 'true')
      );
      // 清除用户信息缓存
      const { userInfoCache } = await import('./user-cache');
      userInfoCache?.delete(userName);
      return;
    }

    console.log(`找到 ${oldKeys.length} 条旧播放记录，开始迁移...`);

    // 3. 批量获取旧数据
    const oldValues = await this.withRetry(() => this.client.mGet(oldKeys));

    // 4. 转换为hash格式
    const hashData: Record<string, string> = {};
    oldKeys.forEach((fullKey: string, idx: number) => {
      const raw = oldValues[idx];
      if (raw) {
        // 提取 source+id 部分作为hash的field
        const keyPart = ensureString(fullKey.replace(`u:${userName}:pr:`, ''));
        hashData[keyPart] = raw;
      }
    });

    // 5. 写入新的hash结构
    if (Object.keys(hashData).length > 0) {
      await this.withRetry(() =>
        this.client.hSet(this.prHashKey(userName), hashData)
      );
      console.log(`成功迁移 ${Object.keys(hashData).length} 条播放记录到hash结构`);
    }

    // 6. 删除旧的key
    await this.withRetry(() => this.client.del(oldKeys));
    console.log(`删除了 ${oldKeys.length} 个旧的播放记录key`);

    // 7. 标记迁移完成
    await this.withRetry(() =>
      this.client.hSet(this.userInfoKey(userName), 'playrecord_migrated', 'true')
    );

    // 8. 清除用户信息缓存，确保下次获取时能读取到最新的迁移标识
    const { userInfoCache } = await import('./user-cache');
    userInfoCache?.delete(userName);

    console.log(`用户 ${userName} 的播放记录迁移完成`);
  }

  // ---------- 收藏 ----------
  private favHashKey(user: string) {
    return `u:${user}:fav`; // u:username:fav (hash结构)
  }

  // 旧版收藏key（用于迁移）
  private favOldKey(user: string, key: string) {
    return `u:${user}:fav:${key}`;
  }

  async getFavorite(userName: string, key: string): Promise<Favorite | null> {
    const val = await this.withRetry(() =>
      this.client.hGet(this.favHashKey(userName), key)
    );
    return val ? (JSON.parse(val) as Favorite) : null;
  }

  async setFavorite(
    userName: string,
    key: string,
    favorite: Favorite
  ): Promise<void> {
    await this.withRetry(() =>
      this.client.hSet(this.favHashKey(userName), key, JSON.stringify(favorite))
    );
  }

  async getAllFavorites(userName: string): Promise<Record<string, Favorite>> {
    const hashData = await this.withRetry(() =>
      this.client.hGetAll(this.favHashKey(userName))
    );

    const result: Record<string, Favorite> = {};
    for (const [key, value] of Object.entries(hashData)) {
      if (value) {
        result[key] = JSON.parse(value) as Favorite;
      }
    }
    return result;
  }

  async deleteFavorite(userName: string, key: string): Promise<void> {
    await this.withRetry(() => this.client.hDel(this.favHashKey(userName), key));
  }

  // 迁移收藏：从旧的多key结构迁移到新的hash结构
  async migrateFavorites(userName: string): Promise<void> {
    // 检查是否已有正在进行的迁移
    const existingMigration = playRecordLocks.get(userName);
    if (existingMigration) {
      console.log(`用户 ${userName} 的收藏正在迁移中，等待完成...`);
      await existingMigration;
      return;
    }

    // 创建新的迁移Promise
    const migrationPromise = this.doFavoriteMigration(userName);
    playRecordLocks.set(userName, migrationPromise);

    try {
      await migrationPromise;
    } finally {
      // 迁移完成后清除锁
      playRecordLocks.delete(userName);
    }
  }

  // 实际执行收藏迁移的方法
  private async doFavoriteMigration(userName: string): Promise<void> {
    console.log(`开始迁移用户 ${userName} 的收藏...`);

    // 1. 检查是否已经迁移过
    const userInfo = await this.getUserInfoV2(userName);
    if (userInfo?.favorite_migrated) {
      console.log(`用户 ${userName} 的收藏已经迁移过，跳过`);
      return;
    }

    // 2. 获取旧结构的所有收藏key
    const pattern = `u:${userName}:fav:*`;
    const oldKeys: string[] = await this.withRetry(() => this.client.keys(pattern));

    if (oldKeys.length === 0) {
      console.log(`用户 ${userName} 没有旧的收藏，标记为已迁移`);
      // 即使没有数据也标记为已迁移
      await this.withRetry(() =>
        this.client.hSet(this.userInfoKey(userName), 'favorite_migrated', 'true')
      );
      // 清除用户信息缓存
      const { userInfoCache } = await import('./user-cache');
      userInfoCache?.delete(userName);
      return;
    }

    console.log(`找到 ${oldKeys.length} 条旧收藏，开始迁移...`);

    // 3. 批量获取旧数据
    const oldValues = await this.withRetry(() => this.client.mGet(oldKeys));

    // 4. 转换为hash格式
    const hashData: Record<string, string> = {};
    oldKeys.forEach((fullKey: string, idx: number) => {
      const raw = oldValues[idx];
      if (raw) {
        // 提取 source+id 部分作为hash的field
        const keyPart = ensureString(fullKey.replace(`u:${userName}:fav:`, ''));
        hashData[keyPart] = raw;
      }
    });

    // 5. 写入新的hash结构
    if (Object.keys(hashData).length > 0) {
      await this.withRetry(() =>
        this.client.hSet(this.favHashKey(userName), hashData)
      );
      console.log(`成功迁移 ${Object.keys(hashData).length} 条收藏到hash结构`);
    }

    // 6. 删除旧的key
    await this.withRetry(() => this.client.del(oldKeys));
    console.log(`删除了 ${oldKeys.length} 个旧的收藏key`);

    // 7. 标记迁移完成
    await this.withRetry(() =>
      this.client.hSet(this.userInfoKey(userName), 'favorite_migrated', 'true')
    );

    // 8. 清除用户信息缓存，确保下次获取时能读取到最新的迁移标识
    const { userInfoCache } = await import('./user-cache');
    userInfoCache?.delete(userName);

    console.log(`用户 ${userName} 的收藏迁移完成`);
  }

  // ---------- 用户注册 / 登录（旧版本，保持兼容） ----------
  private userPwdKey(user: string) {
    return `u:${user}:pwd`;
  }

  async verifyUser(userName: string, password: string): Promise<boolean> {
    const stored = await this.withRetry(() =>
      this.client.get(this.userPwdKey(userName))
    );
    if (stored === null) return false;
    // 确保比较时都是字符串类型
    return ensureString(stored) === password;
  }

  // 检查用户是否存在
  async checkUserExist(userName: string): Promise<boolean> {
    // 使用 EXISTS 判断 key 是否存在
    const exists = await this.withRetry(() =>
      this.client.exists(this.userPwdKey(userName))
    );
    return exists === 1;
  }

  // 修改用户密码
  async changePassword(userName: string, newPassword: string): Promise<void> {
    // 简单存储明文密码，生产环境应加密
    await this.withRetry(() =>
      this.client.set(this.userPwdKey(userName), newPassword)
    );
  }

  // 删除用户及其所有数据
  async deleteUser(userName: string): Promise<void> {
    // 删除用户密码
    await this.withRetry(() => this.client.del(this.userPwdKey(userName)));

    // 删除搜索历史
    await this.withRetry(() => this.client.del(this.shKey(userName)));

    // 删除播放记录（新hash结构）
    await this.withRetry(() => this.client.del(this.prHashKey(userName)));

    // 删除旧的播放记录key（如果有）
    const playRecordPattern = `u:${userName}:pr:*`;
    const playRecordKeys = await this.withRetry(() =>
      this.client.keys(playRecordPattern)
    );
    if (playRecordKeys.length > 0) {
      await this.withRetry(() => this.client.del(playRecordKeys));
    }

    // 删除收藏夹（新hash结构）
    await this.withRetry(() => this.client.del(this.favHashKey(userName)));

    // 删除旧的收藏key（如果有）
    const favoritePattern = `u:${userName}:fav:*`;
    const favoriteKeys = await this.withRetry(() =>
      this.client.keys(favoritePattern)
    );
    if (favoriteKeys.length > 0) {
      await this.withRetry(() => this.client.del(favoriteKeys));
    }

    // 删除跳过片头片尾配置（新hash结构）
    await this.withRetry(() => this.client.del(this.skipHashKey(userName)));

    // 删除旧的跳过配置key（如果有）
    const skipConfigPattern = `u:${userName}:skip:*`;
    const skipConfigKeys = await this.withRetry(() =>
      this.client.keys(skipConfigPattern)
    );
    if (skipConfigKeys.length > 0) {
      await this.withRetry(() => this.client.del(skipConfigKeys));
    }
  }

  // ---------- 新版用户存储（使用Hash和Sorted Set） ----------
  private userInfoKey(userName: string) {
    return `user:${userName}:info`;
  }

  private userListKey() {
    return 'user:list';
  }

  private oidcSubKey(oidcSub: string) {
    return `oidc:sub:${oidcSub}`;
  }

  // SHA256加密密码
  private async hashPassword(password: string): Promise<string> {
    const encoder = new TextEncoder();
    const data = encoder.encode(password);
    const hashBuffer = await crypto.subtle.digest('SHA-256', data);
    const hashArray = Array.from(new Uint8Array(hashBuffer));
    return hashArray.map(b => b.toString(16).padStart(2, '0')).join('');
  }

  // 创建新用户（新版本）
  async createUserV2(
    userName: string,
    password: string,
    role: 'owner' | 'admin' | 'user' = 'user',
    tags?: string[],
    oidcSub?: string,
    enabledApis?: string[]
  ): Promise<void> {
    const hashedPassword = await this.hashPassword(password);
    const createdAt = Date.now();

    // 存储用户信息到Hash
    const userInfo: Record<string, string> = {
      role,
      banned: 'false',
      password: hashedPassword,
      created_at: createdAt.toString(),
    };

    if (tags && tags.length > 0) {
      userInfo.tags = JSON.stringify(tags);
    }

    if (enabledApis && enabledApis.length > 0) {
      userInfo.enabledApis = JSON.stringify(enabledApis);
    }

    if (oidcSub) {
      userInfo.oidcSub = oidcSub;
      // 创建OIDC映射
      await this.withRetry(() => this.client.set(this.oidcSubKey(oidcSub), userName));
    }

    await this.withRetry(() => this.client.hSet(this.userInfoKey(userName), userInfo));

    // 添加到用户列表（Sorted Set，按注册时间排序）
    await this.withRetry(() => this.client.zAdd(this.userListKey(), {
      score: createdAt,
      value: userName,
    }));

    // 如果创建的是站长用户，清除站长存在状态缓存
    if (userName === process.env.USERNAME) {
      const { ownerExistenceCache } = await import('./user-cache');
      ownerExistenceCache.delete(userName);
    }
  }

  // 验证用户密码（新版本）
  async verifyUserV2(userName: string, password: string): Promise<boolean> {
    const userInfo = await this.withRetry(() =>
      this.client.hGetAll(this.userInfoKey(userName))
    );

    if (!userInfo || !userInfo.password) {
      return false;
    }

    const hashedPassword = await this.hashPassword(password);
    return userInfo.password === hashedPassword;
  }

  // 获取用户信息（新版本）
  async getUserInfoV2(userName: string): Promise<{
    role: 'owner' | 'admin' | 'user';
    banned: boolean;
    tags?: string[];
    oidcSub?: string;
    enabledApis?: string[];
    created_at: number;
    playrecord_migrated?: boolean;
    favorite_migrated?: boolean;
    skip_migrated?: boolean;
  } | null> {
    const userInfo = await this.withRetry(() =>
      this.client.hGetAll(this.userInfoKey(userName))
    );

    if (!userInfo || Object.keys(userInfo).length === 0) {
      return null;
    }

    return {
      role: (userInfo.role as 'owner' | 'admin' | 'user') || 'user',
      banned: userInfo.banned === 'true',
      tags: userInfo.tags ? JSON.parse(userInfo.tags) : undefined,
      oidcSub: userInfo.oidcSub,
      enabledApis: userInfo.enabledApis ? JSON.parse(userInfo.enabledApis) : undefined,
      created_at: parseInt(userInfo.created_at || '0', 10),
      playrecord_migrated: userInfo.playrecord_migrated === 'true',
      favorite_migrated: userInfo.favorite_migrated === 'true',
      skip_migrated: userInfo.skip_migrated === 'true',
    };
  }

  // 更新用户信息（新版本）
  async updateUserInfoV2(
    userName: string,
    updates: {
      role?: 'owner' | 'admin' | 'user';
      banned?: boolean;
      tags?: string[];
      oidcSub?: string;
      enabledApis?: string[];
    }
  ): Promise<void> {
    const userInfo: Record<string, string> = {};

    if (updates.role !== undefined) {
      userInfo.role = updates.role;
    }

    if (updates.banned !== undefined) {
      userInfo.banned = updates.banned ? 'true' : 'false';
    }

    if (updates.tags !== undefined) {
      if (updates.tags.length > 0) {
        userInfo.tags = JSON.stringify(updates.tags);
      } else {
        // 删除tags字段
        await this.withRetry(() => this.client.hDel(this.userInfoKey(userName), 'tags'));
      }
    }

    if (updates.enabledApis !== undefined) {
      if (updates.enabledApis.length > 0) {
        userInfo.enabledApis = JSON.stringify(updates.enabledApis);
      } else {
        // 删除enabledApis字段
        await this.withRetry(() => this.client.hDel(this.userInfoKey(userName), 'enabledApis'));
      }
    }

    if (updates.oidcSub !== undefined) {
      const oldInfo = await this.getUserInfoV2(userName);
      if (oldInfo?.oidcSub && oldInfo.oidcSub !== updates.oidcSub) {
        // 删除旧的OIDC映射
        await this.withRetry(() => this.client.del(this.oidcSubKey(oldInfo.oidcSub!)));
      }
      userInfo.oidcSub = updates.oidcSub;
      // 创建新的OIDC映射
      await this.withRetry(() => this.client.set(this.oidcSubKey(updates.oidcSub!), userName));
    }

    if (Object.keys(userInfo).length > 0) {
      await this.withRetry(() => this.client.hSet(this.userInfoKey(userName), userInfo));
    }
  }

  // 修改用户密码（新版本）
  async changePasswordV2(userName: string, newPassword: string): Promise<void> {
    const hashedPassword = await this.hashPassword(newPassword);
    await this.withRetry(() =>
      this.client.hSet(this.userInfoKey(userName), 'password', hashedPassword)
    );
  }

  // 检查用户是否存在（新版本）
  async checkUserExistV2(userName: string): Promise<boolean> {
    const exists = await this.withRetry(() =>
      this.client.exists(this.userInfoKey(userName))
    );
    return exists === 1;
  }

  // 通过OIDC Sub查找用户名
  async getUserByOidcSub(oidcSub: string): Promise<string | null> {
    const userName = await this.withRetry(() =>
      this.client.get(this.oidcSubKey(oidcSub))
    );
    return userName ? ensureString(userName) : null;
  }

  // 获取用户列表（分页，新版本）
  async getUserListV2(
    offset: number = 0,
    limit: number = 20,
    ownerUsername?: string
  ): Promise<{
    users: Array<{
      username: string;
      role: 'owner' | 'admin' | 'user';
      banned: boolean;
      tags?: string[];
      oidcSub?: string;
      enabledApis?: string[];
      created_at: number;
    }>;
    total: number;
  }> {
    // 获取总数
    let total = await this.withRetry(() => this.client.zCard(this.userListKey()));

    // 检查站长是否在数据库中（使用缓存）
    let ownerInfo = null;
    let ownerInDatabase = false;
    if (ownerUsername) {
      // 先检查缓存
      const { ownerExistenceCache } = await import('./user-cache');
      const cachedExists = ownerExistenceCache.get(ownerUsername);

      if (cachedExists !== null) {
        // 使用缓存的结果
        ownerInDatabase = cachedExists;
        if (ownerInDatabase) {
          // 如果站长在数据库中，获取详细信息
          ownerInfo = await this.getUserInfoV2(ownerUsername);
        }
      } else {
        // 缓存未命中，查询数据库
        ownerInfo = await this.getUserInfoV2(ownerUsername);
        ownerInDatabase = !!ownerInfo;
        // 更新缓存
        ownerExistenceCache.set(ownerUsername, ownerInDatabase);
      }

      // 如果站长不在数据库中，总数+1（无论在哪一页都要加）
      if (!ownerInDatabase) {
        total += 1;
      }
    }

    // 如果站长不在数据库中且在第一页，需要调整获取的用户数量和偏移量
    let actualOffset = offset;
    let actualLimit = limit;

    if (ownerUsername && !ownerInDatabase) {
      if (offset === 0) {
        // 第一页：只获取 limit-1 个用户，为站长留出位置
        actualLimit = limit - 1;
      } else {
        // 其他页：偏移量需要减1，因为站长占据了第一页的一个位置
        actualOffset = offset - 1;
      }
    }

    // 获取用户列表（按注册时间升序）
    const usernames = await this.withRetry(() =>
      this.client.zRange(this.userListKey(), actualOffset, actualOffset + actualLimit - 1)
    );

    const users = [];

    // 如果有站长且在第一页，确保站长始终在第一位
    if (ownerUsername && offset === 0) {
      // 即使站长不在数据库中，也要添加站长（站长使用环境变量认证）
      users.push({
        username: ownerUsername,
        role: 'owner' as const,
        banned: ownerInfo?.banned || false,
        tags: ownerInfo?.tags,
        oidcSub: ownerInfo?.oidcSub,
        enabledApis: ownerInfo?.enabledApis,
        created_at: ownerInfo?.created_at || 0,
      });
    }

    // 获取其他用户信息
    for (const username of usernames) {
      const usernameStr = ensureString(username);
      // 跳过站长（已经添加）
      if (ownerUsername && usernameStr === ownerUsername) {
        continue;
      }

      const userInfo = await this.getUserInfoV2(usernameStr);
      if (userInfo) {
        users.push({
          username: usernameStr,
          role: userInfo.role,
          banned: userInfo.banned,
          tags: userInfo.tags,
          oidcSub: userInfo.oidcSub,
          enabledApis: userInfo.enabledApis,
          created_at: userInfo.created_at,
        });
      }
    }

    return { users, total };
  }

  // 删除用户（新版本）
  async deleteUserV2(userName: string): Promise<void> {
    // 获取用户信息
    const userInfo = await this.getUserInfoV2(userName);

    // 删除OIDC映射
    if (userInfo?.oidcSub) {
      await this.withRetry(() => this.client.del(this.oidcSubKey(userInfo.oidcSub!)));
    }

    // 删除用户信息Hash
    await this.withRetry(() => this.client.del(this.userInfoKey(userName)));

    // 从用���列表中移除
    await this.withRetry(() => this.client.zRem(this.userListKey(), userName));

    // 删除用户的其他数据（播放记录、收藏等）
    await this.deleteUser(userName);
  }

  // ---------- 搜索历史 ----------
  private shKey(user: string) {
    return `u:${user}:sh`; // u:username:sh
  }

  async getSearchHistory(userName: string): Promise<string[]> {
    const result = await this.withRetry(() =>
      this.client.lRange(this.shKey(userName), 0, -1)
    );
    // 确保返回的都是字符串类型
    return ensureStringArray(result as any[]);
  }

  async addSearchHistory(userName: string, keyword: string): Promise<void> {
    const key = this.shKey(userName);
    // 先去重
    await this.withRetry(() => this.client.lRem(key, 0, ensureString(keyword)));
    // 插入到最前
    await this.withRetry(() => this.client.lPush(key, ensureString(keyword)));
    // 限制最大长度
    await this.withRetry(() => this.client.lTrim(key, 0, SEARCH_HISTORY_LIMIT - 1));
  }

  async deleteSearchHistory(userName: string, keyword?: string): Promise<void> {
    const key = this.shKey(userName);
    if (keyword) {
      await this.withRetry(() => this.client.lRem(key, 0, ensureString(keyword)));
    } else {
      await this.withRetry(() => this.client.del(key));
    }
  }

  // ---------- 获取全部用户 ----------
  async getAllUsers(): Promise<string[]> {
    // 从新版用户列表获取
    const userListKey = this.userListKey();
    const users = await this.withRetry(() =>
      this.client.zRange(userListKey, 0, -1)
    );
    const userList = users.map(u => ensureString(u));

    // 确保站长在列表中（站长可能不在数据库中，使用环境变量认证）
    const ownerUsername = process.env.USERNAME;
    if (ownerUsername && !userList.includes(ownerUsername)) {
      userList.unshift(ownerUsername);
    }

    return userList;
  }

  // ---------- 管理员配置 ----------
  private adminConfigKey() {
    return 'admin:config';
  }

  async getAdminConfig(): Promise<AdminConfig | null> {
    const val = await this.withRetry(() => this.client.get(this.adminConfigKey()));
    return val ? (JSON.parse(val) as AdminConfig) : null;
  }

  async setAdminConfig(config: AdminConfig): Promise<void> {
    await this.withRetry(() =>
      this.client.set(this.adminConfigKey(), JSON.stringify(config))
    );
  }

  // ---------- 跳过片头片尾配置 ----------
  private skipHashKey(user: string) {
    return `u:${user}:skip`; // u:username:skip (hash结构)
  }

  private danmakuFilterConfigKey(user: string) {
    return `u:${user}:danmaku_filter`;
  }

  async getSkipConfig(
    userName: string,
    source: string,
    id: string
  ): Promise<SkipConfig | null> {
    const key = `${source}+${id}`;
    const val = await this.withRetry(() =>
      this.client.hGet(this.skipHashKey(userName), key)
    );
    return val ? (JSON.parse(val) as SkipConfig) : null;
  }

  async setSkipConfig(
    userName: string,
    source: string,
    id: string,
    config: SkipConfig
  ): Promise<void> {
    const key = `${source}+${id}`;
    await this.withRetry(() =>
      this.client.hSet(this.skipHashKey(userName), key, JSON.stringify(config))
    );
  }

  async deleteSkipConfig(
    userName: string,
    source: string,
    id: string
  ): Promise<void> {
    const key = `${source}+${id}`;
    await this.withRetry(() =>
      this.client.hDel(this.skipHashKey(userName), key)
    );
  }

  async getAllSkipConfigs(
    userName: string
  ): Promise<{ [key: string]: SkipConfig }> {
    const hashData = await this.withRetry(() =>
      this.client.hGetAll(this.skipHashKey(userName))
    );

    const result: Record<string, SkipConfig> = {};
    for (const [key, value] of Object.entries(hashData)) {
      if (value) {
        result[key] = JSON.parse(value) as SkipConfig;
      }
    }
    return result;
  }

  // 迁移跳过配置：从旧的多key结构迁移到新的hash结构
  async migrateSkipConfigs(userName: string): Promise<void> {
    const existingMigration = playRecordLocks.get(`${userName}:skip`);
    if (existingMigration) {
      console.log(`用户 ${userName} 的跳过配置正在迁移中，等待完成...`);
      await existingMigration;
      return;
    }

    const migrationPromise = this.doSkipConfigMigration(userName);
    playRecordLocks.set(`${userName}:skip`, migrationPromise);

    try {
      await migrationPromise;
    } finally {
      playRecordLocks.delete(`${userName}:skip`);
    }
  }

  private async doSkipConfigMigration(userName: string): Promise<void> {
    console.log(`开始迁移用户 ${userName} 的跳过配置...`);

    const userInfo = await this.getUserInfoV2(userName);
    if (userInfo?.skip_migrated) {
      console.log(`用户 ${userName} 的跳过配置已经迁移过，跳过`);
      return;
    }

    const pattern = `u:${userName}:skip:*`;
    const oldKeys: string[] = await this.withRetry(() => this.client.keys(pattern));

    if (oldKeys.length === 0) {
      console.log(`用户 ${userName} 没有旧的跳过配置，标记为已迁移`);
      await this.withRetry(() =>
        this.client.hSet(this.userInfoKey(userName), 'skip_migrated', 'true')
      );
      const { userInfoCache } = await import('./user-cache');
      userInfoCache?.delete(userName);
      return;
    }

    const values = await this.withRetry(() => this.client.mGet(oldKeys));

    const hashData: Record<string, string> = {};
    oldKeys.forEach((key, index) => {
      const value = values[index];
      if (value) {
        const match = key.match(/^u:.+?:skip:(.+)$/);
        if (match) {
          const sourceAndId = match[1];
          hashData[sourceAndId] = value as string;
        }
      }
    });

    if (Object.keys(hashData).length > 0) {
      await this.withRetry(() =>
        this.client.hSet(this.skipHashKey(userName), hashData)
      );
      console.log(`成功迁移 ${Object.keys(hashData).length} 条跳过配置到hash结构`);
    }

    await this.withRetry(() => this.client.del(oldKeys));
    console.log(`删除了 ${oldKeys.length} 个旧的跳过配置key`);

    await this.withRetry(() =>
      this.client.hSet(this.userInfoKey(userName), 'skip_migrated', 'true')
    );
    const { userInfoCache } = await import('./user-cache');
    userInfoCache?.delete(userName);

    console.log(`用户 ${userName} 的跳过配置迁移完成`);
  }

  // ---------- 弹幕过滤配置 ----------
  async getDanmakuFilterConfig(
    userName: string
  ): Promise<import('./types').DanmakuFilterConfig | null> {
    const val = await this.withRetry(() =>
      this.client.get(this.danmakuFilterConfigKey(userName))
    );
    return val ? (JSON.parse(val) as import('./types').DanmakuFilterConfig) : null;
  }

  async setDanmakuFilterConfig(
    userName: string,
    config: import('./types').DanmakuFilterConfig
  ): Promise<void> {
    await this.withRetry(() =>
      this.client.set(
        this.danmakuFilterConfigKey(userName),
        JSON.stringify(config)
      )
    );
  }

  async deleteDanmakuFilterConfig(userName: string): Promise<void> {
    await this.withRetry(() =>
      this.client.del(this.danmakuFilterConfigKey(userName))
    );
  }

  // 清空所有数据
  async clearAllData(): Promise<void> {
    try {
      // 获取所有用户
      const allUsers = await this.getAllUsers();

      // 删除所有用户及其数据
      for (const username of allUsers) {
        await this.deleteUser(username);
      }

      // 删除管理员配置
      await this.withRetry(() => this.client.del(this.adminConfigKey()));

      console.log('所有数据已清空');
    } catch (error) {
      console.error('清空数据失败:', error);
      throw new Error('清空数据失败');
    }
  }

  // ---------- 通用键值存储 ----------
  private globalValueKey(key: string) {
    return `global:${key}`;
  }

  async getGlobalValue(key: string): Promise<string | null> {
    const val = await this.withRetry(() =>
      this.client.get(this.globalValueKey(key))
    );
    return val ? ensureString(val) : null;
  }

  async setGlobalValue(key: string, value: string): Promise<void> {
    await this.withRetry(() =>
      this.client.set(this.globalValueKey(key), ensureString(value))
    );
  }

  async deleteGlobalValue(key: string): Promise<void> {
    await this.withRetry(() => this.client.del(this.globalValueKey(key)));
  }

  // ---------- 通知相关 ----------
  private notificationsKey(userName: string) {
    return `u:${userName}:notifications`;
  }

  private lastFavoriteCheckKey(userName: string) {
    return `u:${userName}:last_fav_check`;
  }

  async getNotifications(userName: string): Promise<import('./types').Notification[]> {
    const val = await this.withRetry(() =>
      this.client.get(this.notificationsKey(userName))
    );
    return val ? (JSON.parse(val) as import('./types').Notification[]) : [];
  }

  async addNotification(
    userName: string,
    notification: import('./types').Notification
  ): Promise<void> {
    const notifications = await this.getNotifications(userName);
    notifications.unshift(notification); // 新通知放在最前面
    // 限制通知数量，最多保留100条
    if (notifications.length > 100) {
      notifications.splice(100);
    }
    await this.withRetry(() =>
      this.client.set(this.notificationsKey(userName), JSON.stringify(notifications))
    );
  }

  async markNotificationAsRead(
    userName: string,
    notificationId: string
  ): Promise<void> {
    const notifications = await this.getNotifications(userName);
    const notification = notifications.find((n) => n.id === notificationId);
    if (notification) {
      notification.read = true;
      await this.withRetry(() =>
        this.client.set(this.notificationsKey(userName), JSON.stringify(notifications))
      );
    }
  }

  async deleteNotification(
    userName: string,
    notificationId: string
  ): Promise<void> {
    const notifications = await this.getNotifications(userName);
    const filtered = notifications.filter((n) => n.id !== notificationId);
    await this.withRetry(() =>
      this.client.set(this.notificationsKey(userName), JSON.stringify(filtered))
    );
  }

  async clearAllNotifications(userName: string): Promise<void> {
    await this.withRetry(() => this.client.del(this.notificationsKey(userName)));
  }

  async getUnreadNotificationCount(userName: string): Promise<number> {
    const notifications = await this.getNotifications(userName);
    return notifications.filter((n) => !n.read).length;
  }

  async getLastFavoriteCheckTime(userName: string): Promise<number> {
    const val = await this.withRetry(() =>
      this.client.get(this.lastFavoriteCheckKey(userName))
    );
    return val ? parseInt(val, 10) : 0;
  }

  async setLastFavoriteCheckTime(
    userName: string,
    timestamp: number
  ): Promise<void> {
    await this.withRetry(() =>
      this.client.set(this.lastFavoriteCheckKey(userName), timestamp.toString())
    );
  }
}
