package services

import (
	"context"
	"testing"
)

// Tests for formatting, revisions and tool orchestration inject the verdict for
// their known fixture. The content reviewer itself is tested independently.
func approveTestAnswer(context.Context, string, string, string) (answerEvidenceReview, error) {
	return answerEvidenceReview{Supported: true}, nil
}

func TestAnswerCannotSendWithoutReviewer(t *testing.T) {
	state := &agentTurnState{userMessage: "halo", policy: responsePolicyForLength(selectAIResponsePolicy("halo", "", "", 1), "short", "halo")}
	check := state.checkAnswer(context.Background(), 1, answerCheckInput{Answer: "Halo, Kak.", Kind: "social"})
	if check.Approved || check.Issue != "review_unavailable" || state.socialDraft != "" {
		t.Fatalf("missing reviewer failed open: %+v", check)
	}
}

func TestReviewedSocialReplyMustStillResolveCustomerIntent(t *testing.T) {
	question := "Harga dan masa aksesnya berapa?"
	state := &agentTurnState{userMessage: question, policy: responsePolicyForLength(selectAIResponsePolicy(question, "", "", 1), "short", question)}
	state.reviewAnswer = func(context.Context, string, string, string) (answerEvidenceReview, error) {
		return answerEvidenceReview{Supported: true, Incomplete: true, MissingAspects: []string{"harga dan masa akses"}}, nil
	}
	check := state.checkAnswer(context.Background(), 1, answerCheckInput{Answer: "Baik, terima kasih, Kak.", Kind: "social"})
	if check.Approved || check.Issue != "incomplete_answer" || state.socialDraft != "" {
		t.Fatalf("social evasion accepted: %+v", check)
	}
}

func TestNonFactualLabelsCannotBypassEvidenceReview(t *testing.T) {
	for _, tc := range []struct{ kind, question, answer string }{
		{"social", "Apakah ada garansi?", "Semua produk kami bergaransi seumur hidup."},
		{"social", "Apakah produk ini tersedia?", "Produk ini tersedia dan gratis ongkir."},
		{"clarification", "Saya ingin retur", "Apakah Anda ingin memakai garansi seumur hidup kami?"},
	} {
		t.Run(tc.kind+tc.question, func(t *testing.T) {
			state := &agentTurnState{userMessage: tc.question, policy: responsePolicyForLength(selectAIResponsePolicy(tc.question, "", "", 1), "balanced", tc.question)}
			reviewed := false
			state.reviewAnswer = func(context.Context, string, string, string) (answerEvidenceReview, error) {
				reviewed = true
				return answerEvidenceReview{UnsupportedClaims: []string{"Klaim bisnis tanpa sumber"}}, nil
			}
			check := state.checkAnswer(context.Background(), 1, answerCheckInput{Answer: tc.answer, Kind: tc.kind})
			if check.Approved || state.socialDraft != "" {
				t.Fatalf("unreviewed factual claim approved or retained: %+v", check)
			}
			if !reviewed {
				t.Fatal("non-factual label skipped independent content review")
			}
		})
	}
}

func TestKnowledgeTrainingPreservesSourceNegation(t *testing.T) {
	source := "Source code ini tidak boleh dijual kembali. Source code hanya untuk penggunaan pribadi."
	if issue := validateKnowledgeEvidence(source, QAPair{Question: "Apakah source code boleh dijual kembali?", Answer: "Source code ini boleh dijual kembali.", Evidence: source}); issue == "" {
		t.Fatal("negation removed without rejection")
	}
	if issue := validateKnowledgeEvidence(source, QAPair{Question: "Apakah source code boleh dijual kembali?", Answer: "Source code ini tidak boleh dijual kembali.", Evidence: source}); issue != "" {
		t.Fatal(issue)
	}
}

func TestAccessDurationCannotBeReplacedWithPaymentFrequency(t *testing.T) {
	for _, q := range []string{"Berapa harga dan masa aksesnya?", "bayar skali apa bulanan, akses smpe kpn?", "Aksesnya sampai kapan?"} {
		if missingExplicitAnswerAspect(q, "Harganya Rp179.000, sekali bayar, tidak ada perpanjangan berkala.") == "" {
			t.Fatalf("omitted access duration accepted: %s", q)
		}
		for _, answer := range []string{"Akses materi selamanya.", "Akses berlaku 12 bulan.", "Durasi akses belum tercantum dalam informasi yang tersedia."} {
			if issue := missingExplicitAnswerAspect(q, answer); issue != "" {
				t.Fatal(issue)
			}
		}
	}
	if issue := missingExplicitAnswerAspect("Berapa harganya?", "Harganya Rp179.000, sekali bayar."); issue != "" {
		t.Fatal("unsolicited aspect required", issue)
	}
}

func TestModelProtocolCannotLeakThroughAnswerCheck(t *testing.T) {
	s := &agentTurnState{reviewAnswer: approveTestAnswer}
	for _, answer := range []string{"Halo.</answer>\n<parameter name=\"kind\">social", "Halo <｜DSML｜parameter>"} {
		result := s.checkAnswer(context.Background(), 1, answerCheckInput{Answer: answer, Kind: "social"})
		if result.Approved || result.Issue != "protocol_markup" || s.socialDraft != "" {
			t.Fatalf("model markup escaped: %+v", result)
		}
	}
}

func TestProductListDoesNotProveAnUnrelatedCourseIsUnavailable(t *testing.T) {
	claim := "Belum ada kursus merakit pesawat terbang, Kak."
	if unsupportedAvailabilityClaim(claim, "Kami menjual kelas pemrograman dan aplikasi kasir.") == "" {
		t.Fatal("unrelated inventory proved absence")
	}
	if unsupportedAvailabilityClaim(claim, "Kursus merakit pesawat terbang belum tersedia.") != "" {
		t.Fatal("explicit absence was rejected")
	}
	if unsupportedAvailabilityClaim("Belum ada informasi kursus merakit pesawat terbang dalam sumber yang saya temukan.", "") != "" {
		t.Fatal("information limit mistaken for product absence")
	}
}
