package sqlite

import (
	"context"
	"testing"
)

func TestImportBatchesRepoCreateAndGet(t *testing.T) {
	store := openTestDB(t)
	hostID := createTestHost(t, store)
	packID := createTestPack(t, store)
	providerID := createTestProviderWithPack(t, store, packID)

	id, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostID, PackID: packID, ProviderID: providerID,
		Mode: "partial", BatchStatus: "running", AccessStatus: "pending",
	})
	if err != nil {
		t.Fatalf("Create() error = %v", err)
	}
	if id <= 0 {
		t.Fatalf("Create() id = %d, want positive", id)
	}

	got, _ := store.ImportBatches().GetByID(context.Background(), id)
	if got.Mode != "partial" || got.BatchStatus != "running" {
		t.Fatalf("GetByID() = %+v, want running batch", got)
	}
}

func TestImportBatchesRepoUpdateStatus(t *testing.T) {
	store := openTestDB(t)
	hostID := createTestHost(t, store)
	packID := createTestPack(t, store)
	providerID := createTestProviderWithPack(t, store, packID)
	id, _ := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostID, PackID: packID, ProviderID: providerID,
		Mode: "partial", BatchStatus: "running", AccessStatus: "pending",
	})

	err := store.ImportBatches().UpdateStatus(context.Background(), id, "succeeded", "subscription_ready")
	if err != nil {
		t.Fatalf("UpdateStatus() error = %v", err)
	}
	got, _ := store.ImportBatches().GetByID(context.Background(), id)
	if got.BatchStatus != "succeeded" || got.AccessStatus != "subscription_ready" {
		t.Fatalf("status = %+v, want succeeded/subscription_ready", got)
	}
}

func TestImportBatchesRepoGetLatestByProviderID(t *testing.T) {
	store := openTestDB(t)
	hostID := createTestHost(t, store)
	packID := createTestPack(t, store)
	providerID := createTestProviderWithPack(t, store, packID)

	store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostID, PackID: packID, ProviderID: providerID,
		Mode: "partial", BatchStatus: "running", AccessStatus: "pending",
	})
	id2, _ := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostID, PackID: packID, ProviderID: providerID,
		Mode: "strict", BatchStatus: "succeeded", AccessStatus: "subscription_ready",
	})

	got, _ := store.ImportBatches().GetLatestByProviderID(context.Background(), providerID)
	if got.ID != id2 {
		t.Fatalf("latest id = %d, want %d", got.ID, id2)
	}
}

func TestImportBatchesRepoListByProviderID(t *testing.T) {
	store := openTestDB(t)
	hostID := createTestHost(t, store)
	packID := createTestPack(t, store)
	providerID := createTestProviderWithPack(t, store, packID)

	olderID, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostID, PackID: packID, ProviderID: providerID,
		Mode: "partial", BatchStatus: "running", AccessStatus: "pending",
	})
	if err != nil {
		t.Fatalf("Create older batch error = %v", err)
	}
	newerID, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostID, PackID: packID, ProviderID: providerID,
		Mode: "strict", BatchStatus: "succeeded", AccessStatus: "subscription_ready",
	})
	if err != nil {
		t.Fatalf("Create newer batch error = %v", err)
	}

	batches, err := store.ImportBatches().ListByProviderID(context.Background(), providerID)
	if err != nil {
		t.Fatalf("ListByProviderID() error = %v", err)
	}
	if len(batches) != 2 {
		t.Fatalf("ListByProviderID() len = %d, want 2", len(batches))
	}
	if batches[0].ID != newerID || batches[1].ID != olderID {
		t.Fatalf("ListByProviderID() ids = [%d %d], want [%d %d]", batches[0].ID, batches[1].ID, newerID, olderID)
	}
}

