import { Type } from '@sinclair/typebox';
import type { ToolDefinition } from '@mariozechner/pi-coding-agent';
import type { SkillsService } from '../../skills/skills.service.js';

/**
 * Creates meta-tools that allow agents to list and invoke skills from the catalog.
 *
 * skill_list  — list all enabled skills
 * skill_invoke — execute a skill by name with parameters
 */
export function createSkillTools(skillsService: SkillsService): ToolDefinition[] {
  const skillList: ToolDefinition = {
    name: 'skill_list',
    label: 'List Skills',
    description:
      'List all enabled skills available in the catalog. Returns name, description, type, and config for each skill.',
    parameters: Type.Object({}),
    async execute() {
      const skills = await skillsService.findEnabled();
      const summary = skills.map((s) => ({
        name: s.name,
        description: s.description,
        version: s.version,
        source: s.source,
        config: s.config,
      }));
      return {
        content: [
          {
            type: 'text' as const,
            text:
              summary.length > 0
                ? JSON.stringify(summary, null, 2)
                : 'No enabled skills found in catalog.',
          },
        ],
        details: undefined,
      };
    },
  };

  const skillInvoke: ToolDefinition = {
    name: 'skill_invoke',
    label: 'Invoke Skill',
    description:
      'Invoke a skill from the catalog by name. For prompt skills, returns the prompt addition. ' +
      'For tool skills, executes the embedded logic. For workflow skills, returns the workflow steps.',
    parameters: Type.Object({
      name: Type.String({ description: 'Skill name to invoke' }),
      params: Type.Optional(
        Type.Record(Type.String(), Type.Unknown(), {
          description: 'Parameters to pass to the skill (if applicable)',
        }),
      ),
    }),
    async execute(_toolCallId, rawParams) {
      const { name, params } = rawParams as {
        name: string;
        params?: Record<string, unknown>;
      };

      const skill = await skillsService.findByName(name);
      if (!skill) {
        return {
          content: [{ type: 'text' as const, text: `Skill not found: ${name}` }],
          details: undefined,
        };
      }

      if (!skill.enabled) {
        return {
          content: [{ type: 'text' as const, text: `Skill is disabled: ${name}` }],
          details: undefined,
        };
      }

      const config = (skill.config ?? {}) as Record<string, unknown>;
      const skillType = (config['type'] as string | undefined) ?? 'prompt';

      switch (skillType) {
        case 'prompt': {
          const promptAddition =
            (config['prompt'] as string | undefined) ?? skill.description ?? '';
          return {
            content: [
              {
                type: 'text' as const,
                text: promptAddition
                  ? `[Skill: ${name}] ${promptAddition}`
                  : `[Skill: ${name}] No prompt content defined.`,
              },
            ],
            details: undefined,
          };
        }

        case 'tool': {
          const toolLogic = config['logic'] as string | undefined;
          if (!toolLogic) {
            return {
              content: [
                {
                  type: 'text' as const,
                  text: `[Skill: ${name}] Tool skill has no logic defined.`,
                },
              ],
              details: undefined,
            };
          }
          // Inline tool skill execution: the logic field holds a JS expression or template
          // For safety, treat it as a template that can reference params
          const result = renderTemplate(toolLogic, { params: params ?? {}, skill });
          return {
            content: [{ type: 'text' as const, text: `[Skill: ${name}]\n${result}` }],
            details: undefined,
          };
        }

        case 'workflow': {
          const steps = config['steps'] as unknown[] | undefined;
          if (!steps || steps.length === 0) {
            return {
              content: [
                {
                  type: 'text' as const,
                  text: `[Skill: ${name}] Workflow has no steps defined.`,
                },
              ],
              details: undefined,
            };
          }
          return {
            content: [
              {
                type: 'text' as const,
                text: `[Skill: ${name}] Workflow steps:\n${JSON.stringify(steps, null, 2)}`,
              },
            ],
            details: undefined,
          };
        }

        default: {
          // Unknown type — return full config so the agent can decide what to do
          return {
            content: [
              {
                type: 'text' as const,
                text: `[Skill: ${name}] (type: ${skillType})\n${JSON.stringify(config, null, 2)}`,
              },
            ],
            details: undefined,
          };
        }
      }
    },
  };

  return [skillList, skillInvoke];
}

/**
 * Minimal template renderer — replaces {{key}} with values from the context.
 * Used for tool skill logic templates.
 */
function renderTemplate(template: string, context: Record<string, unknown>): string {
  return template.replace(/\{\{(\w+(?:\.\w+)*)\}\}/g, (_match, path: string) => {
    const parts = path.split('.');
    let value: unknown = context;
    for (const part of parts) {
      if (value != null && typeof value === 'object') {
        value = (value as Record<string, unknown>)[part];
      } else {
        value = undefined;
        break;
      }
    }
    return value !== undefined && value !== null ? String(value) : '';
  });
}
