package provision

import (
	"context"
	"testing"

	"sub2api-cn-relay-manager/internal/pack"
	"sub2api-cn-relay-manager/internal/store/sqlite"
)

func TestPackInstallServiceInstallPersistsPackAndProviders(t *testing.T) {
	store := openProvisionTestStore(t)
	defer closeProvisionTestStore(t, store)

	host := &fakeHostAdapter{}
	loaded := sampleLoadedPack()

	svc := NewPackInstallService(store, host)
	result, err := svc.Install(context.Background(), PackInstallRequest{Pack: loaded})
	if err != nil {
		t.Fatalf("Install() error = %v", err)
	}
	if result.HostVersion != "0.1.126" {
		t.Fatalf("HostVersion = %q, want 0.1.126", result.HostVersion)
	}
	if result.AlreadyInstalled {
		t.Fatal("AlreadyInstalled = true, want false on first install")
	}
	if result.Pack.PackID != loaded.Manifest.PackID {
		t.Fatalf("Pack.PackID = %q, want %q", result.Pack.PackID, loaded.Manifest.PackID)
	}
	if len(result.Providers) != 1 || result.Providers[0].ProviderID != loaded.Providers[0].ProviderID {
		t.Fatalf("Providers = %#v, want one persisted provider", result.Providers)
	}
	if got := queryCount(t, store.SQLDB(), "packs"); got != 1 {
		t.Fatalf("packs row count = %d, want 1", got)
	}
	if got := queryCount(t, store.SQLDB(), "providers"); got != 1 {
		t.Fatalf("providers row count = %d, want 1", got)
	}

	repeat, err := svc.Install(context.Background(), PackInstallRequest{Pack: loaded})
	if err != nil {
		t.Fatalf("second Install() error = %v", err)
	}
	if !repeat.AlreadyInstalled {
		t.Fatal("AlreadyInstalled = false, want true on re-install")
	}
	if got := queryCount(t, store.SQLDB(), "packs"); got != 1 {
		t.Fatalf("packs row count after re-install = %d, want 1", got)
	}
	if got := queryCount(t, store.SQLDB(), "providers"); got != 1 {
		t.Fatalf("providers row count after re-install = %d, want 1", got)
	}
}

func TestPackInstallServiceInstallUpgradesExistingPackInPlace(t *testing.T) {
	store := openProvisionTestStore(t)
	defer closeProvisionTestStore(t, store)

	svc := NewPackInstallService(store, &fakeHostAdapter{})
	loaded := sampleLoadedPack()
	if _, err := svc.Install(context.Background(), PackInstallRequest{Pack: loaded}); err != nil {
		t.Fatalf("initial Install() error = %v", err)
	}

	upgraded := sampleLoadedPack()
	upgraded.Manifest.Version = "2.0.0"
	upgraded.Checksum = "checksum-2"
	result, err := svc.Install(context.Background(), PackInstallRequest{Pack: upgraded})
	if err != nil {
		t.Fatalf("upgraded Install() error = %v", err)
	}
	if !result.AlreadyInstalled {
		t.Fatal("AlreadyInstalled = false, want true for pre-existing pack upgrade")
	}
	if result.Pack.Version != upgraded.Manifest.Version {
		t.Fatalf("Pack.Version = %q, want %q", result.Pack.Version, upgraded.Manifest.Version)
	}
	if result.Pack.Checksum != upgraded.Checksum {
		t.Fatalf("Pack.Checksum = %q, want %q", result.Pack.Checksum, upgraded.Checksum)
	}
	if got := queryCount(t, store.SQLDB(), "packs"); got != 1 {
		t.Fatalf("packs row count after upgrade = %d, want 1", got)
	}
	if got := queryCount(t, store.SQLDB(), "providers"); got != 1 {
		t.Fatalf("providers row count after upgrade = %d, want 1", got)
	}
}

func TestPackInstallServiceInstallValidatesDependencies(t *testing.T) {
	loaded := sampleLoadedPack()
	storeWithoutHost := openProvisionTestStore(t)
	defer closeProvisionTestStore(t, storeWithoutHost)
	storeWithoutPack := openProvisionTestStore(t)
	defer closeProvisionTestStore(t, storeWithoutPack)

	if _, err := (*PackInstallService)(nil).Install(context.Background(), PackInstallRequest{Pack: loaded}); err == nil || err.Error() != "store is required" {
		t.Fatalf("nil service Install() error = %v, want store is required", err)
	}
	if _, err := (&PackInstallService{store: storeWithoutHost}).Install(context.Background(), PackInstallRequest{Pack: loaded}); err == nil || err.Error() != "host adapter is required" {
		t.Fatalf("missing host Install() error = %v, want host adapter is required", err)
	}
	if _, err := NewPackInstallService(storeWithoutPack, &fakeHostAdapter{}).Install(context.Background(), PackInstallRequest{}); err == nil || err.Error() != "pack manifest is required" {
		t.Fatalf("missing pack Install() error = %v, want pack manifest is required", err)
	}
}

func sampleLoadedPack() pack.LoadedPack {
	provider := sampleProviderManifest()
	return pack.LoadedPack{
		Manifest: pack.Manifest{
			PackID:         "openai-cn-pack",
			Version:        "1.0.0",
			Vendor:         "nous",
			TargetHost:     "sub2api",
			MinHostVersion: "0.1.126",
			MaxHostVersion: "0.2.x",
		},
		Providers: []pack.ProviderManifest{provider},
		Checksum:  "checksum-1",
	}
}

func TestValidateExistingPack(t *testing.T) {
	existing := sqlite.Pack{PackID: "openai-cn-pack", Version: "1.0.0", Checksum: "checksum-1"}
	if err := validateExistingPack(existing, sampleLoadedPack()); err != nil {
		t.Fatalf("validateExistingPack() error = %v, want nil", err)
	}
}
