// Derive content classification, list ordering and path building from a site's
// `config.collections` (see ../../README.md). Pure functions — no config import,
// no filesystem — so they unit-test against any collections array directly.
//
// Fed `examples/openbureau.config.js` these reproduce the engine's original
// hard-coded archiv/library/rubrik/seite behaviour 1:1.

// Parse a `path` pattern ('archiv/:section/:slug') into segments.
function parsePattern(pattern) {
  return pattern.split('/').map((seg) =>
    seg.startsWith(':') ? { param: seg.slice(1) } : { literal: seg });
}

// Match a content rel-path's segments (no .md) against a `path` pattern.
// Returns captured params, or null. Strict: the segment count must equal the
// pattern's, so 'archiv/:section/:slug' matches exactly three deep — the same
// rule the original classify() enforced for archiv.
function matchPattern(segs, pattern) {
  const pat = parsePattern(pattern);
  if (segs.length !== pat.length) return null;
  const params = {};
  for (let i = 0; i < pat.length; i++) {
    if (pat[i].literal !== undefined) {
      if (pat[i].literal !== segs[i]) return null;
    } else {
      if (!segs[i]) return null;
      params[pat[i].param] = segs[i];
    }
  }
  return params;
}

// First literal segment of a pattern (e.g. 'library' from 'library/:slug').
function rootSegment(pattern) {
  const first = pattern.split('/')[0];
  return first.startsWith(':') ? null : first;
}

// { kind, section } for a content file, derived from collections.
// Priority: index (_index.md) → path patterns → fallback — mirrors the original
// hard-coded classify() when fed openbureau.config.js.
export function classify(rel, collections) {
  const parts = rel.split('/');
  const base = parts[parts.length - 1];
  const segs = rel.replace(/\.md$/, '').split('/');

  // _index.md → the index collection; section = parent dir (or 'home' at root).
  if (base === '_index.md') {
    const idx = collections.find((c) => c.index);
    if (idx) {
      const section = parts.length >= 2 ? parts[parts.length - 2] : 'home';
      return { kind: idx.kind, section };
    }
  }

  // path-pattern collections (skip index/fallback).
  for (const c of collections) {
    if (!c.path || c.index || c.fallback) continue;
    const params = matchPattern(segs, c.path);
    if (params) {
      const section = params.section ?? rootSegment(c.path);
      return { kind: c.kind, section: section ?? null };
    }
  }

  // fallback collection (everything not otherwise matched).
  const fb = collections.find((c) => c.fallback);
  return { kind: fb ? fb.kind : null, section: null };
}

// Sort comparator for listEntries: collection `order`, then date desc, then title.
export function compareEntries(collections) {
  const order = {};
  collections.forEach((c, i) => { order[c.kind] = c.order ?? 100 + i; });
  return (a, b) =>
    ((order[a.kind] ?? 999) - (order[b.kind] ?? 999)) ||
    (b.date || '').localeCompare(a.date || '') ||
    a.title.localeCompare(b.title);
}

// Build a content rel-path for a NEW entry of `kind` from form `data`.
// Index collection → '<slug>/_index.md'; a collection without a `path` (fallback)
// → '<slug>.md'; otherwise substitute :params in the collection's `path`
// (archiv/:section/:slug → archiv/<section>/<slug>.md). Returns '' if a required
// segment is missing.
export function buildPath(kind, data, collections) {
  const c = collections.find((x) => x.kind === kind);
  const slug = String(data.slug || '').trim();
  if (c?.index) return slug ? `${slug}/_index.md` : '';
  if (!c?.path) return slug ? `${slug}.md` : '';
  let ok = true;
  const rel = c.path.split('/').map((seg) => {
    if (!seg.startsWith(':')) return seg;
    const v = String(data[seg.slice(1)] || '').trim();
    if (!v) ok = false;
    return v;
  }).join('/');
  return ok && rel ? `${rel}.md` : '';
}

// Build the stats `content` object from classified entries + collections:
// one counter per collection.statKey, plus a drafts counter for any collection
// that declares `draftStatKey`. Mirrors the original hard-coded stats block
// (beitraege/entwuerfe/library/seiten/rubriken) when fed openbureau.config.js.
export function contentStats(entries, collections) {
  const content = {};
  for (const c of collections) {
    if (c.statKey) content[c.statKey] ??= 0;
    if (c.draftStatKey) content[c.draftStatKey] ??= 0;
  }
  const byKind = Object.fromEntries(collections.map((c) => [c.kind, c]));
  for (const e of entries) {
    const c = byKind[e.kind];
    if (!c) continue;
    if (c.statKey) content[c.statKey]++;
    if (c.draftStatKey && e.draft) content[c.draftStatKey]++;
  }
  return content;
}
