#!/usr/bin/env node
// gen-permissions.js — 从 permissions.yaml 生成 seed SQL 和前端 routeConfig 片段
//
// 用法:
//   node scripts/gen-permissions.js --sql       输出 seed INSERT SQL
//   node scripts/gen-permissions.js --frontend   输出 routeConfig.ts 条目
//   node scripts/gen-permissions.js --validate   验证与代码一致性

const fs = require('fs');
const path = require('path');
const yaml = require('js-yaml');

const YAML_PATH = path.resolve(__dirname, '..', 'permissions.yaml');

function loadPermissions() {
  const raw = fs.readFileSync(YAML_PATH, 'utf-8');
  return yaml.load(raw);
}

function getAllCodes(registry) {
  const codes = [];
  for (const [, group] of Object.entries(registry)) {
    for (const perm of group.permissions) {
      codes.push(perm.code);
    }
  }
  return codes;
}

function generateSeedSQL(registry) {
  const sys = '00000000-0000-0000-0000-000000000000';
  const lines = [
    '-- Auto-generated from permissions.yaml by gen-permissions.js',
    `-- Generated: ${new Date().toISOString().slice(0, 10)}`,
    '',
  ];

  for (const [groupKey, group] of Object.entries(registry)) {
    lines.push(`-- ${groupKey}: ${group.description}`);
    for (const perm of group.permissions) {
      const parts = perm.code.split('.');
      const resource = parts.length >= 2 ? parts[0] : groupKey;
      const action = parts.slice(1).join('.');
      lines.push(
        `INSERT INTO permissions (id, tenant_id, code, name, resource, action, description,` +
          ` created_at, updated_at, created_by, updated_by, deleted_at, version)` +
          ` SELECT gen_random_uuid(), t.id, '${perm.code}', '${perm.name}', '${resource}', '${action}', '${perm.name}',` +
          ` NOW(), NOW(), '${sys}', '${sys}', NULL, 1` +
          ` FROM tenant t` +
          ` WHERE NOT EXISTS (SELECT 1 FROM permissions p WHERE p.code = '${perm.code}' AND p.tenant_id = t.id AND p.deleted_at IS NULL)` +
          ` ON CONFLICT DO NOTHING;`
      );
    }
    lines.push('');
  }
  return lines.join('\n');
}

function generateFrontendSnippet(registry) {
  const lines = ['// Auto-generated from permissions.yaml by gen-permissions.js', ''];

  for (const [, group] of Object.entries(registry)) {
    const frozenPerms = group.permissions.filter(p => p.frozen);
    const activePerms = group.permissions.filter(p => !p.frozen);

    // Group by entity prefix (e.g., health.patient → {list, manage})
    const entities = {};
    for (const perm of [...activePerms, ...frozenPerms]) {
      const parts = perm.code.split('.');
      if (parts.length < 2) continue;
      const entity = parts.slice(0, -1).join('.');
      const action = parts[parts.length - 1];
      if (!entities[entity]) entities[entity] = { list: [], frozen: perm.frozen || false };
      entities[entity].list.push(perm.code);
    }

    for (const [entity, info] of Object.entries(entities)) {
      const frozenAttr = info.frozen ? ',\n    frozen: true' : '';
      lines.push(`  {`);
      lines.push(`    path: "/${entity.replace(/\./g, '/')}",`);
      lines.push(`    permissions: [${info.list.map(c => `"${c}"`).join(', ')}]${frozenAttr}`);
      lines.push(`  },`);
    }
  }

  return lines.join('\n');
}

function validate(registry) {
  const yamlCodes = getAllCodes(registry);
  const rootDir = path.resolve(__dirname, '..');

  // Recursively find .rs files and extract permission codes
  const backendCodes = new Set();
  function walkDir(dir) {
    for (const entry of fs.readdirSync(dir, { withFileTypes: true })) {
      const full = path.join(dir, entry.name);
      if (entry.isDirectory() && !entry.name.startsWith('.') && entry.name !== 'target') {
        walkDir(full);
      } else if (entry.isFile() && entry.name.endsWith('.rs')) {
        const content = fs.readFileSync(full, 'utf-8');
        // Match code: "xxx.yyy.zzz" pattern in PermissionDescriptor
        // Must be lowercase letters/digits/hyphens with dots (permission code pattern)
        const matches = content.matchAll(/code:\s*"([a-z][a-z0-9-]*\.[a-z][a-z0-9-]*(?:\.[a-z][a-z0-9-]*)*)"/g);
        for (const m of matches) {
          backendCodes.add(m[1]);
        }
      }
    }
  }
  walkDir(path.join(rootDir, 'crates'));

  let errors = 0;

  // Check YAML covers all backend codes
  for (const code of backendCodes) {
    if (!yamlCodes.includes(code)) {
      console.log(`MISSING: Backend '${code}' not in permissions.yaml`);
      errors++;
    }
  }

  // Check backend covers all YAML codes
  for (const code of yamlCodes) {
    if (!backendCodes.has(code)) {
      console.log(`MISSING: YAML '${code}' not in backend module.rs`);
      errors++;
    }
  }

  if (errors === 0) {
    console.log(`OK: ${yamlCodes.length} YAML / ${backendCodes.size} backend — 0 mismatches`);
  }
  return errors;
}

// Main
const args = process.argv.slice(2);
const registry = loadPermissions();

if (args.includes('--sql')) {
  console.log(generateSeedSQL(registry));
} else if (args.includes('--frontend')) {
  console.log(generateFrontendSnippet(registry));
} else if (args.includes('--validate')) {
  const errors = validate(registry);
  process.exit(errors > 0 ? 1 : 0);
} else {
  const codes = getAllCodes(registry);
  console.log(`permissions.yaml loaded: ${codes.length} permission codes across ${Object.keys(registry).length} modules`);
  console.log('Usage:');
  console.log('  node scripts/gen-permissions.js --sql        Generate seed SQL');
  console.log('  node scripts/gen-permissions.js --frontend    Generate routeConfig snippet');
  console.log('  node scripts/gen-permissions.js --validate    Validate consistency');
}