func TestImportBatchesRepoGetLatestByProviderIDAndHostID(t *testing.T) {
	store := openTestDB(t)
	hostA := createTestHost(t, store)
	hostB := createTestHostWithBaseURL(t, store, "host-b-"+sanitizeTestName(t.Name()), "https://host-b.example.com")
	packID := createTestPack(t, store)
	providerID := createTestProviderWithPack(t, store, packID)

	if _, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostA, PackID: packID, ProviderID: providerID,
		Mode: "partial", BatchStatus: "running", AccessStatus: "pending",
	}); err != nil {
		t.Fatalf("Create(hostA older) error = %v", err)
	}
	latestA, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostA, PackID: packID, ProviderID: providerID,
		Mode: "strict", BatchStatus: "succeeded", AccessStatus: "subscription_ready",
	})
	if err != nil {
		t.Fatalf("Create(hostA newer) error = %v", err)
	}
	if _, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostB, PackID: packID, ProviderID: providerID,
		Mode: "partial", BatchStatus: "partially_succeeded", AccessStatus: "degraded",
	}); err != nil {
		t.Fatalf("Create(hostB) error = %v", err)
	}

	got, err := store.ImportBatches().GetLatestByProviderIDAndHostID(context.Background(), providerID, hostA)
	if err != nil {
		t.Fatalf("GetLatestByProviderIDAndHostID() error = %v", err)
	}
	if got.ID != latestA {
		t.Fatalf("GetLatestByProviderIDAndHostID() id = %d, want %d", got.ID, latestA)
	}
}

func TestImportBatchesRepoListByProviderIDAndHostID(t *testing.T) {
	store := openTestDB(t)
	hostA := createTestHost(t, store)
	hostB := createTestHostWithBaseURL(t, store, "host-b-"+sanitizeTestName(t.Name()), "https://host-b2.example.com")
	packID := createTestPack(t, store)
	providerID := createTestProviderWithPack(t, store, packID)

	olderA, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostA, PackID: packID, ProviderID: providerID,
		Mode: "partial", BatchStatus: "running", AccessStatus: "pending",
	})
	if err != nil {
		t.Fatalf("Create(hostA older) error = %v", err)
	}
	newerA, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostA, PackID: packID, ProviderID: providerID,
		Mode: "strict", BatchStatus: "succeeded", AccessStatus: "subscription_ready",
	})
	if err != nil {
		t.Fatalf("Create(hostA newer) error = %v", err)
	}
	if _, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostB, PackID: packID, ProviderID: providerID,
		Mode: "strict", BatchStatus: "succeeded", AccessStatus: "subscription_ready",
	}); err != nil {
		t.Fatalf("Create(hostB) error = %v", err)
	}

	batches, err := store.ImportBatches().ListByProviderIDAndHostID(context.Background(), providerID, hostA)
	if err != nil {
		t.Fatalf("ListByProviderIDAndHostID() error = %v", err)
	}
	if len(batches) != 2 {
		t.Fatalf("ListByProviderIDAndHostID() len = %d, want 2", len(batches))
	}
	if batches[0].ID != newerA || batches[1].ID != olderA {
		t.Fatalf("ListByProviderIDAndHostID() ids = [%d %d], want [%d %d]", batches[0].ID, batches[1].ID, newerA, olderA)
	}
}

