import { createFileRoute } from "@tanstack/react-router";
import { getProvider, getModelUsageName } from "../../proxy/providers";
import { appendLogEntry } from "../../proxy/logger";
import { addTestLogEntry } from "../../proxy/store";
import {
  ProviderTestResultsSchema,
  type ProviderTestResult as TestResult,
  type ProviderTestState,
} from "../../lib/providerTestContract";

function hasSuccessField(result: ProviderTestState): result is TestResult {
  return Object.prototype.hasOwnProperty.call(result, "success");
}

function createTestLogEntry(
  providerName: string,
  path: string,
  body: string,
  upstreamUrl: string,
  result: TestResult,
  isTest: boolean,
): Record<string, unknown> {
  return {
    timestamp: new Date().toISOString(),
    id: `test-${Date.now()}`,
    method: "POST",
    path,
    model: isTest ? result.model : undefined,
    sessionId: null,
    rawRequestBody: body,
    responseStatus: result.success ? 200 : 500,
    responseText: result.rawResponse ?? JSON.stringify(result),
    inputTokens: result.inputTokens ?? null,
    outputTokens: result.outputTokens ?? null,
    elapsedMs: result.latencyMs ?? 0,
    streaming: result.streaming ?? false,
    userAgent: "provider-test",
    origin: null,
    upstreamUrl,
    error: result.success ? null : (result.error?.message ?? String(result.error)),
    isTest: true,
    providerName,
    headers: result.requestHeaders ?? {},
  };
}

