package store

import (
	"context"
	"path/filepath"
	"testing"
)

func TestCapacityRepoUpsertGetList(t *testing.T) {
	dir := t.TempDir()
	db, err := Open(filepath.Join(dir, "test.db"))
	if err != nil {
		t.Fatalf("Open: %v", err)
	}
	defer db.Close()
	repo := NewCapacityRepo(db)
	ctx := context.Background()

	// Empty initially.
	if _, err := repo.Get(ctx, "self"); err == nil {
		t.Error("expected ErrNotFound on empty store")
	}
	rows, err := repo.List(ctx)
	if err != nil {
		t.Fatalf("List: %v", err)
	}
	if len(rows) != 0 {
		t.Errorf("List: got %d rows, want 0", len(rows))
	}

	// Insert.
	c1 := &NodeCapacity{NodeID: "self", CPUMillicores: 4000, MemoryMiB: 4096, DiskMiB: 4096}
	if err := repo.Upsert(ctx, c1); err != nil {
		t.Fatalf("Upsert: %v", err)
	}
	got, err := repo.Get(ctx, "self")
	if err != nil {
		t.Fatalf("Get: %v", err)
	}
	if got.CPUMillicores != 4000 || got.MemoryMiB != 4096 || got.DiskMiB != 4096 {
		t.Errorf("Get: got %+v, want cpu=4000 mem=4096 disk=4096", got)
	}
	if got.UpdatedAt.IsZero() {
		t.Errorf("Upsert did not fill UpdatedAt")
	}

	// Update (overwrite).
	c2 := &NodeCapacity{NodeID: "self", CPUMillicores: 8000, MemoryMiB: 8192, DiskMiB: 8192}
	if err := repo.Upsert(ctx, c2); err != nil {
		t.Fatalf("Upsert(update): %v", err)
	}
	got, _ = repo.Get(ctx, "self")
	if got.CPUMillicores != 8000 {
		t.Errorf("Update: cpu=%d, want 8000", got.CPUMillicores)
	}

	// Add a second node.
	c3 := &NodeCapacity{NodeID: "peer-1", CPUMillicores: 2000, MemoryMiB: 2048, DiskMiB: 2048}
	if err := repo.Upsert(ctx, c3); err != nil {
		t.Fatalf("Upsert(peer-1): %v", err)
	}
	rows, _ = repo.List(ctx)
	if len(rows) != 2 {
		t.Errorf("List: got %d rows, want 2", len(rows))
	}

	// Delete.
	if err := repo.Delete(ctx, "peer-1"); err != nil {
		t.Fatalf("Delete: %v", err)
	}
	if _, err := repo.Get(ctx, "peer-1"); err == nil {
		t.Error("expected ErrNotFound after Delete")
	}
	if err := repo.Delete(ctx, "missing"); err == nil {
		t.Error("expected ErrNotFound on Delete of missing row")
	}
}

func TestCapacityRepo_UpsertNilAndEmptyNodeID(t *testing.T) {
	dir := t.TempDir()
	db, err := Open(filepath.Join(dir, "test.db"))
	if err != nil {
		t.Fatalf("Open: %v", err)
	}
	defer db.Close()
	repo := NewCapacityRepo(db)
	ctx := context.Background()

	if err := repo.Upsert(ctx, nil); err == nil {
		t.Error("Upsert(nil) should error")
	}
	if err := repo.Upsert(ctx, &NodeCapacity{NodeID: ""}); err == nil {
		t.Error("Upsert(empty NodeID) should error")
	}
}

func TestCapacityRepo_GetEmptyNodeID(t *testing.T) {
	dir := t.TempDir()
	db, err := Open(filepath.Join(dir, "test.db"))
	if err != nil {
		t.Fatalf("Open: %v", err)
	}
	defer db.Close()
	repo := NewCapacityRepo(db)
	ctx := context.Background()

	if _, err := repo.Get(ctx, ""); err == nil {
		t.Error("Get(empty) should error")
	}
}

func TestCapacityRepo_DeleteMissing(t *testing.T) {
	dir := t.TempDir()
	db, err := Open(filepath.Join(dir, "test.db"))
	if err != nil {
		t.Fatalf("Open: %v", err)
	}
	defer db.Close()
	repo := NewCapacityRepo(db)
	ctx := context.Background()

	if err := repo.Delete(ctx, "ghost"); err != ErrNotFound {
		t.Errorf("Delete(ghost) = %v, want ErrNotFound", err)
	}
}

func TestStore_OpenEmptyPath(t *testing.T) {
	// Open with "" should fall back to certpaths.DBPath() which honors
	// ORCA_HOME. Set a temp ORCA_HOME so we don't pollute the real home.
	home := t.TempDir()
	t.Setenv("ORCA_HOME", home)
	db, err := Open("")
	if err != nil {
		t.Fatalf("Open(\"\"): %v", err)
	}
	defer db.Close()
	if err := db.Ping(); err != nil {
		t.Errorf("Ping: %v", err)
	}
}