func TestImportBatchesRepoListLatestReconcilable(t *testing.T) {
	store := openTestDB(t)
	hostA := createTestHost(t, store)
	hostB := createTestHostWithBaseURL(t, store, "host-b-"+sanitizeTestName(t.Name()), "https://host-b3.example.com")
	packAID := createTestPack(t, store)
	packBID := createTestPackWithSuffix(t, store, "reconcile")
	providerA := createTestProviderWithPack(t, store, packAID)
	providerB := createTestProviderWithPack(t, store, packBID)

	if _, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostA, PackID: packAID, ProviderID: providerA,
		Mode: "partial", BatchStatus: "running", AccessStatus: "pending",
	}); err != nil {
		t.Fatalf("Create(providerA older) error = %v", err)
	}
	latestA, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostA, PackID: packAID, ProviderID: providerA,
		Mode: "strict", BatchStatus: "succeeded", AccessStatus: "subscription_ready",
	})
	if err != nil {
		t.Fatalf("Create(providerA latest) error = %v", err)
	}
	if _, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostB, PackID: packBID, ProviderID: providerB,
		Mode: "strict", BatchStatus: "partially_succeeded", AccessStatus: "degraded",
	}); err != nil {
		t.Fatalf("Create(providerB latest) error = %v", err)
	}
	if _, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostB, PackID: packBID, ProviderID: providerB,
		Mode: "strict", BatchStatus: "failed", AccessStatus: "broken",
	}); err != nil {
		t.Fatalf("Create(providerB newer failed) error = %v", err)
	}

	batches, err := store.ImportBatches().ListLatestReconcilable(context.Background())
	if err != nil {
		t.Fatalf("ListLatestReconcilable() error = %v", err)
	}
	if len(batches) != 1 {
		t.Fatalf("ListLatestReconcilable() len = %d, want 1 because providerB latest batch is not reconcilable", len(batches))
	}
	if batches[0].ID != latestA {
		t.Fatalf("ListLatestReconcilable() id = %d, want %d", batches[0].ID, latestA)
	}

	batchID, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostB, PackID: packBID, ProviderID: providerB,
		Mode: "strict", BatchStatus: "partially_succeeded", AccessStatus: "degraded",
	})
	if err != nil {
		t.Fatalf("Create(providerB new reconcilable) error = %v", err)
	}

	batches, err = store.ImportBatches().ListLatestReconcilable(context.Background())
	if err != nil {
		t.Fatalf("ListLatestReconcilable() second call error = %v", err)
	}
	if len(batches) != 2 {
		t.Fatalf("ListLatestReconcilable() second len = %d, want 2", len(batches))
	}
	if batches[0].ID != batchID || batches[1].ID != latestA {
		t.Fatalf("ListLatestReconcilable() ids = [%d %d], want [%d %d]", batches[0].ID, batches[1].ID, batchID, latestA)
	}
}

func TestImportBatchesRepoGetByIDNotFound(t *testing.T) {
	store := openTestDB(t)
	_, err := store.ImportBatches().GetByID(context.Background(), 999)
	if err == nil {
		t.Fatal("GetByID(999) error = nil, want error")
	}
}

func TestImportBatchesRepoCreateValidationErrors(t *testing.T) {
	store := openTestDB(t)
	for _, tt := range []struct {
		name  string
		batch ImportBatch
	}{
		{"host_id zero", ImportBatch{HostID: 0, PackID: 1, ProviderID: 1, Mode: "m", BatchStatus: "s", AccessStatus: "s"}},
		{"pack_id zero", ImportBatch{HostID: 1, PackID: 0, ProviderID: 1, Mode: "m", BatchStatus: "s", AccessStatus: "s"}},
		{"provider_id zero", ImportBatch{HostID: 1, PackID: 1, ProviderID: 0, Mode: "m", BatchStatus: "s", AccessStatus: "s"}},
		{"empty mode", ImportBatch{HostID: 1, PackID: 1, ProviderID: 1, Mode: "", BatchStatus: "s", AccessStatus: "s"}},
		{"empty batch_status", ImportBatch{HostID: 1, PackID: 1, ProviderID: 1, Mode: "m", BatchStatus: "", AccessStatus: "s"}},
		{"empty access_status", ImportBatch{HostID: 1, PackID: 1, ProviderID: 1, Mode: "m", BatchStatus: "s", AccessStatus: ""}},
	} {
		t.Run(tt.name, func(t *testing.T) {
			_, err := store.ImportBatches().Create(context.Background(), tt.batch)
			if err == nil {
				t.Fatal("Create() error = nil")
			}
		})
	}
}

func TestImportBatchesRepoUpdateStatusValidation(t *testing.T) {
	store := openTestDB(t)
	if err := store.ImportBatches().UpdateStatus(context.Background(), 0, "s", "s"); err == nil {
		t.Fatal("UpdateStatus id=0 error = nil")
	}
	if err := store.ImportBatches().UpdateStatus(context.Background(), 1, "", "s"); err == nil {
		t.Fatal("UpdateStatus empty batch_status error = nil")
	}
}

// --- ImportBatchItems Repo Tests ---

