import { countTokens as countAnthropicTokens } from "@anthropic-ai/tokenizer";
import type {
  ProviderAdapter,
  NormalizedMessage,
  UsageBlock,
  HintSurfaceRef,
} from "./ProviderAdapter";

type ContentBlock = { type: string; text?: string };

function normalizeContent(content: unknown): string {
  if (typeof content === "string") return content;
  if (Array.isArray(content)) {
    return (content as ContentBlock[])
      .filter((b) => b.type === "text" && typeof b.text === "string")
      .map((b) => b.text as string)
      .join("\n");
  }
  return String(content ?? "");
}

/**
 * AnthropicAdapter — implements ProviderAdapter for Anthropic Claude API.
 *
 * Handles /v1/messages requests, Claude-3 tokenization, and
 * Anthropic SSE usage events (message_start / message_delta).
 */
export class AnthropicAdapter implements ProviderAdapter {
  readonly id = "anthropic" as const;
  readonly tokenizerId = "claude-3" as const;
  readonly hintSurface: HintSurfaceRef = { kind: "claude-md" } as const;

  matches(req: Request): boolean {
    const url = new URL(req.url);
    return url.pathname.endsWith("/v1/messages");
  }

  extractMessages(reqBody: unknown): NormalizedMessage[] {
    const body = reqBody as { messages?: unknown[] };
    if (!Array.isArray(body?.messages)) return [];
    return body.messages.map((m) => {
      const msg = m as { role?: string; content?: unknown };
      return {
        role: (msg.role ?? "user") as NormalizedMessage["role"],
        content: normalizeContent(msg.content),
      };
    });
  }

  replaceMessages(reqBody: unknown, messages: NormalizedMessage[]): unknown {
    return { ...(reqBody as object), messages };
  }

  readUsageFromSse(eventName: string, dataJson: unknown): UsageBlock | null {
    if (eventName === "message_start") {
      const data = dataJson as { message?: { usage?: Record<string, number> } };
      const u = data?.message?.usage;
      if (!u) return null;
      return {
        input_tokens: u["input_tokens"] ?? 0,
        output_tokens: u["output_tokens"] ?? 0,
        ...(u["cache_creation_input_tokens"] !== undefined && { cache_creation_input_tokens: u["cache_creation_input_tokens"] }),
        ...(u["cache_read_input_tokens"] !== undefined && { cache_read_input_tokens: u["cache_read_input_tokens"] }),
        ...(u["ephemeral_5m_input_tokens"] !== undefined && { ephemeral_5m_input_tokens: u["ephemeral_5m_input_tokens"] }),
        ...(u["ephemeral_1h_input_tokens"] !== undefined && { ephemeral_1h_input_tokens: u["ephemeral_1h_input_tokens"] }),
      };
    }

    if (eventName === "message_delta") {
      const data = dataJson as { usage?: Record<string, number> };
      const u = data?.usage;
      if (!u) return null;
      return {
        input_tokens: 0,
        output_tokens: u["output_tokens"] ?? 0,
      };
    }

    return null;
  }

  countTokens(text: string): number {
    try {
      return countAnthropicTokens(text);
    } catch {
      // Fallback: rough estimate
      return Math.ceil(text.length / 4);
    }
  }
}
