package handlers

import (
	"encoding/json"
	"os"
	"path/filepath"
	"testing"

	"github.com/gin-gonic/gin"
	"wa-assistant/backend/models"
	"wa-assistant/backend/services"
)

func simulationTestStore(t *testing.T) {
	t.Helper()
	previous := simulationLogs
	simulationLogs = services.NewSimulationLogStore(t.TempDir())
	t.Cleanup(func() { simulationLogs = previous })
}

func TestSimulationHandlerLogsEarlyHandoffAndProviderFailure(t *testing.T) {
	// Verify detailed debugging only when the server explicitly enables it.
	t.Setenv("AI_SIMULATION_LOG_CONTENT", "true")
	db := workflowTestDB(t)
	if err := db.AutoMigrate(&models.AppSetting{}, &models.AITurn{}); err != nil {
		t.Fatal(err)
	}
	db.Model(&models.Agent{}).Where("id = ?", 1).Updates(map[string]any{"agentic_enabled": true, "response_length": "short"})
	t.Setenv("OPENROUTER_API_KEY", "")
	simulationTestStore(t)
	for _, tc := range []struct {
		question, status string
		code             int
	}{
		{"Saya mau bicara dengan CS manusia", "handoff", 200},
		{"Apa syarat retur?", "handoff", 200},
	} {
		turnID, sessionID := services.NewSimulationID(), services.NewSimulationID()
		w := workflowRequest(t, TestChat, map[string]any{"turn_id": turnID, "session_id": sessionID, "message": tc.question}, gin.Params{{Key: "id", Value: "1"}})
		var body map[string]any
		if json.Unmarshal(w.Body.Bytes(), &body) != nil || w.Code != tc.code || body["turn_id"] != turnID || body["log_saved"] != true {
			t.Fatalf("response: %d %s", w.Code, w.Body.String())
		}
		record, err := simulationLogs.Read(1, turnID)
		if err != nil || record.Status != tc.status || record.Events[0].Data["question"] != tc.question {
			t.Fatalf("log: %+v %v", record, err)
		}
		if tc.question == "Apa syarat retur?" {
			if body["handoff_reason"] != "provider_unavailable" || body["reply"] != services.DefaultHandoffReply || body["escalate"] != true {
				t.Fatal("provider failure lost its safe notice or diagnostic reason")
			}
			found := false
			for _, event := range record.Events {
				if event.Stage == "handoff_fallback" && event.Data["issue"] == "provider_unavailable" {
					found = true
				}
			}
			if !found {
				t.Fatal("provider failure disappeared from the diagnostic log")
			}
		}
		params := gin.Params{{Key: "id", Value: "1"}, {Key: "turnID", Value: turnID}}
		w = workflowRequest(t, GetSimulationLog, nil, params)
		if w.Code != 200 || w.Header().Get("Cache-Control") != "no-store" {
			t.Fatalf("read: %d", w.Code)
		}
		w = workflowRequest(t, SaveSimulationFeedback, map[string]any{"rating": "needs_work", "note": "Jawaban belum sesuai harapan."}, params)
		if w.Code != 200 {
			t.Fatal(w.Body.String())
		}
		// A foreign tenant and an invalid path must not expose the log or accept feedback.
		db.Create(&models.Agent{ID: 22, TenantID: 2, Name: "foreign"})
		foreign := gin.Params{{Key: "id", Value: "22"}, {Key: "turnID", Value: turnID}}
		if w := workflowRequest(t, GetSimulationLog, nil, foreign); w.Code != 404 {
			t.Fatalf("foreign read: %d", w.Code)
		}
		if w := workflowRequest(t, SaveSimulationFeedback, map[string]any{"rating": "correct"}, foreign); w.Code != 404 {
			t.Fatalf("foreign write: %d", w.Code)
		}
		w = workflowRequest(t, TestChat, map[string]any{"turn_id": turnID, "session_id": sessionID, "message": tc.question}, gin.Params{{Key: "id", Value: "1"}})
		if w.Code != 409 {
			t.Fatal("duplicate turn reran the model")
		}
	}
	var count int64
	db.Model(&models.Handoff{}).Count(&count)
	if count != 0 {
		t.Fatal("simulator created a real handoff")
	}
	db.Model(&models.ChatHistory{}).Count(&count)
	if count != 0 {
		t.Fatal("simulator wrote real WhatsApp history")
	}
}

func TestSimulationResponseRemainsUsableWhenLogCannotBeWritten(t *testing.T) {
	workflowTestDB(t)
	simulationTestStore(t)
	blocked := filepath.Join(t.TempDir(), "blocked")
	if err := os.WriteFile(blocked, nil, 0600); err != nil {
		t.Fatal(err)
	}
	simulationLogs = services.NewSimulationLogStore(blocked)
	w := workflowRequest(t, TestChat, map[string]any{"message": "tolong hubungkan ke CS manusia"}, gin.Params{{Key: "id", Value: "1"}})
	var body map[string]any
	if json.Unmarshal(w.Body.Bytes(), &body) != nil || w.Code != 200 || body["log_saved"] != false || body["escalate"] != true {
		t.Fatalf("failure hidden or breaks handoff: %d %s", w.Code, w.Body.String())
	}
}