func TestImportBatchItemsRepoCreateAndGet(t *testing.T) {
	store := openTestDB(t)
	batchID := createTestBatch(t, store)

	id, err := store.ImportBatchItems().Create(context.Background(), ImportBatchItem{
		BatchID:          batchID,
		KeyFingerprint:   "sha256:abc",
		AccountStatus:    "passed",
		ProbeSummaryJSON: `{"ok":true}`,
	})
	if err != nil {
		t.Fatalf("Create() error = %v", err)
	}
	if id <= 0 {
		t.Fatalf("Create() id = %d, want positive", id)
	}

	items, _ := store.ImportBatchItems().GetByBatchID(context.Background(), batchID)
	if len(items) != 1 || items[0].AccountStatus != "passed" {
		t.Fatalf("items = %+v, want 1 with passed status", items)
	}
}

func TestImportBatchItemsRepoMultipleItems(t *testing.T) {
	store := openTestDB(t)
	batchID := createTestBatch(t, store)

	for _, status := range []string{"passed", "failed"} {
		store.ImportBatchItems().Create(context.Background(), ImportBatchItem{
			BatchID: batchID, KeyFingerprint: "sha256:" + status, AccountStatus: status,
		})
	}

	items, _ := store.ImportBatchItems().GetByBatchID(context.Background(), batchID)
	if len(items) != 2 {
		t.Fatalf("count = %d, want 2", len(items))
	}
}

func TestImportBatchItemsRepoUpdateResult(t *testing.T) {
	store := openTestDB(t)
	batchID := createTestBatch(t, store)
	itemID, _ := store.ImportBatchItems().Create(context.Background(), ImportBatchItem{
		BatchID: batchID, KeyFingerprint: "sha256:x", AccountStatus: "pending",
	})

	store.ImportBatchItems().UpdateResult(context.Background(), itemID, "passed", `{"ok":true}`)
	items, _ := store.ImportBatchItems().GetByBatchID(context.Background(), batchID)
	if items[0].AccountStatus != "passed" {
		t.Fatalf("AccountStatus = %q, want passed", items[0].AccountStatus)
	}
}

func TestImportBatchItemsRepoGetByBatchIDEmpty(t *testing.T) {
	store := openTestDB(t)
	items, err := store.ImportBatchItems().GetByBatchID(context.Background(), 999)
	if err != nil {
		t.Fatalf("GetByBatchID() error = %v, want empty result", err)
	}
	if len(items) != 0 {
		t.Fatalf("count = %d, want 0", len(items))
	}
}

func TestImportBatchItemsRepoValidation(t *testing.T) {
	store := openTestDB(t)
	_, err := store.ImportBatchItems().Create(context.Background(), ImportBatchItem{
		BatchID: 0, KeyFingerprint: "k", AccountStatus: "s",
	})
	if err == nil {
		t.Fatal("Create batch_id=0 error = nil")
	}
}

// --- Managed Resources Repo Tests ---

func TestManagedResourcesRepoCreateAndGet(t *testing.T) {
	store := openTestDB(t)
	batchID := createTestBatch(t, store)
	batch, _ := store.ImportBatches().GetByID(context.Background(), batchID)

	id, err := store.ManagedResources().Create(context.Background(), ManagedResource{
		BatchID: batchID, HostID: batch.HostID, ResourceType: "group", HostResourceID: "g_01", ResourceName: "test-group",
	})
	if err != nil {
		t.Fatalf("Create() error = %v", err)
	}
	resources, _ := store.ManagedResources().GetByBatchID(context.Background(), batchID)
	if len(resources) != 1 || resources[0].HostResourceID != "g_01" {
		t.Fatalf("resources = %+v, want 1 with g_01", resources)
	}
	_ = id
}

func TestManagedResourcesRepoMultipleResources(t *testing.T) {
	store := openTestDB(t)
	batchID := createTestBatch(t, store)
	batch, _ := store.ImportBatches().GetByID(context.Background(), batchID)

	for _, r := range []ManagedResource{
		{BatchID: batchID, HostID: batch.HostID, ResourceType: "group", HostResourceID: "g_01", ResourceName: "group-1"},
		{BatchID: batchID, HostID: batch.HostID, ResourceType: "channel", HostResourceID: "c_01", ResourceName: "channel-1"},
		{BatchID: batchID, HostID: batch.HostID, ResourceType: "account", HostResourceID: "a_01", ResourceName: "account-1"},
	} {
		store.ManagedResources().Create(context.Background(), r)
	}

	resources, _ := store.ManagedResources().GetByBatchID(context.Background(), batchID)
	if len(resources) != 3 {
		t.Fatalf("count = %d, want 3", len(resources))
	}
}

