package knowledgeqa

import (
	"context"
	"errors"
	"testing"
	"time"

	"github.com/DATA-DOG/go-sqlmock"

	"github.com/tidbcloud/AgentTeam/internal/coredb"
)

func TestLoadFeedbackSnapshotForOwnerUsesCurrentAttemptAndProjectsSafeData(t *testing.T) {
	sqlDB, mock, err := sqlmock.New()
	if err != nil {
		t.Fatal(err)
	}
	defer sqlDB.Close()
	now := time.Date(2026, 8, 11, 12, 0, 0, 0, time.UTC)

	mock.ExpectQuery(`(?s)SELECT id, workspace_id, organization_id.*FROM knowledge_qa_sessions.*WHERE workspace_id=\? AND id=\?`).
		WithArgs("wsp_1", "kqs_1").
		WillReturnRows(sqlmock.NewRows([]string{
			"id", "workspace_id", "organization_id", "owner_user_id", "owner_member_id",
			"root_message_id", "thread_channel_id", "requested_kbs", "requested_sources",
			"requested_model", "requested_reason_level", "web_search_enabled",
			"active_turn_id", "status", "last_activity_at", "created_at", "updated_at",
		}).AddRow(
			"kqs_1", "wsp_1", "org_1", "usr_1", "mem_1", "msg_root", "thr_1",
			[]byte(`["kb_1"]`), []byte(`["src_1"]`), "model-a", "high", false, "", "active", now, now, now,
		))
	mock.ExpectQuery(`(?s)SELECT turn\.id.*FROM knowledge_qa_turns AS turn.*WHERE turn\.workspace_id=\? AND turn\.id=\?`).
		WithArgs("wsp_1", "kqt_1").
		WillReturnRows(sqlmock.NewRows([]string{
			"id", "workspace_id", "organization_id", "session_id", "requester_user_id",
			"user_message_id", "assistant_message_id", "question", "idempotency_key",
			"requested_kbs", "requested_sources", "authorized_roots", "requested_model",
			"requested_reason_level", "web_search_enabled", "effective_model", "effective_reason_level",
			"organization_policy_version", "runtime_version", "prompt_version",
			"current_attempt_id", "status", "error_code", "error_detail", "queued_at",
			"started_at", "completed_at", "updated_at",
		}).AddRow(
			"kqt_1", "wsp_1", "org_1", "kqs_1", "usr_1", "msg_q", "msg_a", "Question?", "idem_1",
			[]byte(`["kb_1"]`), []byte(`["src_1"]`), []byte(`[{"knowledgeBaseId":"kb_1","sourceId":"src_1","rootKind":"repository","repoRole":"primary","revision":"abc123","freshnessStatus":"fresh"}]`),
			"model-a", "high", false, "model-b", "medium", int64(3), "runtime-v2", "prompt-v4", "kqa_current",
			"completed", "", "private internal detail", now, now, now, now,
		))
	mock.ExpectQuery(`(?s)SELECT content.*FROM scope_messages.*workspace_id=\? AND scope_id=\? AND id=\?`).
		WithArgs("wsp_1", "thr_1", "msg_a").
		WillReturnRows(sqlmock.NewRows([]string{"content"}).AddRow(" Answer with citation. "))
	mock.ExpectQuery(`(?s)SELECT event\.sequence.*FROM knowledge_qa_events.*event\.attempt_id=\?.*ORDER BY event\.sequence ASC`).
		WithArgs("wsp_1", "kqt_1", "kqa_current").
		WillReturnRows(sqlmock.NewRows([]string{
			"sequence", "kind", "status", "summary", "tool_name", "payload_json", "created_at",
		}).AddRow(
			int64(1), "tool", "completed", "searched docs", "grep",
			[]byte(`{"stage":"retrieval_complete","grepCalls":2,"query":"must not leave store"}`), now,
		))
	mock.ExpectQuery(`(?s)SELECT id, workspace_id.*FROM knowledge_qa_citations.*attempt_id=\?.*ORDER BY id ASC`).
		WithArgs("wsp_1", "kqt_1", "kqa_current").
		WillReturnRows(sqlmock.NewRows([]string{
			"id", "workspace_id", "turn_id", "attempt_id", "knowledge_base_id", "source_id",
			"root_kind", "repo_role", "revision", "resolved_ref", "resolved_ref_kind", "path",
			"line_start", "line_end", "created_at",
		}).AddRow(
			"kqc_1", "wsp_1", "kqt_1", "kqa_current", "kb_1", "src_1", "repository",
			"primary", "abc123", "main", "branch", "docs/guide.md", int64(10), int64(12), now,
		))

	snapshot, err := New(coredb.WrapSQLDB(sqlDB)).LoadFeedbackSnapshotForOwner(
		context.Background(), "wsp_1", "usr_1", "kqs_1", "kqt_1",
	)
	if err != nil {
		t.Fatal(err)
	}
	if snapshot.ThreadChannelID != "thr_1" || snapshot.Answer != "Answer with citation." {
		t.Fatalf("snapshot identity = %#v", snapshot)
	}
	if snapshot.Turn.ErrorDetail != "" || snapshot.Turn.DebugModelOutput != "" || snapshot.Turn.Activities != nil {
		t.Fatalf("unsafe turn fields were retained: %#v", snapshot.Turn)
	}
	if len(snapshot.Activities) != 1 || snapshot.Activities[0].Counts == nil || snapshot.Activities[0].Counts.SearchCalls == nil || *snapshot.Activities[0].Counts.SearchCalls != 2 {
		t.Fatalf("activities = %#v", snapshot.Activities)
	}
	if len(snapshot.Citations) != 1 || snapshot.Citations[0].Path != "docs/guide.md" || snapshot.Citations[0].AttemptID != "kqa_current" {
		t.Fatalf("citations = %#v", snapshot.Citations)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatal(err)
	}
}

func TestLoadFeedbackSnapshotForOwnerRejectsDifferentOwnerBeforeTurnLookup(t *testing.T) {
	sqlDB, mock, err := sqlmock.New()
	if err != nil {
		t.Fatal(err)
	}
	defer sqlDB.Close()
	now := time.Date(2026, 8, 11, 12, 0, 0, 0, time.UTC)
	mock.ExpectQuery(`(?s)SELECT id, workspace_id, organization_id.*FROM knowledge_qa_sessions.*WHERE workspace_id=\? AND id=\?`).
		WithArgs("wsp_1", "kqs_1").
		WillReturnRows(sqlmock.NewRows([]string{
			"id", "workspace_id", "organization_id", "owner_user_id", "owner_member_id",
			"root_message_id", "thread_channel_id", "requested_kbs", "requested_sources",
			"requested_model", "requested_reason_level", "web_search_enabled",
			"active_turn_id", "status", "last_activity_at", "created_at", "updated_at",
		}).AddRow(
			"kqs_1", "wsp_1", "org_1", "usr_owner", "mem_1", "msg_root", "thr_1",
			[]byte(`[]`), []byte(`[]`), "model-a", "high", false, "", "active", now, now, now,
		))

	_, err = New(coredb.WrapSQLDB(sqlDB)).LoadFeedbackSnapshotForOwner(
		context.Background(), "wsp_1", "usr_other", "kqs_1", "kqt_1",
	)
	if !errors.Is(err, ErrForbidden) {
		t.Fatalf("error = %v, want ErrForbidden", err)
	}
	if err := mock.ExpectationsWereMet(); err != nil {
		t.Fatal(err)
	}
}
