/**
 * Manual one-off sync — NOT wired into build or pack.
 *   node scripts/sync-docker-icons.mjs
 *
 * Generates colored SVGs (Simple Icons, CC0) plus a few official brand assets
 * into public/docker-icons/, then writes domain/systemManager/dockerIconBundled.ts.
 */
import { mkdirSync, readFileSync, readdirSync, unlinkSync, writeFileSync } from 'node:fs';
import { dirname, join } from 'node:path';
import { fileURLToPath } from 'node:url';
import * as simpleIcons from 'simple-icons';

const __dirname = dirname(fileURLToPath(import.meta.url));
const ROOT = join(__dirname, '..');
const SRC_FILE = join(ROOT, 'domain/systemManager/dockerImageIcons.ts');
const OUT_DIR = join(ROOT, 'public/docker-icons');
const MANIFEST_FILE = join(ROOT, 'domain/systemManager/dockerIconBundled.ts');

/**
 * Official assets not covered by Simple Icons — see public/docker-icons/NOTICE.md
 * Prefer SVG when the upstream project publishes one; PNG only when no SVG exists.
 */
const OFFICIAL_ICONS = [
  {
    iconId: 'nacos',
    file: 'nacos.svg',
    url: 'https://raw.githubusercontent.com/nacos-group/nacos-logo/master/Nacos%20logo%20%E7%99%BD%E8%93%9D%E8%B5%84%E6%BA%90%205.svg',
  },
  {
    iconId: 'polaris',
    file: 'polaris.svg',
    url: 'https://raw.githubusercontent.com/polarismesh/polaris/main/logo.svg',
  },
  {
    iconId: 'memcached',
    file: 'memcached.png',
    url: 'https://memcached.org/images/memcached_link_125.png',
  },
];

const slugById = parseStringRecord(SRC_FILE, 'SIMPLE_ICONS_SLUG');
const styleById = parseTileStyles(SRC_FILE);

const iconsBySlug = new Map();
for (const icon of Object.values(simpleIcons)) {
  if (icon && typeof icon === 'object' && 'slug' in icon && 'path' in icon) {
    iconsBySlug.set(icon.slug, icon);
  }
}

mkdirSync(OUT_DIR, { recursive: true });

const bundled = [];
const iconFiles = {};
const skipped = [];

for (const [iconId, slug] of Object.entries(slugById)) {
  const brand = iconsBySlug.get(slug);
  if (!brand) {
    skipped.push({ iconId, slug, reason: 'slug not in simple-icons' });
    continue;
  }

  const iconColor = styleById[iconId]?.iconColor ?? 'ffffff';
  const fill = iconColor.startsWith('#') ? iconColor : `#${iconColor}`;
  const file = `${iconId}.svg`;

  const svg = [
    `<svg role="img" viewBox="0 0 24 24" xmlns="http://www.w3.org/2000/svg">`,
    `  <title>${escapeXml(brand.title)}</title>`,
    `  <path d="${brand.path}" fill="${fill}"/>`,
    `</svg>`,
    '',
  ].join('\n');

  writeFileSync(join(OUT_DIR, file), svg, 'utf8');
  bundled.push(iconId);
  iconFiles[iconId] = file;
}

for (const entry of OFFICIAL_ICONS) {
  const response = await fetch(entry.url);
  if (!response.ok) {
    throw new Error(`Failed to download ${entry.iconId} from ${entry.url}: ${response.status}`);
  }
  const buffer = Buffer.from(await response.arrayBuffer());
  writeFileSync(join(OUT_DIR, entry.file), buffer);
  bundled.push(entry.iconId);
  iconFiles[entry.iconId] = entry.file;
  console.log(`Downloaded official ${entry.iconId} -> ${entry.file}`);
}

const bundledSet = new Set(bundled);
for (const file of readdirSync(OUT_DIR)) {
  if (file === 'NOTICE.md') continue;
  const iconId = file.replace(/\.(svg|png|webp)$/i, '');
  const owned =
    bundledSet.has(iconId) && iconFiles[iconId] === file;
  if (!owned) {
    unlinkSync(join(OUT_DIR, file));
    console.log(`Removed stale ${file}`);
  }
}

bundled.sort();
const fileEntries = bundled
  .filter((id) => iconFiles[id] !== `${id}.svg`)
  .map((id) => `  '${id}': '${iconFiles[id]}',`);

writeFileSync(
  MANIFEST_FILE,
  [
    '// Auto-generated by scripts/sync-docker-icons.mjs — do not edit.',
    'export const BUNDLED_DOCKER_ICON_IDS = new Set<string>([',
    ...bundled.map((id) => `  '${id}',`),
    ']);',
    '',
    '/** Non-default filenames (e.g. official PNG assets). Default is `${id}.svg`. */',
    'export const DOCKER_ICON_FILES: Record<string, string> = {',
    ...fileEntries,
    '};',
    '',
  ].join('\n'),
  'utf8',
);

console.log(`Wrote ${bundled.length} icons to public/docker-icons/`);
console.log(`Updated ${MANIFEST_FILE}`);

if (skipped.length > 0) {
  console.log(`Skipped ${skipped.length} (no official Simple Icons slug):`);
  for (const item of skipped) {
    console.log(`  ${item.iconId} -> ${item.slug}`);
  }
}

function parseStringRecord(filePath, constName) {
  const src = readFileSync(filePath, 'utf8');
  const start = src.indexOf(`const ${constName}`);
  if (start < 0) throw new Error(`Could not find ${constName} in ${filePath}`);

  const braceStart = src.indexOf('{', start);
  const braceEnd = findMatchingBrace(src, braceStart);
  const block = src.slice(braceStart + 1, braceEnd);

  const out = {};
  for (const line of block.split('\n')) {
    const match = line.match(/^\s*([a-zA-Z0-9_]+):\s*'([^']*)',?\s*$/);
    if (match) out[match[1]] = match[2];
  }
  return out;
}

function parseTileStyles(filePath) {
  const src = readFileSync(filePath, 'utf8');
  const start = src.indexOf('const ICON_TILE_STYLE');
  if (start < 0) throw new Error(`Could not find ICON_TILE_STYLE in ${filePath}`);

  const braceStart = src.indexOf('{', start);
  const braceEnd = findMatchingBrace(src, braceStart);
  const block = src.slice(braceStart + 1, braceEnd);

  const out = {};
  const re =
    /^\s*([a-zA-Z0-9_]+):\s*\{\s*background:\s*'([^']*)',\s*iconColor:\s*'([^']*)'\s*\},?\s*$/;
  for (const line of block.split('\n')) {
    const match = line.match(re);
    if (match) {
      out[match[1]] = { background: match[2], iconColor: match[3] };
    }
  }
  return out;
}

function findMatchingBrace(src, openIndex) {
  let depth = 0;
  for (let i = openIndex; i < src.length; i += 1) {
    if (src[i] === '{') depth += 1;
    else if (src[i] === '}') {
      depth -= 1;
      if (depth === 0) return i;
    }
  }
  throw new Error('Unbalanced braces while parsing dockerImageIcons.ts');
}

function escapeXml(value) {
  return value
    .replace(/&/g, '&amp;')
    .replace(/</g, '&lt;')
    .replace(/>/g, '&gt;')
    .replace(/"/g, '&quot;');
}
