"use strict";

const fs = require("fs");
const path = require("path");
const os = require("os");
const {
  BRAND,
  SLATE,
  OK,
  WARN,
  ERR,
  MUTED,
  BOLD,
  RESET,
  lbl,
  ICONS,
} = require("./color-system");
const { shortenPath } = require("./helpers");
const { COMPONENT_REGISTRY, compNextCmd } = require("./components");
const { renderRowGrid, renderRowFlow } = require("./grid-renderer");
const { gitBranch, gitDirtyCount } = require("./data-gathering");

// ─── Layout Engine ─────────────────────────────────────────────────────────

const DEFAULT_LAYOUT = {
  rows: [
    {
      id: "r1",
      components: ["brand_version"],
      align: "grid",
    },
    {
      id: "r2",
      components: [
        "model_labeled",
        "protection",
        "project_type",
        "status",
        "lifecycle",
      ],
      align: "grid",
    },
    {
      id: "r3",
      components: [
        "context_combined",
        "tokens_io",
        "dev_rigor",
        "usage_time",
        "rate_limits",
      ],
      align: "grid",
    },
    {
      id: "r4",
      components: ["cost", "cache_hit", "style", "learning", "feature"],
      align: "grid",
    },
  ],
};

/** Load statusline config from disk, validate version. */
function loadConfig() {
  const configPath = path.join(
    os.homedir(),
    ".claude",
    "evolv-coder-kit",
    "statusline-config.json",
  );
  try {
    if (!fs.existsSync(configPath)) return null;
    const config = JSON.parse(fs.readFileSync(configPath, "utf-8"));
    if (config.version !== 1) return null;
    return config;
  } catch {
    return null;
  }
}

/** Placeholder for unknown/null components — renders as a dash. */
const PLACEHOLDER_COMPONENT = { vis: "\u2014", out: MUTED("\u2014") };

/** Collect component arrays for configurable rows (R1-R3 or custom). */
function collectConfigRows(layout, dataBag) {
  const rows = [];
  for (const row of layout.rows) {
    const components = row.components.map((name) => {
      const fn = COMPONENT_REGISTRY[name];
      if (!fn) return PLACEHOLDER_COMPONENT;
      return fn(dataBag) || PLACEHOLDER_COMPONENT;
    });
    rows.push(components);
  }
  return rows;
}

/** Legacy: render config rows individually (for custom flow layouts). */
function renderConfigRows(layout, dataBag, termWidth) {
  const lines = [];
  for (const row of layout.rows) {
    const components = row.components.map((name) =>
      COMPONENT_REGISTRY[name] ? COMPONENT_REGISTRY[name](dataBag) : null,
    );
    const rendered =
      row.align === "flow"
        ? renderRowFlow(components)
        : renderRowGrid(components, termWidth);
    if (rendered) lines.push(rendered);
  }
  return lines;
}

/** Build grid-compatible components for a directory row. */
function makeDirComponents(
  label,
  dirPath,
  branch,
  dirty,
  icon,
  linesAdded,
  linesRemoved,
  extraComp,
) {
  const dirComp = {
    vis: `${label}: ${dirPath}`,
    out: `${lbl(`${icon}${label}:`)} ${dirPath}`,
  };
  const rawBranch = branch || "\u2014";
  // Long branch names dominate the col-2 natural width and force the whole
  // table into the overflow path. Cap at 30 chars with an ellipsis so the
  // branch column stays a sane width across most terminals.
  const BRANCH_MAX = 30;
  const branchStr =
    rawBranch.length > BRANCH_MAX
      ? rawBranch.slice(0, BRANCH_MAX - 1) + "\u2026"
      : rawBranch;
  const branchComp = {
    vis: `Branch: ${branchStr}`,
    out: `${lbl(`${ICONS.branch}Branch:`)} ${SLATE(`${BOLD}${branchStr}`)}${RESET}`,
  };
  let dirtyComp;
  if (!dirty || dirty === 0 || dirty === "0") {
    dirtyComp = {
      vis: "Files: Clean",
      out: `${lbl(`${ICONS.dirty}Files:`)} ${OK("Clean")}`,
    };
  } else {
    dirtyComp = {
      vis: `Files: ${dirty} Changed`,
      out: `${lbl(`${ICONS.dirty}Files:`)} ${WARN(`${BOLD}${dirty}`)}${RESET} ${MUTED("Changed")}`,
    };
  }
  let linesComp;
  const la = linesAdded || 0;
  const lr = linesRemoved || 0;
  if (la > 0 || lr > 0) {
    linesComp = {
      vis: `Lines: +${la}/-${lr}`,
      out: `${lbl(`${ICONS.files}Lines:`)} ${OK(`${BOLD}+${la}`)}${RESET}${MUTED("/")}${ERR(`${BOLD}-${lr}`)}${RESET}`,
    };
  } else {
    linesComp = {
      vis: "Lines: \u2014",
      out: `${lbl(`${ICONS.files}Lines:`)} ${MUTED("\u2014")}`,
    };
  }
  const result = [dirComp, branchComp, dirtyComp, linesComp];
  if (extraComp) result.push(extraComp);
  return result;
}

/** Collect component arrays for directory rows (project, current, added dirs). */
function collectDirRows(dataBag) {
  const rows = [];

  const {
    projectDir,
    projectDirShort,
    projectBranch,
    projectDirty,
    currentDir,
    currentDirShort,
    currentBranch,
    currentDirty,
    addedDirs,
    stdinProjectDir,
    stdinCwd,
    linesAdded,
    linesRemoved,
  } = dataBag;

  // Compute next_cmd for first dir row's C5
  const nextCmdComp = compNextCmd(dataBag) || PLACEHOLDER_COMPONENT;

  let showCurrentRow = true;

  if (projectDir) {
    rows.push(
      makeDirComponents(
        "Project",
        projectDirShort,
        projectBranch,
        projectDirty,
        ICONS.project,
        linesAdded,
        linesRemoved,
        nextCmdComp,
      ),
    );
    if (stdinProjectDir === stdinCwd) {
      showCurrentRow = false;
    }
  } else {
    rows.push(
      makeDirComponents(
        "Current",
        currentDirShort,
        currentBranch,
        currentDirty,
        ICONS.folder,
        linesAdded,
        linesRemoved,
        nextCmdComp,
      ),
    );
    showCurrentRow = false;
  }

  if (showCurrentRow) {
    rows.push(
      makeDirComponents(
        "Current",
        currentDirShort,
        currentBranch,
        currentDirty,
        ICONS.folder,
        undefined,
        undefined,
        PLACEHOLDER_COMPONENT,
      ),
    );
  }

  if (addedDirs && addedDirs.length > 0) {
    for (const dir of addedDirs) {
      const short = shortenPath(dir, dataBag.pathMax || 40);
      const branch = gitBranch(dir);
      const dirty = gitDirtyCount(dir);
      rows.push(
        makeDirComponents(
          "Added",
          short,
          branch,
          dirty,
          ICONS.folder,
          undefined,
          undefined,
          PLACEHOLDER_COMPONENT,
        ),
      );
    }
  }

  return rows;
}

/** Legacy wrapper for backward compatibility with tests. */
function renderDirRows(dataBag) {
  const rows = collectDirRows(dataBag);
  const tw = dataBag.termWidth || 80;
  return rows.map((comps) => renderRowGrid(comps, tw)).filter(Boolean);
}

module.exports = {
  DEFAULT_LAYOUT,
  loadConfig,
  PLACEHOLDER_COMPONENT,
  collectConfigRows,
  renderConfigRows,
  makeDirComponents,
  collectDirRows,
  renderDirRows,
};
