import { existsSync, readFileSync } from 'node:fs';
import path from 'node:path';
import process from 'node:process';
import { fileURLToPath } from 'node:url';

const root = path.resolve(path.dirname(fileURLToPath(import.meta.url)), '..');

const failures = [];
let colorTokenCount = 0;

function readJson(relativePath) {
  const absolutePath = path.join(root, relativePath);

  try {
    return JSON.parse(readFileSync(absolutePath, 'utf8'));
  } catch (error) {
    failures.push(`${relativePath}: ${error.message}`);
    return null;
  }
}

function assertFile(relativePath) {
  const absolutePath = path.resolve(root, relativePath);

  if (!existsSync(absolutePath)) {
    failures.push(`${relativePath}: file does not exist`);
  }
}

function isHexColor(value) {
  return /^#(?:[0-9a-f]{3}|[0-9a-f]{6}|[0-9a-f]{8})$/i.test(value);
}

function visitW3cTokenTree(node, trail = [], inheritedType = undefined) {
  if (!node || typeof node !== 'object' || Array.isArray(node)) {
    return;
  }

  const type = node.$type || inheritedType;

  if (Object.hasOwn(node, '$value')) {
    if (type === 'color') {
      colorTokenCount += 1;

      if (typeof node.$value !== 'string' || !isHexColor(node.$value)) {
        failures.push(`tokens/ru.tokens.json:${trail.join('.')}: invalid color value`);
      }
    }

    return;
  }

  for (const [key, value] of Object.entries(node)) {
    if (key.startsWith('$')) {
      continue;
    }

    visitW3cTokenTree(value, [...trail, key], type);
  }
}

function visitFigmaTokenTree(node, trail = []) {
  if (!node || typeof node !== 'object' || Array.isArray(node)) {
    return;
  }

  if (node.type === 'color' && Object.hasOwn(node, 'value')) {
    const value = String(node.value);

    if (!value.startsWith('{') && !isHexColor(value)) {
      failures.push(`tokens/figma-tokens.json:${trail.join('.')}: invalid color value`);
    }

    return;
  }

  for (const [key, value] of Object.entries(node)) {
    if (key.startsWith('$')) {
      continue;
    }

    visitFigmaTokenTree(value, [...trail, key]);
  }
}

const w3cTokens = readJson('tokens/ru.tokens.json');
const figmaTokens = readJson('tokens/figma-tokens.json');
const manifest = readJson('assets/manifest.json');

assertFile('README.md');
assertFile('penpot/ru-variables.css');
assertFile('figma/README.md');
assertFile('penpot/README.md');

if (w3cTokens) {
  visitW3cTokenTree(w3cTokens);
}

if (figmaTokens) {
  visitFigmaTokenTree(figmaTokens);
}

if (manifest) {
  assertFile(manifest.sourceManual);

  const approvedAssets = Array.isArray(manifest.approvedAssets) ? manifest.approvedAssets : [];
  const ids = new Set();

  for (const asset of approvedAssets) {
    if (!asset.id || ids.has(asset.id)) {
      failures.push(`assets/manifest.json: duplicate or missing approved asset id "${asset.id}"`);
    }

    ids.add(asset.id);

    if (!asset.path) {
      failures.push(`assets/manifest.json:${asset.id}: missing path`);
      continue;
    }

    if (/\/institutional\//i.test(asset.path) || /ufpe-id/i.test(asset.path)) {
      failures.push(`assets/manifest.json:${asset.id}: forbidden asset approved`);
    }

    assertFile(asset.path);
  }

  for (const asset of manifest.forbiddenAssets || []) {
    if (!asset.reason) {
      failures.push(`assets/manifest.json:${asset.path}: forbidden asset must explain reason`);
    }
  }
}

if (failures.length > 0) {
  console.error('RU design system check failed:');
  for (const failure of failures) {
    console.error(`- ${failure}`);
  }
  process.exit(1);
}

console.log(`RU design system OK: ${colorTokenCount} color tokens, ${manifest.approvedAssets.length} approved assets.`);
