import { randomUUID } from "node:crypto";
import type { AgentDiscipline, OpenClawApi } from "../types.js";
import type { Skill, SkillScore, SkillStep, TaskPattern } from "./types.js";

/** Local LLM service interface — matches the old OpenClaw LlmService shape. */
interface LlmService {
  complete(request: { model: string; messages: Array<{ role: string; content: string }>; max_tokens?: number; temperature?: number }): Promise<{ content: string }>;
}

const THIRTY_DAYS_MS = 30 * 24 * 60 * 60 * 1000;
const MAX_COMPLEXITY_STEPS = 10;
const MAX_USAGE_FOR_SCORE = 10;

function generateId(): string {
  return `skill-${Date.now().toString(36)}-${randomUUID()}`;
}

export class SkillEvolver {
  constructor(private api: OpenClawApi) {}

  async evaluateAndGenerate(
    pattern: TaskPattern,
    context: Record<string, unknown>,
  ): Promise<Skill | null> {
    let llm: LlmService;
    try {
      llm = this.api.services.get<LlmService>("openclaw.llm");
    } catch (e) { console.warn(`error: ${e}`);
      return this.generateFromPattern(pattern, context);
    }

    const prompt = this.buildEvaluationPrompt(pattern, context);

    try {
      const response = await llm.complete({
        model: "claude-3-sonnet",
        max_tokens: 2048,
        temperature: 0.4,
        messages: [
          {
            role: "system",
            content:
              "You are a skill analyst for an AI agent workflow system. " +
              "Analyze workflow patterns and determine if they should be captured as reusable skills. " +
              "Respond ONLY with valid JSON, no markdown fences.",
          },
          { role: "user", content: prompt },
        ],
      });

      return this.parseLlmResponse(response.content, pattern);
    } catch (e) { console.warn(`error: ${e}`);
      return this.generateFromPattern(pattern, context);
    }
  }

  generateSKILLMd(skill: Skill): string {
    const stepsSection = skill.steps
      .map((step, i) => {
        const paramLines = Object.entries(step.params)
          .map(([k, v]) => `  - \`${k}\`: ${String(v)}`)
          .join("\n");
        return (
          `### ${i + 1}. ${step.name}\n\n` +
          `- **Discipline**: ${step.discipline}\n` +
          `- **Action**: ${step.action}\n` +
          (paramLines ? `- **Parameters**:\n${paramLines}\n` : "")
        );
      })
      .join("\n");

    return [
      `# ${skill.name}\n`,
      `> ${skill.description}\n`,
      `| Property | Value |`,
      `|----------|-------|`,
      `| ID | \`${skill.id}\` |`,
      `| Discipline | ${skill.discipline} |`,
      `| Success Rate | ${(skill.successRate * 100).toFixed(1)}% |`,
      `| Usage Count | ${skill.usageCount} |`,
      `| Installed | ${skill.installed ? "Yes" : "No"} |`,
      "",
      `## Steps\n`,
      stepsSection,
      "",
      `## Source Workflows`,
      "",
      ...skill.sourceWorkflowIds.map((id) => `- \`${id}\``),
      "",
      "---",
      "*Auto-generated by SoloFlow Skill Evolution System*",
    ].join("\n");
  }

  scoreSkill(skill: Skill): SkillScore {
    const successRate = skill.successRate;
    const usageScore = Math.min(skill.usageCount / MAX_USAGE_FOR_SCORE, 1);
    const ageMs = Date.now() - skill.updatedAt;
    const recency = Math.max(0, 1 - ageMs / THIRTY_DAYS_MS);
    const complexity = Math.min(skill.steps.length / MAX_COMPLEXITY_STEPS, 1);

    const score =
      0.4 * successRate +
      0.3 * usageScore +
      0.2 * recency +
      0.1 * (1 - complexity);

    return {
      skillId: skill.id,
      score,
      successRate,
      usageCount: skill.usageCount,
      recency,
      complexity,
    };
  }

  private buildEvaluationPrompt(
    pattern: TaskPattern,
    context: Record<string, unknown>,
  ): string {
    return JSON.stringify({
      task: "evaluate_pattern_as_skill",
      pattern: {
        stepSignatures: pattern.stepSignatures,
        occurrenceCount: pattern.occurrenceCount,
        disciplines: pattern.disciplines,
        paramTemplates: pattern.paramTemplates,
      },
      context,
      instructions: {
        shouldGenerate:
          "true if this pattern represents a coherent, reusable workflow worth automating",
        name: "concise, descriptive skill name in PascalCase",
        description: "1-2 sentence description of what this skill accomplishes",
        steps:
          "array of refined steps, each with name (string), action (string describing what the step does)",
      },
    });
  }

  private parseLlmResponse(content: string, pattern: TaskPattern): Skill | null {
    try {
      const cleaned = content.replace(/```json\n?/g, "").replace(/```\n?/g, "").trim();
      const parsed = JSON.parse(cleaned) as {
        shouldGenerate?: boolean;
        name?: string;
        description?: string;
        steps?: Array<{ name: string; action: string }>;
      };

      if (!parsed.shouldGenerate || !parsed.name) return null;

      const steps: SkillStep[] = (parsed.steps ?? []).map((s, i) => ({
        name: s.name,
        action: s.action,
        discipline: pattern.disciplines[i] ?? pattern.disciplines[0]!,
        params: pattern.paramTemplates[i] ?? {},
      }));

      return {
        id: generateId(),
        name: parsed.name,
        description: parsed.description ?? `Auto-generated skill from pattern ${pattern.id}`,
        steps,
        discipline: pattern.disciplines[0]!,
        successRate: 1.0,
        usageCount: pattern.occurrenceCount,
        installed: false,
        createdAt: Date.now(),
        updatedAt: Date.now(),
        sourceWorkflowIds: pattern.workflowIds,
      };
    } catch (e) { console.warn(`error: ${e}`);
      return null;
    }
  }

  private generateFromPattern(
    pattern: TaskPattern,
    context: Record<string, unknown>,
  ): Skill {
    const nameFromContext = typeof context["name"] === "string"
      ? context["name"]
      : pattern.stepSignatures
          .map((sig) => sig.split(":").pop() ?? "")
          .map((s) => s.charAt(0).toUpperCase() + s.slice(1))
          .join(" → ");

    const steps: SkillStep[] = pattern.stepSignatures.map((sig, i) => {
      const parts = sig.split(":");
      const discipline = (parts[0] ?? "quick") as AgentDiscipline;
      const stepName = parts.slice(1).join(":") || `Step ${i + 1}`;

      return {
        name: stepName,
        action: `Execute ${stepName} using ${discipline} discipline`,
        discipline,
        params: pattern.paramTemplates[i] ?? {},
      };
    });

    return {
      id: generateId(),
      name: nameFromContext,
      description: `Auto-generated skill from ${pattern.occurrenceCount} repeated workflow executions`,
      steps,
      discipline: pattern.disciplines[0]!,
      successRate: 1.0,
      usageCount: pattern.occurrenceCount,
      installed: false,
      createdAt: Date.now(),
      updatedAt: Date.now(),
      sourceWorkflowIds: pattern.workflowIds,
    };
  }
}
