const WEIGHT_RANK = { light: 0, medium: 1, heavy: 2 };
const WEIGHT_EMOJI = { light: "🟢", medium: "🟡", heavy: "🔴" };

function applyFileThresholdSignals(classification, matrix) {
  const estimated = classification?.signals?.estimated_files;
  if (!estimated || !matrix?.classification?.file_thresholds) return classification;
  const next = { ...classification, reasons: [...(classification.reasons || [])] };
  const thresholds = matrix.classification.file_thresholds;
  if (estimated >= (thresholds.heavy || Number.MAX_SAFE_INTEGER)) {
    next.reasons.push(`file_threshold:heavy(${estimated})`);
  } else if (estimated >= (thresholds.medium || Number.MAX_SAFE_INTEGER)) {
    next.reasons.push(`file_threshold:medium(${estimated})`);
  } else {
    next.reasons.push(`file_threshold:light(${estimated})`);
  }
  return next;
}

function skillStatus(name, registry, installed, disabled = new Set()) {
  if (disabled.has("*") || disabled.has(name)) return "disabled";
  if (!installed.includes(name)) return "not_installed";
  for (const cat of ["core", "recommended", "optional", "project_added"]) {
    if ((registry[cat] || []).includes(name)) return cat;
  }
  return "on_disk";
}

function collectSkills(text, matrix, classification, matchKeywords) {
  const skills = new Set();
  let workflow = null;
  let rulesHint = null;
  const order = matrix?.resolver_order || ["exact_keyword", "domain_rules", "classification_default"];

  if (order.includes("exact_keyword") && classification.taskType) {
    for (const s of classification.taskType.skills || []) skills.add(s);
    workflow = classification.taskType.workflow || null;
    rulesHint = classification.taskType.rules_hint || null;
  }

  if (order.includes("domain_rules")) {
    for (const tt of matrix.task_types || []) {
      if (matchKeywords(text, tt.keywords || [])) {
        for (const s of tt.skills || []) skills.add(s);
        if (tt.workflow) workflow = tt.workflow;
        if (tt.rules_hint) rulesHint = tt.rules_hint;
      }
    }
    for (const [ruleFile, meta] of Object.entries(matrix.rules_domain_map || {})) {
      const domain = ruleFile.replace("rules/", "").replace(".md", "");
      if (matchKeywords(text, [domain, ...domain.split("-")])) {
        const minWeight = meta.weight_min || "light";
        if (WEIGHT_RANK[classification.weight] >= WEIGHT_RANK[minWeight]) {
          for (const s of meta.skills || []) skills.add(s);
          rulesHint = rulesHint || ruleFile;
        }
      }
    }
  }

  if (order.includes("classification_default") && !skills.size) skills.add("capability-router");
  return { skills: [...skills], workflow, rulesHint };
}

function deriveProviders(taskType, skills, workflow) {
  if (taskType?.providers?.length) return taskType.providers;
  const providers = [];
  if (workflow) providers.push({ name: "workflow", type: "workflow", resource: workflow.replace(/^\//, ""), confidence_base: 0.8 });
  if (skills?.length) providers.push({ name: "skill", type: "skill", resource: skills[0], confidence_base: 0.75 });
  if (!providers.length) providers.push({ name: "fallback", type: "skill", resource: "capability-router", confidence_base: 0.5 });
  return providers;
}

function pickProvider(providers, resolverOrder = []) {
  const sorted = [...providers].sort((a, b) => (b.confidence_base || 0) - (a.confidence_base || 0));
  if (!resolverOrder.length) return sorted[0];
  for (const rule of resolverOrder) {
    if (rule === "exact_keyword") {
      const s = sorted.find((p) => p.type === "skill");
      if (s) return s;
    }
    if (rule === "domain_rules") {
      const w = sorted.find((p) => p.type === "workflow");
      if (w) return w;
    }
    if (rule === "classification_default") return sorted[0];
  }
  return sorted[0];
}

function routeCapability(parsedIntent, matrix, registry, installed, matchKeywords, disabled = new Set()) {
  const rows = parsedIntent.segments.map((segment) => {
    const classified = applyFileThresholdSignals(segment.classification, matrix);
    const { skills, workflow, rulesHint } = collectSkills(segment.text, matrix, classified, matchKeywords);
    return {
      index: segment.index,
      subtask: segment.text,
      weight: classified.weight,
      emoji: WEIGHT_EMOJI[classified.weight],
      reason: classified.reasons.join("; "),
      skills: skills.map((name) => ({ name, status: skillStatus(name, registry, installed, disabled) })),
      workflow,
      rulesHint,
      taskType: classified.taskType || null
    };
  });

  let overall = "light";
  for (const r of rows) if (WEIGHT_RANK[r.weight] > WEIGHT_RANK[overall]) overall = r.weight;
  if (rows.length >= 2 && WEIGHT_RANK[overall] < WEIGHT_RANK.medium) overall = matrix.classification.multi_item_bundle_min || "medium";

  const showPlan = overall !== "light" || rows.length >= 2 || matchKeywords(parsedIntent.rawText, ["skill plan", "which skill", "plan_first"]);
  const taskTypeResolved = rows.find((r) => r.taskType)?.taskType || null;
  const providers = deriveProviders(taskTypeResolved, rows[0]?.skills?.map((s) => s.name) || [], rows[0]?.workflow || null);
  const winner = pickProvider(providers, matrix?.resolver_order || []);

  return { rows, overall, showPlan, taskTypeResolved, providers, winner, confidence: winner?.confidence_base || 0 };
}

module.exports = { routeCapability };
