package dashboard

import (
	"context"
	"errors"
	"testing"

	"tm/pkg/ai_summarizer"

	"go.mongodb.org/mongo-driver/v2/bson"
)

type mockProcedureDocumentsLister struct {
	procedures []ai_summarizer.ProcedureDocumentsSummary
	err        error
}

func (m *mockProcedureDocumentsLister) ListProceduresWithDocuments(context.Context) ([]ai_summarizer.ProcedureDocumentsSummary, error) {
	if m.err != nil {
		return nil, m.err
	}
	return m.procedures, nil
}

func TestScrapedDocumentsFolderIDsUsesMinIOProcedures(t *testing.T) {
	repo := &repository{
		procedureLister: &mockProcedureDocumentsLister{
			procedures: []ai_summarizer.ProcedureDocumentsSummary{
				{ContractFolderID: "PROC-1", DocumentCount: 3},
				{ContractFolderID: "PROC-2", DocumentCount: 0},
				{ContractFolderID: " PROC-3 ", DocumentCount: 1},
				{ContractFolderID: "PROC-1", DocumentCount: 2},
			},
		},
	}

	got, err := repo.scrapedDocumentsFolderIDs(context.Background())
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}

	want := []string{"PROC-1", "PROC-3"}
	if len(got) != len(want) {
		t.Fatalf("expected %d folder IDs, got %d: %v", len(want), len(got), got)
	}
	for i, id := range want {
		if got[i] != id {
			t.Fatalf("expected folder ID %q at index %d, got %q", id, i, got[i])
		}
	}
}

func TestScrapedDocumentsFolderIDsWithoutLister(t *testing.T) {
	repo := &repository{}

	got, err := repo.scrapedDocumentsFolderIDs(context.Background())
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if got != nil {
		t.Fatalf("expected nil folder IDs without lister, got %v", got)
	}
}

func TestScrapedDocumentsFolderIDsPropagatesError(t *testing.T) {
	repo := &repository{
		procedureLister: &mockProcedureDocumentsLister{
			err: errors.New("minio unavailable"),
		},
	}

	_, err := repo.scrapedDocumentsFolderIDs(context.Background())
	if err == nil {
		t.Fatal("expected error")
	}
}

func TestResolveScrapedTendersScopeUsesMinIOFolders(t *testing.T) {
	repo := &repository{
		procedureLister: &mockProcedureDocumentsLister{
			procedures: []ai_summarizer.ProcedureDocumentsSummary{
				{ContractFolderID: "PROC-1", DocumentCount: 2},
			},
		},
	}

	scope, err := repo.resolveScrapedTendersScope(context.Background())
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if scope.zero {
		t.Fatal("expected non-zero scope")
	}
	in, ok := scope.match["contract_folder_id"].(bson.M)
	if !ok {
		t.Fatalf("expected contract_folder_id filter, got %#v", scope.match)
	}
	ids, ok := in["$in"].([]string)
	if !ok || len(ids) != 1 || ids[0] != "PROC-1" {
		t.Fatalf("unexpected folder IDs: %#v", in["$in"])
	}
}

func TestResolveScrapedTendersScopeZeroWhenMinIOEmpty(t *testing.T) {
	repo := &repository{
		procedureLister: &mockProcedureDocumentsLister{},
	}

	scope, err := repo.resolveScrapedTendersScope(context.Background())
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if !scope.zero {
		t.Fatalf("expected zero scope, got %#v", scope)
	}
}

func TestResolveScrapedTendersScopeMongoFallbackWithoutLister(t *testing.T) {
	repo := &repository{}

	scope, err := repo.resolveScrapedTendersScope(context.Background())
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if scope.zero {
		t.Fatal("expected mongo fallback scope")
	}
	if scope.match["processing_metadata.documents_scraped"] != true {
		t.Fatalf("expected mongo fallback filter, got %#v", scope.match)
	}
}

func TestMongoScrapedTendersScopeMatchesStatisticsFilter(t *testing.T) {
	scope := mongoScrapedTendersScope()
	if scope.zero {
		t.Fatal("expected non-zero mongo statistics scope")
	}
	if scope.match["processing_metadata.documents_scraped"] != true {
		t.Fatalf("expected documents_scraped filter, got %#v", scope.match)
	}
}
