package main

import (
	"bytes"
	"net/http"
	"net/http/httptest"
	"os"
	"strings"
	"testing"
)

func TestSmokeOpenAICommandSuccess(t *testing.T) {
	// Record the endpoint hit order so we assert health -> models -> responses.
	var calledEndpoints []string
	// Start an httptest server to mock the OpenAI-compatible endpoint
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		calledEndpoints = append(calledEndpoints, r.URL.Path)
		switch r.URL.Path {
		case "/healthz":
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(`{"status":"ok"}`))
		case "/v1/models":
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(`{"object":"list","data":[{"id":"test-model","object":"model","created":123456,"owned_by":"iop"}]}`))
		case "/v1/responses":
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(`{"id":"resp-123","object":"response","created_at":123456,"model":"test-model","output_text":"responses pong","output":[{"type":"message","role":"assistant","content":[{"type":"output_text","text":"responses pong"}]}],"usage":{"prompt_tokens":1,"completion_tokens":1,"total_tokens":2}}`))
		default:
			w.WriteHeader(http.StatusNotFound)
		}
	}))
	defer server.Close()

	root := rootCmd()
	var out bytes.Buffer
	root.SetOut(&out)
	root.SetErr(&out)
	root.SetArgs([]string{"smoke", "openai", "--model", "test-model", "--base-url", server.URL, "--prompt", "ping", "--timeout", "5s"})
	if err := root.Execute(); err != nil {
		t.Fatalf("smoke openai command failed: %v\n%s", err, out.String())
	}

	got := out.String()
	wants := []string{
		"Step 1: Checking /healthz ... [OK]",
		"Step 2: Checking /v1/models ... [OK]",
		"Step 3: Checking /v1/responses ... [OK]",
		"Responses Output Text: \"responses pong\"",
		"IOP Edge OpenAI Smoke Test SUCCESS!",
	}
	for _, w := range wants {
		if !strings.Contains(got, w) {
			t.Errorf("smoke openai success output missing: %q\nFull output:\n%s", w, got)
		}
	}

	wantOrder := []string{"/healthz", "/v1/models", "/v1/responses"}
	if len(calledEndpoints) != len(wantOrder) {
		t.Fatalf("expected endpoints %v, got %v", wantOrder, calledEndpoints)
	}
	for i, want := range wantOrder {
		if calledEndpoints[i] != want {
			t.Fatalf("expected endpoint order %v, got %v", wantOrder, calledEndpoints)
		}
	}
}

func TestSmokeOpenAICommandAuthenticatedEndpoint(t *testing.T) {
	oldAPIKey, hadAPIKey := os.LookupEnv("OPENAI_API_KEY")
	os.Unsetenv("OPENAI_API_KEY")
	defer func() {
		if hadAPIKey {
			os.Setenv("OPENAI_API_KEY", oldAPIKey)
		} else {
			os.Unsetenv("OPENAI_API_KEY")
		}
	}()

	const token = "test-token"
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		switch r.URL.Path {
		case "/healthz":
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(`{"status":"ok"}`))
		case "/v1/models", "/v1/responses":
			if r.Header.Get("Authorization") != "Bearer "+token {
				w.WriteHeader(http.StatusUnauthorized)
				w.Write([]byte(`{"error":{"type":"unauthorized","message":"missing bearer token"}}`))
				return
			}
			w.Header().Set("Content-Type", "application/json")
			w.WriteHeader(http.StatusOK)
			if r.URL.Path == "/v1/models" {
				w.Write([]byte(`{"object":"list","data":[{"id":"test-model","object":"model","created":123456,"owned_by":"iop"}]}`))
				return
			}
			w.Write([]byte(`{"id":"resp-123","object":"response","created_at":123456,"model":"test-model","output_text":"responses pong","output":[{"type":"message","role":"assistant","content":[{"type":"output_text","text":"responses pong"}]}]}`))
		default:
			w.WriteHeader(http.StatusNotFound)
		}
	}))
	defer server.Close()

	root := rootCmd()
	var out bytes.Buffer
	root.SetOut(&out)
	root.SetErr(&out)
	root.SetArgs([]string{"smoke", "openai", "--model", "test-model", "--base-url", server.URL, "--timeout", "5s"})
	err := root.Execute()
	if err == nil {
		t.Fatalf("expected unauthenticated smoke to fail\n%s", out.String())
	}
	if !strings.Contains(err.Error(), "401") {
		t.Fatalf("expected 401 error, got %v\n%s", err, out.String())
	}

	os.Setenv("OPENAI_API_KEY", token)
	root = rootCmd()
	out.Reset()
	root.SetOut(&out)
	root.SetErr(&out)
	root.SetArgs([]string{"smoke", "openai", "--model", "test-model", "--base-url", server.URL, "--timeout", "5s"})
	if err := root.Execute(); err != nil {
		t.Fatalf("authenticated smoke failed: %v\n%s", err, out.String())
	}
	if !strings.Contains(out.String(), "IOP Edge OpenAI Smoke Test SUCCESS!") {
		t.Fatalf("success output missing:\n%s", out.String())
	}
}