func TestManagedResourcesRepoGetByBatchIDEmpty(t *testing.T) {
	store := openTestDB(t)
	resources, _ := store.ManagedResources().GetByBatchID(context.Background(), 999)
	if len(resources) != 0 {
		t.Fatalf("count = %d, want 0", len(resources))
	}
}

func TestManagedResourcesRepoGetByResourceIdentity(t *testing.T) {
	store := openTestDB(t)
	batchID := createTestBatch(t, store)
	batch, err := store.ImportBatches().GetByID(context.Background(), batchID)
	if err != nil {
		t.Fatalf("GetByID() error = %v", err)
	}
	if _, err := store.ManagedResources().Create(context.Background(), ManagedResource{
		BatchID: batchID, HostID: batch.HostID, ResourceType: "channel", HostResourceID: "channel-1", ResourceName: "Channel 1",
	}); err != nil {
		t.Fatalf("Create() error = %v", err)
	}

	resource, err := store.ManagedResources().GetByResourceIdentity(context.Background(), batch.HostID, "channel", "channel-1")
	if err != nil {
		t.Fatalf("GetByResourceIdentity() error = %v", err)
	}
	if resource.ResourceName != "Channel 1" {
		t.Fatalf("GetByResourceIdentity() resource_name = %q, want Channel 1", resource.ResourceName)
	}
}

func TestManagedResourcesRepoListByProviderScopes(t *testing.T) {
	store := openTestDB(t)
	hostA := createTestHost(t, store)
	hostB := createTestHostWithBaseURL(t, store, "host-b-"+sanitizeTestName(t.Name()), "https://managed-host-b.example.com")
	packID := createTestPack(t, store)
	providerID := createTestProviderWithPack(t, store, packID)
	otherProviderID := createTestProviderWithPack(t, store, createTestPackWithSuffix(t, store, "managed"))

	batchA, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostA, PackID: packID, ProviderID: providerID,
		Mode: "partial", BatchStatus: "succeeded", AccessStatus: "subscription_ready",
	})
	if err != nil {
		t.Fatalf("Create(batchA) error = %v", err)
	}
	batchB, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostB, PackID: packID, ProviderID: providerID,
		Mode: "partial", BatchStatus: "partially_succeeded", AccessStatus: "degraded",
	})
	if err != nil {
		t.Fatalf("Create(batchB) error = %v", err)
	}
	otherBatch, err := store.ImportBatches().Create(context.Background(), ImportBatch{
		HostID: hostB, PackID: packID, ProviderID: otherProviderID,
		Mode: "partial", BatchStatus: "succeeded", AccessStatus: "subscription_ready",
	})
	if err != nil {
		t.Fatalf("Create(otherBatch) error = %v", err)
	}

	for _, resource := range []ManagedResource{
		{BatchID: batchA, HostID: hostA, ResourceType: "group", HostResourceID: "g-a", ResourceName: "Group A"},
		{BatchID: batchB, HostID: hostB, ResourceType: "account", HostResourceID: "a-b", ResourceName: "Account B"},
		{BatchID: otherBatch, HostID: hostB, ResourceType: "channel", HostResourceID: "c-other", ResourceName: "Other"},
	} {
		if _, err := store.ManagedResources().Create(context.Background(), resource); err != nil {
			t.Fatalf("Create(%s) error = %v", resource.HostResourceID, err)
		}
	}

	byProvider, err := store.ManagedResources().ListByProviderID(context.Background(), providerID)
	if err != nil {
		t.Fatalf("ListByProviderID() error = %v", err)
	}
	if len(byProvider) != 2 {
		t.Fatalf("ListByProviderID() len = %d, want 2", len(byProvider))
	}

	byProviderHost, err := store.ManagedResources().ListByProviderIDAndHostID(context.Background(), providerID, hostB)
	if err != nil {
		t.Fatalf("ListByProviderIDAndHostID() error = %v", err)
	}
	if len(byProviderHost) != 1 {
		t.Fatalf("ListByProviderIDAndHostID() len = %d, want 1", len(byProviderHost))
	}
	if byProviderHost[0].HostResourceID != "a-b" {
		t.Fatalf("ListByProviderIDAndHostID() resource = %q, want a-b", byProviderHost[0].HostResourceID)
	}
}

