import { createSignal, onCleanup, createMemo } from "solid-js";
import { existsSync, readFileSync } from "fs";
import { homedir } from "os";
import { join } from "path";

// ── Config reader (no external deps) ───────────────────────────────────────

interface InfinicodeConfig {
  masterUrl: string;
  defaultModel: string;
  policy?: string;
  workerModels?: Record<string, { providerId: string; modelId: string }>;
  cloudProviders?: Array<{ id: string; name: string; enabled: boolean; apiKey?: string }>;
}

function findConfigPath(): string {
  const home = homedir();
  const paths = [
    // Windows — Conf appends "-nodejs" for Node projects
    join(home, "AppData", "Roaming", "infinicode-nodejs", "Config", "config.json"),
    join(home, "AppData", "Roaming", "infinicode", "Config", "config.json"),
    // Linux
    join(home, ".config", "infinicode", "config.json"),
    // macOS
    join(home, "Library", "Preferences", "infinicode", "config.json"),
  ];
  for (const p of paths) {
    if (existsSync(p)) return p;
  }
  return paths[0];
}

function loadConfig(): InfinicodeConfig | null {
  try {
    const path = findConfigPath();
    if (!existsSync(path)) return null;
    return JSON.parse(readFileSync(path, "utf-8")) as InfinicodeConfig;
  } catch {
    return null;
  }
}

// ── Routing info ───────────────────────────────────────────────────────────

// Every policy auto-routes across providers except `offline`, which is locked
// to the local machine — mirrors the kernel router's one locked mode.
const LOCKED_POLICIES = new Set(["offline"]);

interface RoutingBadge {
  glyph: string;
  text: string;
  /** true = actively auto-routing (drives the pulse highlight). */
  active: boolean;
}

function buildRoutingBadge(cfg: InfinicodeConfig | null, tuiModel?: string): RoutingBadge {
  if (!cfg) return { glyph: "◆", text: "AUTO (no config)", active: true };

  const enabledCloud = (cfg.cloudProviders ?? []).filter((p) => p.enabled && p.apiKey);
  const providerCount = 1 + enabledCloud.length; // ollama + cloud
  const pinned = Object.keys(cfg.workerModels ?? {}).length;
  const policy = cfg.policy ?? "balanced";
  const codingPin = cfg.workerModels?.["coding"];
  const autoModel = codingPin
    ? `${codingPin.providerId}/${codingPin.modelId}`
    : `ollama/${cfg.defaultModel}`;

  // If the user manually pinned a model in the TUI, that overrides routing.
  if (tuiModel && tuiModel !== autoModel) {
    const [prov, ...rest] = tuiModel.split("/");
    return { glyph: "◇", text: `SINGLE ${prov}/${rest.join("/")}`, active: false };
  }

  // The one locked mode: offline stays local-only.
  if (LOCKED_POLICIES.has(policy)) {
    return { glyph: "🔒", text: `LOCKED ${policy} (local only)`, active: false };
  }

  return {
    glyph: "◆",
    text: `AUTO policy=${policy} providers=${providerCount} pins=${pinned}`,
    active: true,
  };
}

// ── Plugin ──────────────────────────────────────────────────────────────────

const tui = async (api: any) => {
  const [cfg] = createSignal(loadConfig());

  const getTuiModel = (): string | undefined => {
    try {
      return api.state?.config?.model;
    } catch {
      return undefined;
    }
  };

  const [tuiModel, setTuiModel] = createSignal<string | undefined>(getTuiModel());

  if (api.event?.on) {
    const unsub = api.event.on("session.next.model_switched", () => {
      setTuiModel(getTuiModel());
    });
    onCleanup(unsub);
  }

  const badge = createMemo(() => buildRoutingBadge(cfg(), tuiModel()));

  // Pulse the highlight color while auto-routing is active so the badge reads
  // as "live". Static gold when locked / single-pinned.
  const PULSE = ["#FFD86B", "#FFE9A6", "#F5C542"];
  const [pulse, setPulse] = createSignal(0);
  const timer = setInterval(() => setPulse((i) => (i + 1) % PULSE.length), 600);
  onCleanup(() => clearInterval(timer));

  const color = () => (badge().active ? PULSE[pulse()] : "#FFD86B");
  const render = () => (
    <text fg={color()}>{`${badge().glyph} ${badge().text}`}</text>
  );

  api.slots.register({
    slots: {
      // Right of the home prompt — routing badge
      home_prompt_right() {
        return render();
      },

      // Right of the session prompt — routing badge
      session_prompt_right(props: { session_id: string }) {
        return render();
      },
    },
  });
};

// The TUI plugin loader reads `mod.default` (strict mode) and requires an object
// with a tui() function — a bare `export const tui` is silently skipped.
export default { id: "infinicode-routing-mode", tui };