/**
 * Token fleet manager agent.
 *
 * Analyzes user requests against fleet state to propose concrete fleet actions
 * (pull_model, remove_model, restart_engine). Actions require user approval
 * before dispatch to devices.
 */

import { logger } from "@/lib/logger";

const OPENROUTER_URL = "https://openrouter.ai/api/v1/chat/completions";

const FLEET_MANAGER_PROMPT = `You are Token's Fleet Manager — you translate natural language fleet commands into specific, actionable operations.

## Your Role
Given the user's fleet state and their request, propose specific fleet actions. Each action targets a specific device and model.

## Available Action Types
- "pull_model": Download/install a model on a device
- "remove_model": Remove a model from a device
- "restart_engine": Restart the inference engine on a device

## Output Format
Respond with a JSON object containing your analysis and proposed actions:
{
  "analysis": "Brief explanation of what you're proposing and why",
  "actions": [
    {
      "deviceId": "<device id from fleet state>",
      "deviceName": "<device name for display>",
      "type": "pull_model",
      "payload": { "model": "qwen3:8b" },
      "reasoning": "Why this action on this device"
    }
  ]
}

## Rules
- Only propose actions on devices that are "online" — skip offline devices
- Check VRAM before recommending model pulls (don't suggest 70B models for 8GB cards)
- If the user's request is ambiguous, propose the most reasonable interpretation
- If no valid action can be derived, return empty actions array with an explanation in analysis
- Always include the device name in the response for human readability
- Maximum 5 actions per response to prevent runaway operations
- Never propose removing ALL models from a device unless explicitly asked

IMPORTANT: Return ONLY the JSON object, no markdown wrapping.`;

export interface FleetDevice {
  id: string;
  name: string;
  status: string;
  models: string[];
  hardware: string;
  tunnelUrl: string;
}

export interface FleetActionProposal {
  deviceId: string;
  deviceName: string;
  type: "pull_model" | "remove_model" | "restart_engine";
  payload: Record<string, string>;
  reasoning: string;
}

export interface FleetManagerResult {
  analysis: string;
  actions: FleetActionProposal[];
  content: string; // Full LLM response for display
  model: string;
  inputTokens: number;
  outputTokens: number;
  costUsd: number;
  latencyMs: number;
}

