import pino from 'pino';

const logger = pino({ name: 'governance' });

/**
 * Clock interface for deterministic governance tests (BMad must-have).
 * Inject FakeClock in tests, RealClock in production.
 */
export interface Clock {
  now(): number;
}

export class RealClock implements Clock {
  now() { return Date.now(); }
}

export class FakeClock implements Clock {
  private current: number;
  constructor(start = Date.now()) { this.current = start; }
  now() { return this.current; }
  advanceBy(ms: number) { this.current += ms; }
}

export interface PromotionResult {
  promoted: boolean;
  newMode?: 'audit' | 'enforce';
  reason?: string;
}

const PROMOTION_DAYS = 14;
const MAX_FP_RATE = 0.10; // 10% false positive rate

/**
 * Governance engine — manages auto-promotion from shadow → audit → enforce.
 * Uses injectable Clock for deterministic testing.
 */
export class GovernanceEngine {
  private clock: Clock;

  constructor(clock: Clock = new RealClock()) {
    this.clock = clock;
  }

  /**
   * Evaluate whether a tenant should be promoted to the next governance mode.
   * Requires: 14+ days in current mode AND false positive rate < 10%.
   */
  evaluatePromotion(
    tenantId: string,
    stats: { fpRate: number; daysInCurrentMode: number },
  ): PromotionResult {
    if (stats.daysInCurrentMode < PROMOTION_DAYS) {
      return { promoted: false, reason: `Only ${stats.daysInCurrentMode} days — need ${PROMOTION_DAYS}` };
    }

    if (stats.fpRate > MAX_FP_RATE) {
      return {
        promoted: false,
        reason: `false-positive rate ${(stats.fpRate * 100).toFixed(1)}% exceeds ${MAX_FP_RATE * 100}% threshold`,
      };
    }

    return { promoted: true, newMode: 'audit' };
  }

  /**
   * Check panic mode status.
   * Defaults to panic=active (safe) when Redis is unreachable (BMad must-have).
   */
  async checkPanicMode(tenantId: string, redis: any): Promise<boolean> {
    try {
      const val = await redis.get(`panic:${tenantId}`);
      return val === '1';
    } catch (err) {
      logger.warn({ tenantId, error: (err as Error).message },
        'Redis unreachable — defaulting to panic=active');
      return true; // Safe default: panic IS active
    }
  }
}