async function logModelResults(
  displayName: string,
  providerName: string,
  anthropicUrl: string | undefined,
  openaiUrl: string | undefined,
  modelResults: {
    anthropic: { nonStreaming: ProviderTestState; streaming: ProviderTestState };
    openai: { nonStreaming: ProviderTestState; streaming: ProviderTestState };
  },
): Promise<void> {
  const usageModel = getModelUsageName(displayName, providerName);

  if (anthropicUrl !== undefined) {
    const nsResult = modelResults.anthropic.nonStreaming;
    const sResult = modelResults.anthropic.streaming;
    if (hasSuccessField(nsResult) && hasSuccessField(sResult)) {
      const nonStreamingResult = nsResult;
      const streamingResult = sResult;

      const requestBody = JSON.stringify({
        model: usageModel,
        messages: [{ role: "user", content: "say hello and briefly introduce yourself" }],
        max_tokens: 1024,
      });
      const upstreamUrl = `${anthropicUrl}/v1/messages`;

      await addTestLogEntry({
        timestamp: new Date().toISOString(),
        method: "POST",
        path: "/v1/messages",
        model: nonStreamingResult.model ?? displayName,
        sessionId: null,
        rawRequestBody: requestBody,
        responseStatus: nonStreamingResult.success ? 200 : 500,
        responseText: nonStreamingResult.rawResponse ?? JSON.stringify(nonStreamingResult),
        inputTokens: nonStreamingResult.inputTokens ?? null,
        outputTokens: nonStreamingResult.outputTokens ?? null,
        cacheCreationInputTokens: nonStreamingResult.cacheCreationInputTokens ?? null,
        cacheReadInputTokens: nonStreamingResult.cacheReadInputTokens ?? null,
        elapsedMs: nonStreamingResult.latencyMs ?? 0,
        streaming: false,
        userAgent: "provider-test",
        origin: null,
        apiFormat: "anthropic",
        isTest: true,
        providerName,
        headers: nonStreamingResult.requestHeaders ?? {},
      });

      appendLogEntry(
        createTestLogEntry(
          providerName,
          "/v1/messages",
          requestBody,
          upstreamUrl,
          nonStreamingResult,
          true,
        ),
      );

      const streamingRequestBody = JSON.stringify({
        model: usageModel,
        messages: [{ role: "user", content: "say hello" }],
        max_tokens: 256,
        stream: true,
      });

      await addTestLogEntry({
        timestamp: new Date().toISOString(),
        method: "POST",
        path: "/v1/messages",
        model: streamingResult.model ?? displayName,
        sessionId: null,
        rawRequestBody: streamingRequestBody,
        responseStatus: streamingResult.success ? 200 : 500,
        responseText: streamingResult.rawResponse ?? JSON.stringify(streamingResult),
        inputTokens: streamingResult.inputTokens ?? null,
        outputTokens: streamingResult.outputTokens ?? null,
        cacheCreationInputTokens: streamingResult.cacheCreationInputTokens ?? null,
        cacheReadInputTokens: streamingResult.cacheReadInputTokens ?? null,
        elapsedMs: streamingResult.latencyMs ?? 0,
        streaming: true,
        streamingChunks: streamingResult.streamingChunks,
        userAgent: "provider-test",
        origin: null,
        apiFormat: "anthropic",
        isTest: true,
        providerName,
        headers: streamingResult.requestHeaders ?? {},
      });

      appendLogEntry(
        createTestLogEntry(
          providerName,
          "/v1/messages",
          streamingRequestBody,
          upstreamUrl,
          streamingResult,
          true,
        ),
      );
    }
  }

  if (openaiUrl !== undefined) {
    const nsResult = modelResults.openai.nonStreaming;
    const sResult = modelResults.openai.streaming;
    if (hasSuccessField(nsResult) && hasSuccessField(sResult)) {
      const nonStreamingResult = nsResult;
      const streamingResult = sResult;

      const requestBody = JSON.stringify({
        model: usageModel,
        messages: [{ role: "user", content: "say hello and briefly introduce yourself" }],
        max_tokens: 1024,
      });
      const upstreamUrl = `${openaiUrl}/v1/chat/completions`;

      await addTestLogEntry({
        timestamp: new Date().toISOString(),
        method: "POST",
        path: "/v1/chat/completions",
        model: nonStreamingResult.model ?? displayName,
        sessionId: null,
        rawRequestBody: requestBody,
        responseStatus: nonStreamingResult.success ? 200 : 500,
        responseText: nonStreamingResult.rawResponse ?? JSON.stringify(nonStreamingResult),
        inputTokens: nonStreamingResult.inputTokens ?? null,
        outputTokens: nonStreamingResult.outputTokens ?? null,
        cacheCreationInputTokens: null,
        cacheReadInputTokens: null,
        elapsedMs: nonStreamingResult.latencyMs ?? 0,
        streaming: false,
        userAgent: "provider-test",
        origin: null,
        apiFormat: "openai",
        isTest: true,
        providerName,
        headers: nonStreamingResult.requestHeaders ?? {},
      });

      appendLogEntry(
        createTestLogEntry(
          providerName,
          "/v1/chat/completions",
          requestBody,
          upstreamUrl,
          nonStreamingResult,
          true,
        ),
      );

      const streamingRequestBody = JSON.stringify({
        model: usageModel,
        messages: [{ role: "user", content: "say hello" }],
        max_tokens: 256,
        stream: true,
      });

      await addTestLogEntry({
        timestamp: new Date().toISOString(),
        method: "POST",
        path: "/v1/chat/completions",
        model: streamingResult.model ?? displayName,
        sessionId: null,
        rawRequestBody: streamingRequestBody,
        responseStatus: streamingResult.success ? 200 : 500,
        responseText: streamingResult.rawResponse ?? JSON.stringify(streamingResult),
        inputTokens: streamingResult.inputTokens ?? null,
        outputTokens: streamingResult.outputTokens ?? null,
        cacheCreationInputTokens: null,
        cacheReadInputTokens: null,
        elapsedMs: streamingResult.latencyMs ?? 0,
        streaming: true,
        streamingChunks: streamingResult.streamingChunks,
        userAgent: "provider-test",
        origin: null,
        apiFormat: "openai",
        isTest: true,
        providerName,
        headers: streamingResult.requestHeaders ?? {},
      });

      appendLogEntry(
        createTestLogEntry(
          providerName,
          "/v1/chat/completions",
          streamingRequestBody,
          upstreamUrl,
          streamingResult,
          true,
        ),
      );
    }
  }
}

export const Route = createFileRoute("/api/providers/$providerId/test/log")({
  server: {
    handlers: {
      POST: async ({ params, request }: { params: { providerId: string }; request: Request }) => {
        const provider = getProvider(params.providerId);
        if (!provider) {
          return Response.json({ error: "Provider not found" }, { status: 404 });
        }

        let body: unknown;
        try {
          body = await request.json();
        } catch {
          return Response.json({ error: "Invalid JSON body" }, { status: 400 });
        }

        const parsed = ProviderTestResultsSchema.safeParse(body);
        if (!parsed.success) {
          return Response.json(
            { error: `Invalid test results: ${parsed.error.message}` },
            { status: 400 },
          );
        }

        const results = parsed.data;
        const anthropicUrl =
          provider.anthropicBaseUrl !== undefined && provider.anthropicBaseUrl.length > 0
            ? provider.anthropicBaseUrl
            : undefined;
        const openaiUrl =
          provider.openaiBaseUrl !== undefined && provider.openaiBaseUrl.length > 0
            ? provider.openaiBaseUrl
            : undefined;

        const entries: Promise<void>[] = [];
        if (results.models !== undefined) {
          for (const [modelName, modelResult] of Object.entries(results.models)) {
            entries.push(
              logModelResults(modelName, provider.name, anthropicUrl, openaiUrl, modelResult),
            );
          }
        }

        await Promise.all(entries);

        return Response.json({ logged: entries.length });
      },
    },
  },
});
