// src/install/Installer.ts
export type DetectResult =
  | { present: false; hint: string }
  | { present: true; version: string; minSatisfied: boolean; minRequired: string };

export interface InstallContext {
  proxyUrl: string;
  fewtokHome: string;
  dryRun: boolean;
  force: boolean;
}

export type ConfigShape = "toml" | "json" | "yaml";

export type ConfigMutation =
  | { op: "set"; path: string[]; value: unknown }
  | { op: "delete"; path: string[] }
  | { op: "merge"; path: string[]; value: Record<string, unknown> }
  | {
      op: "hook-array-merge";
      path: ["hooks", "PreToolUse" | "SessionStart" | "PostToolUse" | "Stop"];
      matcher?: string;
      dedupeBy: { kind: "command-equals"; command: string };
      entry: { type: "command"; command: string; timeout?: number };
      position?: "first" | "last";
    }
  | {
      op: "hook-array-delete";
      path: ["hooks", "PreToolUse" | "SessionStart" | "PostToolUse" | "Stop"];
      matcher?: string;
      predicate:
        | { kind: "command-suffix"; suffix: string }
        | { kind: "command-equals"; command: string }
        | { kind: "matcher-equals"; matcher: string };
    };

export type PlanStep =
  | { kind: "config-file"; path: string; shape: ConfigShape; mutations: ConfigMutation[] }
  | { kind: "wrapper"; symlink: string; target: string }
  | { kind: "env-var"; shellRc: string; name: string; value: string }
  | { kind: "hint-surface"; surfaceId: "claude-md" | "agents-md" };

export interface InstallPlan {
  installerId: string;
  fewtokHome: string;
  steps: PlanStep[];
}

export type StepReceipt =
  | { kind: "config-file"; path: string; backupPath: string; priorContent: string | null; postChecksum: string }
  | { kind: "wrapper"; symlink: string; existedBefore: boolean; priorTarget: string | null }
  | { kind: "env-var"; shellRc: string; lineRangeAdded: [number, number] }
  | { kind: "hint-surface"; surfaceId: "claude-md" | "agents-md" };

export interface InstallReceipt {
  installerId: string;
  version: number;
  appliedAt: string;
  steps: StepReceipt[];
}

export interface Finding {
  level: "ok" | "warn" | "error";
  message: string;
  remediation?: string;
}

export interface HealthReport {
  installerId: string;
  ok: boolean;
  findings: Finding[];
}

export interface Installer {
  readonly id: string;
  readonly displayName: string;
  detect(): Promise<DetectResult>;
  plan(ctx: InstallContext): Promise<InstallPlan>;
  apply(plan: InstallPlan): Promise<InstallReceipt>;
  revert(receipt: InstallReceipt, opts?: { force?: boolean }): Promise<void>;
  check(): Promise<HealthReport>;
}
