import { Injectable, Inject, Logger } from '@nestjs/common';
import { RedisService } from '@/infrastructure/redis';
import {
  CAPABILITY_REPOSITORY,
  CapabilityRepository,
} from '@/domain/repositories/capability.repository.interface';
import {
  Capability,
  CapabilityMap,
  defaultCapabilityMap,
} from '@/domain/value-objects/capability.vo';

@Injectable()
export class CapabilityService {
  private readonly logger = new Logger(CapabilityService.name);
  private readonly REDIS_PREFIX = 'cap:';
  private readonly REDIS_TTL = 3600; // 1 hour

  constructor(
    @Inject(CAPABILITY_REPOSITORY)
    private readonly capabilityRepo: CapabilityRepository,
    private readonly redis: RedisService,
  ) {}

  /**
   * 获取用户的完整能力映射
   * Redis 缓存优先 → DB fallback → 写回 Redis
   * 默认行为：无记录 = 全部开启
   */
  async getCapabilities(accountSequence: string): Promise<CapabilityMap> {
    const cached = await this.redis.getJson<CapabilityMap>(
      `${this.REDIS_PREFIX}${accountSequence}`,
    );
    if (cached) return cached;

    const map = await this.buildCapabilityMap(accountSequence);

    await this.redis.setJson(
      `${this.REDIS_PREFIX}${accountSequence}`,
      map,
      this.REDIS_TTL,
    );

    return map;
  }

  /**
   * 检查单个能力是否开启
   */
  async isCapabilityEnabled(
    accountSequence: string,
    capability: Capability,
  ): Promise<boolean> {
    const map = await this.getCapabilities(accountSequence);
    return map[capability] ?? true;
  }

  /**
   * 设置单个能力
   */
  async setCapability(params: {
    accountSequence: string;
    capability: Capability;
    enabled: boolean;
    reason?: string;
    operatorId?: string;
    expiresAt?: Date;
  }): Promise<CapabilityMap> {
    const current = await this.capabilityRepo.findByAccountSequence(params.accountSequence);
    const existing = current.find((c) => c.capability === params.capability);
    const previousValue = existing ? existing.enabled : true;

    await this.capabilityRepo.upsertWithLog(
      {
        accountSequence: params.accountSequence,
        capability: params.capability,
        enabled: params.enabled,
        reason: params.reason,
        disabledBy: params.enabled ? undefined : params.operatorId,
        expiresAt: params.expiresAt,
      },
      {
        accountSequence: params.accountSequence,
        capability: params.capability,
        action: params.enabled ? 'ENABLE' : 'DISABLE',
        reason: params.reason,
        operatorId: params.operatorId,
        previousValue,
        newValue: params.enabled,
        expiresAt: params.expiresAt,
      },
    );

    return this.refreshCache(params.accountSequence);
  }

  /**
   * 批量设置能力
   */
  async setCapabilities(params: {
    accountSequence: string;
    capabilities: Array<{
      capability: Capability;
      enabled: boolean;
      reason?: string;
      expiresAt?: Date;
    }>;
    operatorId?: string;
  }): Promise<CapabilityMap> {
    for (const cap of params.capabilities) {
      await this.setCapability({
        accountSequence: params.accountSequence,
        capability: cap.capability,
        enabled: cap.enabled,
        reason: cap.reason,
        operatorId: params.operatorId,
        expiresAt: cap.expiresAt,
      });
    }
    return this.refreshCache(params.accountSequence);
  }

  /**
   * 处理到期的临时限制（由 cron 调用）
   */
  async processExpiredRestrictions(): Promise<number> {
    const expired = await this.capabilityRepo.findExpired();
    let count = 0;

    for (const record of expired) {
      await this.capabilityRepo.upsertWithLog(
        {
          accountSequence: record.accountSequence,
          capability: record.capability,
          enabled: true,
          reason: '临时限制已到期，自动恢复',
        },
        {
          accountSequence: record.accountSequence,
          capability: record.capability,
          action: 'EXPIRE',
          reason: '临时限制到期自动恢复',
          previousValue: false,
          newValue: true,
        },
      );

      await this.refreshCache(record.accountSequence);
      count++;
    }

    return count;
  }

  /**
   * 查询能力变更日志
   */
  async getCapabilityLogs(
    accountSequence: string,
    page: number,
    pageSize: number,
  ) {
    return this.capabilityRepo.findLogsByAccountSequence(
      accountSequence,
      page,
      pageSize,
    );
  }

  private async buildCapabilityMap(accountSequence: string): Promise<CapabilityMap> {
    const records = await this.capabilityRepo.findByAccountSequence(accountSequence);
    const map = defaultCapabilityMap();

    for (const record of records) {
      if (record.capability in Capability) {
        // 已过期的限制视为开启
        if (!record.enabled && record.expiresAt && record.expiresAt <= new Date()) {
          map[record.capability as Capability] = true;
        } else {
          map[record.capability as Capability] = record.enabled;
        }
      }
    }

    return map;
  }

  private async refreshCache(accountSequence: string): Promise<CapabilityMap> {
    const map = await this.buildCapabilityMap(accountSequence);
    try {
      await this.redis.setJson(
        `${this.REDIS_PREFIX}${accountSequence}`,
        map,
        this.REDIS_TTL,
      );
    } catch (error) {
      this.logger.warn(`Redis 缓存刷新失败 (${accountSequence}): ${error?.message}`);
    }
    return map;
  }
}
