import { invoke } from "@tauri-apps/api/core";
import type { FsReadResult, FsReadPortionResult } from "@/lib/ipc";

/** @deprecated Import `FsReadResult` from `@/lib/ipc` instead. */
export type ReadResult = FsReadResult;
/** @deprecated Import `FsReadPortionResult` from `@/lib/ipc` instead. */
export type ReadPortionResult = FsReadPortionResult;

export type DirEntry = {
  name: string;
  kind: "file" | "dir" | "symlink";
  size: number;
  mtime: number;
};

export type CommandOutput = {
  stdout: string;
  stderr: string;
  exit_code: number | null;
  timed_out: boolean;
  truncated: boolean;
};

export type GrepHit = {
  path: string;
  rel: string;
  line: number;
  text: string;
};

export type GrepResponse = {
  hits: GrepHit[];
  truncated: boolean;
  files_scanned: number;
};

export type GlobHit = { path: string; rel: string };
export type GlobResponse = { hits: GlobHit[]; truncated: boolean };

export type GrepReplaceEdit = { path: string; rel: string; replacements: number };
export type GrepReplaceResponse = {
  files_changed: number;
  total_replacements: number;
  edits: GrepReplaceEdit[];
  truncated: boolean;
};

export const native = {
  readFile: (path: string) => invoke<ReadResult>("fs_read_file", { path }),
  readFilePortion: (path: string, offset?: number, limit?: number) =>
    invoke<ReadPortionResult>("fs_read_file_portion", {
      path,
      offset: offset ?? null,
      limit: limit ?? null,
    }),
  writeFile: (path: string, content: string) => invoke<void>("fs_write_file", { path, content }),
  createFile: (path: string) => invoke<void>("fs_create_file", { path }),
  createDir: (path: string) => invoke<void>("fs_create_dir", { path }),
  deletePath: (path: string) => invoke<void>("fs_delete", { path }),
  /** Move/rename a path. Backend refuses to overwrite an existing target. */
  rename: (from: string, to: string) => invoke<void>("fs_rename", { from, to }),
  /** Copy a file/dir (recursive). Backend refuses to overwrite an existing target. */
  copy: (from: string, to: string) => invoke<void>("fs_copy", { from, to }),
  readDir: (path: string) => invoke<DirEntry[]>("fs_read_dir", { path }),
  /** Resolve symlinks to the real absolute path. Throws if the path is missing. */
  canonicalize: (path: string) => invoke<string>("fs_canonicalize", { path }),
  grep: (params: {
    pattern: string;
    root: string;
    glob?: string[];
    caseInsensitive?: boolean;
    maxResults?: number;
  }) =>
    invoke<GrepResponse>("fs_grep", {
      pattern: params.pattern,
      root: params.root,
      glob: params.glob ?? null,
      caseInsensitive: params.caseInsensitive ?? null,
      maxResults: params.maxResults ?? null,
    }),
  glob: (params: { pattern: string; root: string; maxResults?: number }) =>
    invoke<GlobResponse>("fs_glob", {
      pattern: params.pattern,
      root: params.root,
      maxResults: params.maxResults ?? null,
    }),
  grepReplace: (params: {
    pattern: string;
    replacement: string;
    root: string;
    glob?: string[];
    caseInsensitive?: boolean;
  }) =>
    invoke<GrepReplaceResponse>("fs_grep_replace", {
      pattern: params.pattern,
      replacement: params.replacement,
      root: params.root,
      glob: params.glob ?? null,
      caseInsensitive: params.caseInsensitive ?? null,
    }),
  runCommand: (command: string, cwd?: string | null, timeoutSecs?: number) =>
    invoke<CommandOutput>("shell_run_command", {
      command,
      cwd: cwd ?? null,
      timeoutSecs: timeoutSecs ?? null,
    }),

  shellSessionOpen: (cwd?: string | null) =>
    invoke<number>("shell_session_open", { cwd: cwd ?? null }),
  shellSessionRun: (id: number, command: string, cwd?: string | null, timeoutSecs?: number) =>
    invoke<{
      stdout: string;
      stderr: string;
      exit_code: number | null;
      timed_out: boolean;
      truncated: boolean;
      cwd_after: string;
    }>("shell_session_run", {
      id,
      command,
      cwd: cwd ?? null,
      timeoutSecs: timeoutSecs ?? null,
    }),
  shellSessionClose: (id: number) => invoke<void>("shell_session_close", { id }),
  shellBgSpawn: (command: string, cwd?: string | null) =>
    invoke<number>("shell_bg_spawn", { command, cwd: cwd ?? null }),
  shellBgLogs: (handle: number, sinceOffset?: number) =>
    invoke<{
      bytes: string;
      next_offset: number;
      dropped: number;
      exited: boolean;
      exit_code: number | null;
    }>("shell_bg_logs", { handle, sinceOffset: sinceOffset ?? null }),
  shellBgKill: (handle: number) => invoke<void>("shell_bg_kill", { handle }),
  shellBgRemove: (handle: number) => invoke<void>("shell_bg_remove", { handle }),
  shellBgList: () =>
    invoke<
      {
        handle: number;
        command: string;
        cwd: string | null;
        started_at_ms: number;
        exited: boolean;
        exit_code: number | null;
      }[]
    >("shell_bg_list"),
};