func TestManagedResourcesRepoQueryValidationErrors(t *testing.T) {
	store := openTestDB(t)

	if _, err := store.ManagedResources().GetByResourceIdentity(context.Background(), 0, "group", "g-1"); err == nil {
		t.Fatal("GetByResourceIdentity() host_id=0 error = nil")
	}
	if _, err := store.ManagedResources().ListByProviderID(context.Background(), 0); err == nil {
		t.Fatal("ListByProviderID() provider_id=0 error = nil")
	}
	if _, err := store.ManagedResources().ListByProviderIDAndHostID(context.Background(), 1, 0); err == nil {
		t.Fatal("ListByProviderIDAndHostID() host_id=0 error = nil")
	}
}

func TestManagedResourcesRepoValidationErrors(t *testing.T) {
	store := openTestDB(t)
	for _, tt := range []struct {
		name string
		r    ManagedResource
	}{
		{"batch_id zero", ManagedResource{HostID: 1, ResourceType: "g", HostResourceID: "h", ResourceName: "n"}},
		{"host_id zero", ManagedResource{BatchID: 1, ResourceType: "g", HostResourceID: "h", ResourceName: "n"}},
		{"empty resource_type", ManagedResource{BatchID: 1, HostID: 1, HostResourceID: "h", ResourceName: "n"}},
		{"empty host_resource_id", ManagedResource{BatchID: 1, HostID: 1, ResourceType: "g", ResourceName: "n"}},
		{"empty resource_name", ManagedResource{BatchID: 1, HostID: 1, ResourceType: "g", HostResourceID: "h"}},
	} {
		t.Run(tt.name, func(t *testing.T) {
			_, err := store.ManagedResources().Create(context.Background(), tt.r)
			if err == nil {
				t.Fatal("Create() error = nil")
			}
		})
	}
}

// --- Probe Results Repo Tests ---

func TestProbeResultsRepoCreateAndGet(t *testing.T) {
	store := openTestDB(t)
	batchID := createTestBatch(t, store)
	itemID := createTestBatchItem(t, store, batchID)

	id, err := store.ProbeResults().Create(context.Background(), ProbeResult{
		BatchItemID: itemID, ProbeType: "account_smoke", Status: "passed", SummaryJSON: `{"ok":true}`,
	})
	if err != nil {
		t.Fatalf("Create() error = %v", err)
	}
	results, _ := store.ProbeResults().GetByBatchItemID(context.Background(), itemID)
	if len(results) != 1 || results[0].ProbeType != "account_smoke" {
		t.Fatalf("results = %+v, want 1 with account_smoke", results)
	}
	_ = id
}

func TestProbeResultsRepoMultipleResults(t *testing.T) {
	store := openTestDB(t)
	batchID := createTestBatch(t, store)
	itemID := createTestBatchItem(t, store, batchID)

	for _, p := range []ProbeResult{
		{BatchItemID: itemID, ProbeType: "account_smoke", Status: "passed", SummaryJSON: `{"ok":true}`},
		{BatchItemID: itemID, ProbeType: "model_list", Status: "passed", SummaryJSON: `{"models":["m1"]}`},
	} {
		store.ProbeResults().Create(context.Background(), p)
	}

	results, _ := store.ProbeResults().GetByBatchItemID(context.Background(), itemID)
	if len(results) != 2 {
		t.Fatalf("count = %d, want 2", len(results))
	}
}

func TestProbeResultsRepoGetByBatchItemIDEmpty(t *testing.T) {
	store := openTestDB(t)
	results, _ := store.ProbeResults().GetByBatchItemID(context.Background(), 999)
	if len(results) != 0 {
		t.Fatalf("count = %d, want 0", len(results))
	}
}

