'use strict';

const path = require('node:path');
const { wildcardMatch } = require('../tools/permission-rules');

const KV_PREFIX = 'permission:always:';
const _memoryRules = new Map();

class PermissionRulesStore {
  constructor({ brain = null, namespace = KV_PREFIX } = {}) {
    this.brain = brain;
    this.namespace = namespace;
  }

  list(projectRoot = '') {
    return this._load(projectRoot);
  }

  addAlways({ projectRoot = '', permission, pattern = '*', tool = '', fingerprint = '', metadata = {} } = {}) {
    if (!permission) throw new Error('permission is required');
    const rules = this._load(projectRoot);
    const normalized = {
      permission,
      pattern,
      tool,
      fingerprint: fingerprint || metadata.fingerprint || '',
      metadata,
      createdAt: new Date().toISOString(),
    };
    const exists = rules.some((rule) =>
      rule.permission === normalized.permission &&
      rule.pattern === normalized.pattern &&
      rule.tool === normalized.tool &&
      (rule.fingerprint || '') === normalized.fingerprint
    );
    if (!exists) {
      rules.push(normalized);
      this._save(projectRoot, rules);
    }
    return normalized;
  }

  findAlways({ projectRoot = '', permission, pattern = '*', tool = '', fingerprint = '' } = {}) {
    const roots = uniqueRoots(projectRoot);
    for (const root of roots) {
      for (const rule of this._load(root)) {
        if (tool && rule.tool && rule.tool !== tool) continue;
        if (fingerprint) {
          if (rule.fingerprint && rule.fingerprint !== fingerprint) continue;
          if (!rule.fingerprint && !isExactLegacyMatch(rule, { permission, pattern, tool })) continue;
        }
        if (wildcardMatch(permission || '', rule.permission || '*') && wildcardMatch(pattern || '', rule.pattern || '*')) {
          return rule;
        }
      }
    }
    return null;
  }

  _load(projectRoot = '') {
    const key = this._key(projectRoot);
    const raw = this._getKv(key);
    if (!raw) return [];
    try {
      const parsed = JSON.parse(raw);
      return Array.isArray(parsed) ? parsed : [];
    } catch {
      return [];
    }
  }

  _save(projectRoot = '', rules = []) {
    this._setKv(this._key(projectRoot), JSON.stringify(rules));
  }

  _key(projectRoot = '') {
    return this.namespace + normalizeRoot(projectRoot || 'global');
  }

  _getKv(key) {
    if (this.brain?.getKv) return this.brain.getKv(key);
    try {
      const brain = require('../brain');
      if (brain?.getKv) return brain.getKv(key);
    } catch {}
    return _memoryRules.get(key) || '';
  }

  _setKv(key, value) {
    if (this.brain?.setKv) return this.brain.setKv(key, value);
    try {
      const brain = require('../brain');
      if (brain?.setKv) return brain.setKv(key, value);
    } catch {}
    _memoryRules.set(key, value);
    return null;
  }
}

function normalizeRoot(projectRoot) {
  if (!projectRoot || projectRoot === 'global') return 'global';
  return path.resolve(projectRoot);
}

function uniqueRoots(projectRoot) {
  const roots = [normalizeRoot(projectRoot), 'global'];
  return [...new Set(roots)];
}

function isExactLegacyMatch(rule, request) {
  return !hasWildcard(rule.permission)
    && !hasWildcard(rule.pattern)
    && rule.permission === request.permission
    && rule.pattern === request.pattern
    && (!rule.tool || !request.tool || rule.tool === request.tool);
}

function hasWildcard(value) {
  return String(value || '').includes('*');
}

function clearMemoryRules() {
  _memoryRules.clear();
}

module.exports = {
  PermissionRulesStore,
  clearMemoryRules,
};
