import fs from 'node:fs';
import path from 'node:path';
import { batch7a, batch7b, batch7c, brandSlugs, brandHand } from './defs.mjs';
import { batch8a, batch8b, batch8c, batch8d, batch8e, batch8f } from './defs8.mjs';

const ROOT = path.resolve(import.meta.dirname, '..');
const CSS = path.join(ROOT, 'css', 'ga-icons.css');
const HTML = path.join(ROOT, 'pages', 'icons.html');

// Matches the encoding already used throughout ga-icons.css: single quotes stay
// literal, only <, >, # and " are escaped.
const enc = (s) => s.replace(/</g, '%3C').replace(/>/g, '%3E').replace(/#/g, '%23').replace(/"/g, '%22');

const OUTLINE_ATTRS = `viewBox='0 0 24 24' fill='none' stroke='#000' stroke-width='2' stroke-linecap='round' stroke-linejoin='round'`;
const BRAND_ATTRS = `viewBox='0 0 24 24' fill='#000'`;

function rule(name, inner, attrs) {
  const svg = `<svg xmlns='http://www.w3.org/2000/svg' ${attrs}>${inner}</svg>`;
  const uri = `data:image/svg+xml,${enc(svg)}`;
  return `.ga.ga-${name} { -webkit-mask-image: url("${uri}"); mask-image: url("${uri}"); }`;
}

async function fetchBrandPaths() {
  const out = {};
  for (const [name, slug] of Object.entries(brandSlugs)) {
    const url = `https://cdn.jsdelivr.net/npm/simple-icons@13/icons/${slug}.svg`;
    const res = await fetch(url);
    if (!res.ok) throw new Error(`${name} (${slug}): HTTP ${res.status}`);
    const svg = await res.text();
    const paths = [...svg.matchAll(/<path\b[^>]*\bd="([^"]+)"[^>]*\/>/g)].map((m) => `<path d='${m[1]}'/>`);
    if (!paths.length) throw new Error(`${name} (${slug}): no <path d="..."> found`);
    out[name] = paths.join('');
    process.stdout.write(`  ${name} <- simple-icons/${slug}\n`);
  }
  for (const [name, inner] of Object.entries(brandHand)) {
    out[name] = inner;
    process.stdout.write(`  ${name} <- hand-authored\n`);
  }
  return out;
}

const sections = [
  ['Batch 7a — Bootstrap Icons: Admin / Dashboard UI', batch7a, OUTLINE_ATTRS],
  ['Batch 7b — Bootstrap Icons: Files & Filetypes', batch7b, OUTLINE_ATTRS],
  ['Batch 7c — Bootstrap Icons: Content, Text & Communication', batch7c, OUTLINE_ATTRS],
];

console.log('Fetching brand paths from Simple Icons...');
const brands = await fetchBrandPaths();
sections.push(['Batch 7d — Bootstrap Icons: Brand logos', brands, BRAND_ATTRS]);
sections.push(
  ['Batch 8a — Bootstrap Icons: Media & Playback', batch8a, OUTLINE_ATTRS],
  ['Batch 8b — Bootstrap Icons: Weather & Nature', batch8b, OUTLINE_ATTRS],
  ['Batch 8c — Bootstrap Icons: Emoji & Hands', batch8c, OUTLINE_ATTRS],
  ['Batch 8d — Bootstrap Icons: Buildings, Places & Transport', batch8d, OUTLINE_ATTRS],
  ['Batch 8e — Bootstrap Icons: Calendar, Books & Documents', batch8e, OUTLINE_ATTRS],
  ['Batch 8f — Bootstrap Icons: Health, Accessibility & Tools', batch8f, OUTLINE_ATTRS]
);

// ---- collision check against what is already shipped -----------------------
let css = fs.readFileSync(CSS, 'utf8');
const existing = new Set([...css.matchAll(/^\.ga\.ga-([a-z0-9-]+)\s*\{/gm)].map((m) => m[1]));

const allNew = [];
for (const [, defs] of sections.map((s) => [s[0], s[1]])) allNew.push(...Object.keys(defs));

const dupes = allNew.filter((n) => existing.has(n));
const selfDupes = allNew.filter((n, i) => allNew.indexOf(n) !== i);
if (dupes.length) throw new Error(`Would redefine existing icons: ${dupes.join(', ')}`);
if (selfDupes.length) throw new Error(`Duplicate names within new batches: ${selfDupes.join(', ')}`);

// ---- emit CSS --------------------------------------------------------------
// ga-icons.css is CRLF throughout; keep it that way.
const blocks = sections.map(([title, defs, attrs]) => {
  const lines = Object.entries(defs).map(([name, inner]) => rule(name, inner, attrs));
  return [`/* ======================================== ${title} ======================================== */`, ...lines].join('\r\n');
});

css = css.replace('/*! GreenAdmin Icons v1.0.1 |', '/*! GreenAdmin Icons v1.1.0 |');
css = css.trimEnd() + '\r\n' + blocks.join('\r\n') + '\r\n';
fs.writeFileSync(CSS, css);

// ---- extend the gallery array ---------------------------------------------
const chunk = (arr, n) => (arr.length ? [arr.slice(0, n), ...chunk(arr.slice(n), n)] : []);
const htmlBlocks = sections
  .map(([title, defs]) => {
    const names = Object.keys(defs);
    const rows = chunk(names, 6).map((row) => `      ${row.map((n) => `'${n}'`).join(',')},`);
    return `      // ${title}\n${rows.join('\n')}`;
  })
  .join('\n');

let html = fs.readFileSync(HTML, 'utf8');
const marker = `      'user-x','volume-1','volume-2','window'\n    ];`;
if (!html.includes(marker)) throw new Error('Could not locate the end of the gaIcons array');
html = html.replace(marker, `      'user-x','volume-1','volume-2','window',\n${htmlBlocks.replace(/,$/, '')}\n    ];`);
fs.writeFileSync(HTML, html);

console.log(`\nAdded ${allNew.length} icons across ${sections.length} batches.`);
for (const [title, defs] of sections) console.log(`  ${Object.keys(defs).length.toString().padStart(3)}  ${title}`);