func TestProbeResultsRepoValidationErrors(t *testing.T) {
	store := openTestDB(t)
	for _, tt := range []struct {
		name  string
		probe ProbeResult
	}{
		{"batch_item_id zero", ProbeResult{ProbeType: "t", Status: "s"}},
		{"empty probe_type", ProbeResult{BatchItemID: 1, Status: "s"}},
		{"empty status", ProbeResult{BatchItemID: 1, ProbeType: "t"}},
	} {
		t.Run(tt.name, func(t *testing.T) {
			_, err := store.ProbeResults().Create(context.Background(), tt.probe)
			if err == nil {
				t.Fatal("Create() error = nil")
			}
		})
	}
}

// --- Access Closures Repo Tests ---

func TestAccessClosureRecordsRepoCreateAndGet(t *testing.T) {
	store := openTestDB(t)
	batchID := createTestBatch(t, store)

	id, err := store.AccessClosures().Create(context.Background(), AccessClosureRecord{
		BatchID: batchID, ClosureType: "subscription", Status: "subscription_ready", DetailsJSON: `{"status_code":200}`,
	})
	if err != nil {
		t.Fatalf("Create() error = %v", err)
	}
	records, _ := store.AccessClosures().GetByBatchID(context.Background(), batchID)
	if len(records) != 1 || records[0].ClosureType != "subscription" {
		t.Fatalf("records = %+v, want 1 subscription", records)
	}
	_ = id
}

func TestAccessClosureRecordsRepoMultiple(t *testing.T) {
	store := openTestDB(t)
	batchID := createTestBatch(t, store)
	store.AccessClosures().Create(context.Background(), AccessClosureRecord{BatchID: batchID, ClosureType: "subscription", Status: "subscription_ready", DetailsJSON: "{}"})
	store.AccessClosures().Create(context.Background(), AccessClosureRecord{BatchID: batchID, ClosureType: "self_service", Status: "self_service_ready", DetailsJSON: "{}"})
	records, _ := store.AccessClosures().GetByBatchID(context.Background(), batchID)
	if len(records) != 2 {
		t.Fatalf("count = %d, want 2", len(records))
	}
}

func TestAccessClosureRecordsRepoGetByBatchIDEmpty(t *testing.T) {
	store := openTestDB(t)
	records, _ := store.AccessClosures().GetByBatchID(context.Background(), 999)
	if len(records) != 0 {
		t.Fatalf("count = %d, want 0", len(records))
	}
}

func TestAccessClosureRecordsRepoValidation(t *testing.T) {
	store := openTestDB(t)
	_, err := store.AccessClosures().Create(context.Background(), AccessClosureRecord{BatchID: 0, ClosureType: "t", Status: "s"})
	if err == nil {
		t.Fatal("Create batch_id=0 error = nil")
	}
}

// --- Reconcile Runs Repo Tests ---

func createTestProviderWithPack(t *testing.T, store *DB, packID int64) int64 {
	t.Helper()
	id, err := store.Providers().Create(context.Background(), Provider{
		PackID: packID, ProviderID: "test-provider-" + sanitizeTestName(t.Name()), DisplayName: "TP",
		BaseURL: "https://tp.com", Platform: "openai",
	})
	if err != nil {
		t.Fatalf("createTestProviderWithPack error = %v", err)
	}
	return id
}

func createTestProvider(t *testing.T, store *DB) int64 {
	t.Helper()
	packID := createTestPack(t, store)
	return createTestProviderWithPack(t, store, packID)
}

func TestReconcileRunsRepoCreateAndGet(t *testing.T) {
	store := openTestDB(t)
	batchID := createTestBatch(t, store)
	batch, err := store.ImportBatches().GetByID(context.Background(), batchID)
	if err != nil {
		t.Fatalf("ImportBatches().GetByID() error = %v", err)
	}

	id, err := store.ReconcileRuns().Create(context.Background(), ReconcileRun{
		BatchID: batchID, HostID: batch.HostID, ProviderID: batch.ProviderID, Status: "active", SummaryJSON: `{"drifted":false}`,
	})
	if err != nil {
		t.Fatalf("Create() error = %v", err)
	}
	runs, _ := store.ReconcileRuns().GetByBatchID(context.Background(), batchID)
	if len(runs) != 1 || runs[0].Status != "active" {
		t.Fatalf("runs = %+v, want 1 active", runs)
	}
	_ = id
}

