import { CACHE_MANAGER } from '@nestjs/cache-manager';
import { Inject, Injectable, OnModuleInit } from '@nestjs/common';
import { Cron, CronExpression } from '@nestjs/schedule';
import { Cache } from 'cache-manager';
import { ROLES_BUILDER_TOKEN, RolesBuilder } from 'nest-access-control';
import { RoleService } from './role.service';

/**
 * 1. 启动时优先从缓存加载权限数据，缓存不存在则从数据库加载
 * 2. 每分钟从数据库刷新权限数据
 * 3. 刷新成功后同时更新缓存和 RolesBuilder
 * 4. 刷新失败时保持使用缓存中的旧数据，确保服务可用性
 */
@Injectable()
export class RolesRefresherService implements OnModuleInit {
  private static readonly CACHE_KEY = 'roles:grants';
  // 使用全局 TTL 配置（5分钟），无需单独设置

  constructor(
    @Inject(ROLES_BUILDER_TOKEN) private readonly rolesBuilder: RolesBuilder,
    @Inject(CACHE_MANAGER) private readonly cacheManager: Cache,
    private readonly roleService: RoleService,
  ) {}

  async onModuleInit() {
    // 启动时优先从缓存加载，失败则从数据库加载
    await this.initializeRoles();
  }

  /**
   * 初始化权限数据
   * 优先从缓存加载，缓存不存在则从数据库加载
   */
  private async initializeRoles() {
    try {
      // 1. 尝试从缓存加载
      const cachedGrants = await this.cacheManager.get<any>(
        RolesRefresherService.CACHE_KEY,
      );

      if (cachedGrants) {
        // console.log('[RolesRefresher] Loading roles from cache...');
        this.updateRolesBuilder(cachedGrants);
        // console.log('[RolesRefresher] ✅ Roles loaded from cache successfully');

        // 后台异步刷新数据库数据（不阻塞启动）
        this.refreshRolesFromDB().catch((error) => {
          console.error('[RolesRefresher] Background refresh failed:', error);
        });
        return;
      }

      // 如果缓存不存在，从数据库加载
      console.log(
        '[RolesRefresher] Cache miss, loading roles from database...',
      );
      await this.refreshRolesFromDB();
    } catch (error) {
      console.error('[RolesRefresher] ❌ Failed to initialize roles:', error);
      // 初始化失败，RolesBuilder 保持为空，权限检查会失败（fail-safe）
    }
  }

  /**
   * 定时刷新任务（每1分钟执行一次）
   */
  @Cron(CronExpression.EVERY_MINUTE)
  async handleCron() {
    await this.refreshRolesFromDB();
  }

  /**
   * 从数据库刷新权限数据
   * 成功后同时更新缓存和 RolesBuilder
   * 失败时保持使用缓存中的旧数据
   */
  private async refreshRolesFromDB() {
    try {
      console.log('[RolesRefresher] Refreshing roles from database...');
      const newBuilder = await this.roleService.getBuilder();
      const newGrants =
        (newBuilder as any)._grants || (newBuilder as any).grants || null;

      if (!newGrants) {
        console.error(
          '[RolesRefresher] ❌ Failed to extract grants from builder',
        );
        return;
      }
      // 先更新缓存（使用全局 TTL：5分钟）
      await this.cacheManager.set(RolesRefresherService.CACHE_KEY, newGrants);
      // console.log('[RolesRefresher] ✅ Roles cached successfully');
      // 更新 RolesBuilder（内存中的权限数据）
      this.updateRolesBuilder(newGrants);

      // console.log('[RolesRefresher] ✅ Roles refreshed successfully');
    } catch (error) {
      console.error(
        '[RolesRefresher] ❌ Failed to refresh roles from DB:',
        error,
      );

      // 失败时尝试从缓存恢复
      try {
        const cachedGrants = await this.cacheManager.get<any>(
          RolesRefresherService.CACHE_KEY,
        );
        if (cachedGrants) {
          // console.log('[RolesRefresher] Using cached roles as fallback');
          this.updateRolesBuilder(cachedGrants);
        } else {
          // console.error('[RolesRefresher] No cached roles available');
        }
      } catch (cacheError) {
        console.error(
          '[RolesRefresher] Failed to load from cache:',
          cacheError,
        );
      }
    }
  }

  /**
   * 更新 RolesBuilder 的内部状态
   * @param grants 权限数据
   */
  private updateRolesBuilder(grants: any) {
    (this.rolesBuilder as any)._grants = grants;
    if ((this.rolesBuilder as any).grants !== undefined) {
      (this.rolesBuilder as any).grants = grants;
    }
  }
}
