package llm

import (
	"context"
	"encoding/json"
	"net/http"
	"net/http/httptest"
	"strings"
	"sync/atomic"
	"testing"
	"time"

	"github.com/nexuscrm/sentry/internal/types"
)

func sampleResult() types.RuleResult {
	return types.RuleResult{
		RuleID: "data.row_spike_warn",
		Entity: "Contact",
		Level:  "WARN",
		Context: map[string]any{
			"current":     int64(523411),
			"baseline_1h": int64(300000),
			"delta_pct":   74.5,
		},
	}
}

func TestQwen_HappyPath(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		if r.Header.Get("Authorization") != "Bearer key-test" {
			http.Error(w, "unauthorized", http.StatusUnauthorized)
			return
		}
		if r.Header.Get("Content-Type") != "application/json" {
			http.Error(w, "bad content type", http.StatusBadRequest)
			return
		}
		var req chatReq
		_ = json.NewDecoder(r.Body).Decode(&req)
		if req.Model != "qwen-max" {
			t.Errorf("model=%s want qwen-max", req.Model)
		}
		if len(req.Messages) != 2 || req.Messages[0].Role != "system" || req.Messages[1].Role != "user" {
			t.Errorf("messages shape wrong: %+v", req.Messages)
		}
		// Verify the system prompt includes the guardrails
		if !strings.Contains(req.Messages[0].Content, "FACTS ONLY") {
			t.Errorf("system prompt missing guardrail: %s", req.Messages[0].Content)
		}
		_ = json.NewEncoder(w).Encode(chatResp{
			Choices: []struct {
				Message chatMessage `json:"message"`
			}{
				{Message: chatMessage{Role: "assistant", Content: "Row-count spike on Contact."}},
			},
		})
	}))
	defer srv.Close()

	c := NewQwenClient(srv.URL, "key-test", "qwen-max", 5*time.Second)
	got, err := c.Translate(context.Background(), sampleResult())
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(got, "Contact") {
		t.Errorf("unexpected content: %s", got)
	}
}

func TestQwen_4xxFailsFast(t *testing.T) {
	var calls int32
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		atomic.AddInt32(&calls, 1)
		http.Error(w, "forbidden", http.StatusForbidden)
	}))
	defer srv.Close()
	c := NewQwenClient(srv.URL, "key", "qwen-max", 5*time.Second)
	if _, err := c.Translate(context.Background(), sampleResult()); err == nil {
		t.Error("want error")
	}
	if atomic.LoadInt32(&calls) != 1 {
		t.Errorf("4xx must not retry; calls=%d", calls)
	}
}

func TestQwen_5xxRetries(t *testing.T) {
	var calls int32
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		n := atomic.AddInt32(&calls, 1)
		if n < 3 {
			http.Error(w, "down", http.StatusBadGateway)
			return
		}
		_ = json.NewEncoder(w).Encode(chatResp{
			Choices: []struct {
				Message chatMessage `json:"message"`
			}{{Message: chatMessage{Role: "assistant", Content: "Recovered after retry."}}},
		})
	}))
	defer srv.Close()
	c := NewQwenClient(srv.URL, "key", "qwen-max", 5*time.Second)
	got, err := c.Translate(context.Background(), sampleResult())
	if err != nil {
		t.Fatal(err)
	}
	if !strings.Contains(got, "Recovered") {
		t.Errorf("content: %s", got)
	}
	if atomic.LoadInt32(&calls) != 3 {
		t.Errorf("want 3 attempts, got %d", calls)
	}
}

func TestQwen_EmptyChoicesIsError(t *testing.T) {
	srv := httptest.NewServer(http.HandlerFunc(func(w http.ResponseWriter, r *http.Request) {
		_, _ = w.Write([]byte(`{"choices":[]}`))
	}))
	defer srv.Close()
	c := NewQwenClient(srv.URL, "key", "qwen-max", 5*time.Second)
	if _, err := c.Translate(context.Background(), sampleResult()); err == nil {
		t.Error("want error on empty choices")
	}
}

func TestQwen_URLBaseNormalization(t *testing.T) {
	// Base URL without /chat/completions should get it appended
	c := NewQwenClient("https://example.com/compatible-mode/v1", "k", "", 1*time.Second)
	if !strings.HasSuffix(c.url, "/chat/completions") {
		t.Errorf("url should end with /chat/completions: %s", c.url)
	}
	// Base URL that already has /chat/completions should not double it
	c2 := NewQwenClient("https://example.com/compatible-mode/v1/chat/completions", "k", "", 1*time.Second)
	if strings.Count(c2.url, "/chat/completions") != 1 {
		t.Errorf("url should contain /chat/completions exactly once: %s", c2.url)
	}
	// Default model
	if c.model != "qwen-max" {
		t.Errorf("default model=%s", c.model)
	}
}
