import { Static, TSchema } from '@sinclair/typebox';
import type { RuntimeProcessEventInput } from '../runtime/process_events.js';

// --- 工具接口 ---

export type ToolProcessUpdateCallback = (event: RuntimeProcessEventInput) => void;

export type AgentTool<TParams extends TSchema, TResult> = {
  name: string;
  label: string;
  description: string;
  parameters: TParams;
  execute(id: string, params: Static<TParams>, onUpdate?: ToolProcessUpdateCallback): Promise<TResult>;
};

export type ToolVisibility = 'internal' | 'tool' | 'skill';

export type AgentToolWithMeta<TParams extends TSchema, TResult> =
  AgentTool<TParams, TResult> & {
    ownerOnly?: boolean;
    displaySummary?: string;
    visibility?: ToolVisibility;
  };

export type AnyAgentTool = AgentToolWithMeta<any, unknown>;

// --- 工具结果 ---

export interface ImageItem {
  url: string;
  mimeType?: string;
  label?: string;
  purpose?: string;
  reason?: string;
  damageId?: string;
  timestamp?: number;
  width?: number;
  height?: number;
  seed?: number;
}

export type ToolResultContent =
  | { type: 'text'; text: string }
  | { type: 'json'; data: unknown }
  | {
      type: 'image';
      url: string;
      mimeType?: string;
      text?: string;
      width?: number;
      height?: number;
      bytes?: number;
      originalWidth?: number;
      originalHeight?: number;
      originalBytes?: number;
      resized?: boolean;
    }
  | { type: 'images'; images: ImageItem[]; text?: string };

export function textResult(text: string): ToolResultContent {
  return { type: 'text', text };
}

export function jsonResult(data: unknown): ToolResultContent {
  return { type: 'json', data };
}

export function imageResult(
  url: string,
  mimeType?: string,
  metadata?: Omit<Extract<ToolResultContent, { type: 'image' }>, 'type' | 'url' | 'mimeType'>,
): ToolResultContent {
  return { type: 'image', url, mimeType, ...metadata };
}

export function imagesResult(
  images: ImageItem[],
  text?: string,
): ToolResultContent {
  return { type: 'images', images, text };
}

export function toolResultToText(result: unknown): string {
  if (typeof result === 'string') {
    return result;
  }
  if (!result || typeof result !== 'object') {
    return JSON.stringify(result);
  }

  const value = result as ToolResultContent;
  if (value.type === 'text') {
    return value.text;
  }
  if (value.type === 'json') {
    return JSON.stringify(value.data);
  }
  if (value.type === 'image') {
    if (value.text) return value.text;
    const lines = [value.mimeType ? `Read image file [${value.mimeType}]` : 'Read image file'];
    if (value.width && value.height) {
      lines.push(`Dimensions: ${value.width}x${value.height}`);
    }
    if (value.bytes) {
      lines.push(`Size: ${value.bytes} bytes`);
    }
    if (value.resized && value.originalWidth && value.originalHeight) {
      lines.push(`Original: ${value.originalWidth}x${value.originalHeight}`);
    }
    return lines.join('\n');
  }
  if (value.type === 'images') {
    const imgs = (value as { type: 'images'; images: ImageItem[]; text?: string });
    const lines = imgs.images.map((img, i) =>
      `[图${i + 1}] ${img.url}${img.width && img.height ? ` (${img.width}x${img.height})` : ''}`
    );
    const header = imgs.text || `已生成 ${lines.length} 张图片`;
    return `${header}\n${lines.join('\n')}`;
  }

  return JSON.stringify(result);
}

// --- 工具错误 ---

export class ToolInputError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'ToolInputError';
  }
}

export class ToolAuthorizationError extends Error {
  constructor(message: string) {
    super(message);
    this.name = 'ToolAuthorizationError';
  }
}

// --- 参数读取辅助 ---

export function readStringParam(params: Record<string, unknown>, key: string): string {
  const val = params[key];
  if (typeof val !== 'string') throw new ToolInputError(`参数 "${key}" 必须是字符串`);
  return val;
}

export function readOptionalStringParam(params: Record<string, unknown>, key: string): string | undefined {
  const val = params[key];
  if (val === undefined || val === null) return undefined;
  if (typeof val !== 'string') throw new ToolInputError(`参数 "${key}" 必须是字符串`);
  return val;
}
