import React from "react";
import type { ToolInputDefinition, ToolInput } from "../io/input-types";
import type { ToolOutputDefinition, ToolResult } from "../io/output-types";

export type ToolCategory =
  | "image"
  | "pdf"
  | "text"
  | "developer"
  | "crypto"
  | "conversion"
  | "privacy";

export interface ToolManifest {
  id: string;
  name: string;
  description: string;
  category: ToolCategory;
  version: string;

  input: ToolInputDefinition;
  output: ToolOutputDefinition;

  tags?: string[];
  icon?: string;
  example?: string;
  offlineReady: boolean;
}

export type ToolOptionField =
  | {
      type: "text";
      key: string;
      label: string;
      defaultValue?: string;
      placeholder?: string;
    }
  | {
      type: "number";
      key: string;
      label: string;
      defaultValue: number;
      min?: number;
      max?: number;
      step?: number;
    }
  | {
      type: "boolean";
      key: string;
      label: string;
      defaultValue: boolean;
    }
  | {
      type: "select";
      key: string;
      label: string;
      defaultValue: string;
      options: Array<{
        label: string;
        value: string;
      }>;
    }
  | {
      type: "slider";
      key: string;
      label: string;
      defaultValue: number;
      min: number;
      max: number;
      step?: number;
    };

export interface ToolOptionsSchema {
  fields: ToolOptionField[];
}

export type ToolOptionValue = string | number | boolean;
export type ToolOptionsValue = Record<string, ToolOptionValue>;

export interface ToolCapabilities {
  batch?: boolean;
  worker?: boolean;
  /** Keep the worker alive between runs so it can retain expensive state. */
  persistentWorker?: boolean;
  wasm?: boolean;
  preview?: boolean;
  streaming?: boolean;
  cancelable?: boolean;
  customUi?: boolean;
}

export interface ToolPermissions {
  network: "none" | "optional" | "required";
  clipboard?: "none" | "read" | "write" | "read-write";
  fileSystem?: "none" | "read" | "write" | "read-write";
}

export interface ToolProgress {
  percentage?: number;
  message?: string;
}

export interface ToolExample<TOptions = unknown> {
  label?: string;
  description?: string;
  input: ToolInput;
  options?: Partial<TOptions>;
}

export interface ToolContext {
  signal: AbortSignal;
  reportProgress: (progress: ToolProgress) => void;
  logger: {
    info: (message: string) => void;
    warn: (message: string) => void;
    error: (message: string) => void;
  };
}

export type ToolRunner<TOptions = unknown> = (
  input: ToolInput,
  options: TOptions,
  context: ToolContext
) => Promise<ToolResult>;

export interface ToolUiProps<TOptions = unknown> {
  plugin: PlimiPlugin<TOptions>;
  dark?: boolean;
  examples?: ToolExample<TOptions>[];
}

export interface PlimiPlugin<TOptions = unknown> {
  manifest: ToolManifest;
  optionsSchema?: ToolOptionsSchema;
  examples?: ToolExample<TOptions>[];
  capabilities?: ToolCapabilities;
  permissions?: ToolPermissions;

  run?: ToolRunner<TOptions>;

  worker?: () => Worker;

  /**
   * Optional pre-run check. Return a message to surface a confirmation dialog
   * before the tool runs (e.g. "this will download 44 MB"); return null to run
   * immediately. Runs on the main thread, so it can inspect caches/storage.
   */
  getRunWarning?: (
    input: ToolInput,
    options: TOptions
  ) => Promise<string | null> | string | null;

  customUi?: React.LazyExoticComponent<
    React.ComponentType<ToolUiProps<TOptions>>
  >;
}

export type UnknownPlimiPlugin = Omit<
  PlimiPlugin<never>,
  "run" | "customUi" | "getRunWarning"
> & {
  run?: ToolRunner<ToolOptionsValue>;
  examples?: ToolExample<ToolOptionsValue>[];
  getRunWarning?: (
    input: ToolInput,
    options: ToolOptionsValue
  ) => Promise<string | null> | string | null;
  customUi?: React.LazyExoticComponent<
    React.ComponentType<ToolUiProps<ToolOptionsValue>>
  >;
};