export async function analyzeFleetRequest(
  message: string,
  model: string,
  devices: FleetDevice[],
  conversationHistory?: Array<{ role: string; content: string }>,
): Promise<FleetManagerResult> {
  const apiKey = process.env.OPENROUTER_API_KEY;
  if (!apiKey) {
    throw new Error("OPENROUTER_API_KEY not configured");
  }

  const start = Date.now();

  // Build fleet state for the prompt
  const fleetState =
    devices.length > 0
      ? devices
          .map(
            (d) =>
              `- ${d.name} (${d.id}): status=${d.status}, hardware=${d.hardware}, models=[${d.models.join(", ")}]`,
          )
          .join("\n")
      : "No devices connected.";

  const messages = [
    {
      role: "system",
      content: FLEET_MANAGER_PROMPT + "\n\n## Current Fleet State\n" + fleetState,
    },
    ...(conversationHistory ?? []),
    { role: "user", content: message },
  ];

  const res = await fetch(OPENROUTER_URL, {
    method: "POST",
    headers: {
      Authorization: `Bearer ${apiKey}`,
      "Content-Type": "application/json",
      "HTTP-Referer": "https://llmhosts.com",
      "X-Title": "LLMHosts Token Fleet Manager",
    },
    body: JSON.stringify({
      model,
      messages,
      temperature: 0.1,
      max_tokens: 2048,
    }),
  });

  if (!res.ok) {
    const errorText = await res.text().catch(() => "Unknown error");
    logger.error(
      { action: "token_fleet_error", status: res.status },
      "Fleet manager API error",
    );
    throw new Error(`Fleet manager API error (${res.status}): ${errorText}`);
  }

  const data = await res.json();
  const latencyMs = Date.now() - start;
  const rawContent = data.choices?.[0]?.message?.content ?? "";
  const usage = data.usage ?? {};

  const inputTokens = usage.prompt_tokens ?? 0;
  const outputTokens = usage.completion_tokens ?? 0;
  const costUsd = parseFloat(res.headers.get("x-openrouter-cost") ?? "0");

  // Parse the structured response
  let analysis = "";
  let actions: FleetActionProposal[] = [];

  try {
    const jsonMatch = rawContent.match(/\{[\s\S]*\}/);
    if (jsonMatch) {
      const parsed = JSON.parse(jsonMatch[0]);
      analysis = parsed.analysis ?? "";
      actions = (parsed.actions ?? []).slice(0, 5).map(
        (a: {
          deviceId?: string;
          deviceName?: string;
          type?: string;
          payload?: Record<string, string>;
          reasoning?: string;
        }) => ({
          deviceId: a.deviceId ?? "",
          deviceName: a.deviceName ?? "",
          type: a.type,
          payload: a.payload ?? {},
          reasoning: a.reasoning ?? "",
        }),
      );

      // Validate action types
      const validTypes = ["pull_model", "remove_model", "restart_engine"];
      actions = actions.filter((a) => validTypes.includes(a.type));
    }
  } catch (err) {
    logger.warn(
      { action: "token_fleet_parse_fail", err },
      "Failed to parse fleet manager response",
    );
    analysis = rawContent; // Fall back to showing raw response
  }

  // Build human-readable content for display
  let content = analysis;
  if (actions.length > 0) {
    content += "\n\n**Proposed Actions:**\n";
    for (const action of actions) {
      const actionLabel =
        action.type === "pull_model"
          ? "Install"
          : action.type === "remove_model"
            ? "Remove"
            : "Restart";
      const target = action.payload.model ? ` \`${action.payload.model}\`` : "";
      content += `\n- **${actionLabel}${target}** on ${action.deviceName} — ${action.reasoning}`;
    }
    content += "\n\nApprove the actions above to proceed, or tell me to adjust.";
  }

  logger.info(
    {
      action: "token_fleet_analysis",
      model,
      actions_count: actions.length,
      latency_ms: latencyMs,
      cost_usd: costUsd,
    },
    "Fleet manager analysis complete",
  );

  return {
    analysis,
    actions,
    content,
    model: data.model ?? model,
    inputTokens,
    outputTokens,
    costUsd,
    latencyMs,
  };
}

/**
 * Dispatch an approved action to a device via its tunnel URL.
 */
export async function dispatchFleetAction(
  tunnelUrl: string,
  actionType: string,
  payload: Record<string, string>,
): Promise<{ success: boolean; result: string }> {
  try {
    let endpoint: string;
    let body: Record<string, unknown>;

    switch (actionType) {
      case "pull_model":
        endpoint = `${tunnelUrl}/api/pull`;
        body = { name: payload.model };
        break;
      case "remove_model":
        endpoint = `${tunnelUrl}/api/delete`;
        body = { name: payload.model };
        break;
      case "restart_engine":
        // Ollama doesn't have a restart endpoint — this would go through our proxy
        endpoint = `${tunnelUrl}/v1/health`;
        body = { action: "restart" };
        break;
      default:
        return { success: false, result: `Unknown action type: ${actionType}` };
    }

    const res = await fetch(endpoint, {
      method: "POST",
      headers: { "Content-Type": "application/json" },
      body: JSON.stringify(body),
      signal: AbortSignal.timeout(60_000), // 60s timeout for model pulls
    });

    if (!res.ok) {
      const errorText = await res.text().catch(() => "Unknown error");
      return { success: false, result: `Device returned ${res.status}: ${errorText}` };
    }

    const result = await res.text();
    return { success: true, result };
  } catch (err) {
    const message = err instanceof Error ? err.message : "Unknown error";
    logger.error(
      { action: "token_fleet_dispatch_error", err, tunnelUrl, actionType },
      "Fleet action dispatch failed",
    );
    return { success: false, result: `Dispatch failed: ${message}` };
  }
}