func TestReconcileRunsRepoMultipleRunsOrderedDesc(t *testing.T) {
	store := openTestDB(t)
	batchID := createTestBatch(t, store)
	batch, err := store.ImportBatches().GetByID(context.Background(), batchID)
	if err != nil {
		t.Fatalf("ImportBatches().GetByID() error = %v", err)
	}

	id1, _ := store.ReconcileRuns().Create(context.Background(), ReconcileRun{BatchID: batchID, HostID: batch.HostID, ProviderID: batch.ProviderID, Status: "first", SummaryJSON: "{}"})
	id2, _ := store.ReconcileRuns().Create(context.Background(), ReconcileRun{BatchID: batchID, HostID: batch.HostID, ProviderID: batch.ProviderID, Status: "second", SummaryJSON: "{}"})
	runs, _ := store.ReconcileRuns().GetByBatchID(context.Background(), batchID)
	if len(runs) != 2 || runs[0].ID != id2 || runs[1].ID != id1 {
		t.Fatalf("order: got %d, %d; want %d, %d (DESC)", runs[0].ID, runs[1].ID, id2, id1)
	}
}

func TestReconcileRunsRepoSeparatesHosts(t *testing.T) {
	store := openTestDB(t)
	hostA := createTestHost(t, store)
	hostB := createTestHostWithBaseURL(t, store, "host-b", "https://host-b.example.com")
	packID := createTestPack(t, store)
	providerID := createTestProviderWithPack(t, store, packID)
	batchA, err := store.ImportBatches().Create(context.Background(), ImportBatch{HostID: hostA, PackID: packID, ProviderID: providerID, Mode: "partial", BatchStatus: "running", AccessStatus: "pending"})
	if err != nil {
		t.Fatalf("ImportBatches().Create(hostA) error = %v", err)
	}
	batchB, err := store.ImportBatches().Create(context.Background(), ImportBatch{HostID: hostB, PackID: packID, ProviderID: providerID, Mode: "partial", BatchStatus: "running", AccessStatus: "pending"})
	if err != nil {
		t.Fatalf("ImportBatches().Create(hostB) error = %v", err)
	}

	if _, err := store.ReconcileRuns().Create(context.Background(), ReconcileRun{BatchID: batchA, HostID: hostA, ProviderID: providerID, Status: "drifted", SummaryJSON: `{"host":"a"}`}); err != nil {
		t.Fatalf("Create(hostA) error = %v", err)
	}
	if _, err := store.ReconcileRuns().Create(context.Background(), ReconcileRun{BatchID: batchB, HostID: hostB, ProviderID: providerID, Status: "active", SummaryJSON: `{"host":"b"}`}); err != nil {
		t.Fatalf("Create(hostB) error = %v", err)
	}

	runs, _ := store.ReconcileRuns().GetByProviderIDAndHostID(context.Background(), providerID, hostA)
	if len(runs) != 1 {
		t.Fatalf("len(runs) = %d, want 1", len(runs))
	}
	if runs[0].Status != "drifted" {
		t.Fatalf("runs[0].Status = %q, want drifted", runs[0].Status)
	}
}

func TestReconcileRunsRepoGetByProviderIDAndHostIDEmpty(t *testing.T) {
	store := openTestDB(t)
	runs, _ := store.ReconcileRuns().GetByProviderIDAndHostID(context.Background(), 999, 1)
	if len(runs) != 0 {
		t.Fatalf("count = %d, want 0", len(runs))
	}
}

func TestReconcileRunsRepoGetByBatchIDEmpty(t *testing.T) {
	store := openTestDB(t)
	runs, _ := store.ReconcileRuns().GetByBatchID(context.Background(), 999)
	if len(runs) != 0 {
		t.Fatalf("count = %d, want 0", len(runs))
	}
}

func TestReconcileRunsRepoValidation(t *testing.T) {
	store := openTestDB(t)
	hostID := createTestHost(t, store)
	_, err := store.ReconcileRuns().Create(context.Background(), ReconcileRun{BatchID: 1, HostID: hostID, ProviderID: 0, Status: "s"})
	if err == nil {
		t.Fatal("Create provider_id=0 error = nil")
	}
}