func TestSmokeOpenAICommandFailure(t *testing.T) {
	// 1. Non-200 /healthz error
	server := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.URL.Path == "/healthz" {
			w.WriteHeader(http.StatusInternalServerError)
			w.Write([]byte("internal server error"))
			return
		}
		w.WriteHeader(http.StatusOK)
	}))
	defer server.Close()

	root := rootCmd()
	var out bytes.Buffer
	root.SetOut(&out)
	root.SetErr(&out)
	root.SetArgs([]string{"smoke", "openai", "--model", "test-model", "--base-url", server.URL})
	err := root.Execute()
	if err == nil {
		t.Fatalf("expected error from non-200 healthz, got nil. Output:\n%s", out.String())
	}
	if !strings.Contains(err.Error(), "returned non-200 status 500") {
		t.Errorf("unexpected error message: %v", err)
	}

	// 2. Responses non-200 error
	server4 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		switch r.URL.Path {
		case "/healthz":
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(`{"status":"ok"}`))
		case "/v1/models":
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(`{"object":"list","data":[{"id":"test-model","object":"model"}]}`))
		case "/v1/responses":
			w.WriteHeader(http.StatusServiceUnavailable)
			w.Write([]byte("node offline"))
		}
	}))
	defer server4.Close()

	root = rootCmd()
	out.Reset()
	root.SetOut(&out)
	root.SetErr(&out)
	root.SetArgs([]string{"smoke", "openai", "--model", "test-model", "--base-url", server4.URL})
	err4 := root.Execute()
	if err4 == nil {
		t.Fatalf("expected error from non-200 responses, got nil")
	}
	if !strings.Contains(err4.Error(), "returned non-200 status 503") {
		t.Errorf("unexpected error message: %v", err4)
	}

	// 3. Responses empty text error
	server5 := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		switch r.URL.Path {
		case "/healthz":
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(`{"status":"ok"}`))
		case "/v1/models":
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(`{"object":"list","data":[{"id":"test-model","object":"model"}]}`))
		case "/v1/responses":
			w.WriteHeader(http.StatusOK)
			w.Write([]byte(`{"id":"resp-123","object":"response","created_at":123456,"model":"test-model","output_text":"","output":[]}`))
		}
	}))
	defer server5.Close()

	root = rootCmd()
	out.Reset()
	root.SetOut(&out)
	root.SetErr(&out)
	root.SetArgs([]string{"smoke", "openai", "--model", "test-model", "--base-url", server5.URL})
	err5 := root.Execute()
	if err5 == nil {
		t.Fatalf("expected error from empty responses text, got nil")
	}
	if !strings.Contains(err5.Error(), "returned empty response text") {
		t.Errorf("unexpected error message: %v", err5)
	}
}
