package storage

import (
	"context"
	"errors"
	"io"
	"strings"
	"testing"
)

func TestValidateKey(t *testing.T) {
	valid := []string{
		"did:plc:xyz123/go-mod-v1",
		"did:web:spindle.example.com/cache.tar",
		"abc",
		"a/b/c/d",
	}
	for _, k := range valid {
		if err := ValidateKey(k); err != nil {
			t.Errorf("ValidateKey(%q) = %v, want nil", k, err)
		}
	}

	invalid := []string{
		"",
		"../escape",
		"a/../../b",
		"/leading",
		"trailing/",
		"double//slash",
		"with space",
		"with\\backslash",
		"-leading-dash",
	}
	for _, k := range invalid {
		if err := ValidateKey(k); err == nil {
			t.Errorf("ValidateKey(%q) = nil, want error", k)
		}
	}
}

func TestDiskRoundTrip(t *testing.T) {
	ctx := context.Background()
	d, err := NewDisk(t.TempDir())
	if err != nil {
		t.Fatal(err)
	}

	key := "did:plc:xyz/go-mod-v1"
	if err := d.Put(ctx, key, strings.NewReader("archive-bytes")); err != nil {
		t.Fatal(err)
	}

	rc, err := d.Get(ctx, key)
	if err != nil {
		t.Fatal(err)
	}
	got, err := io.ReadAll(rc)
	rc.Close()
	if err != nil {
		t.Fatal(err)
	}
	if string(got) != "archive-bytes" {
		t.Fatalf("got %q, want %q", got, "archive-bytes")
	}

	// overwrite
	if err := d.Put(ctx, key, strings.NewReader("new-bytes")); err != nil {
		t.Fatal(err)
	}
	rc, _ = d.Get(ctx, key)
	got, _ = io.ReadAll(rc)
	rc.Close()
	if string(got) != "new-bytes" {
		t.Fatalf("overwrite: got %q, want %q", got, "new-bytes")
	}

	if err := d.Delete(ctx, key); err != nil {
		t.Fatalf("delete: %v", err)
	}
	if _, err := d.Get(ctx, key); !errors.Is(err, ErrNotExist) {
		t.Fatalf("get deleted: got %v, want ErrNotExist", err)
	}
	if err := d.Delete(ctx, key); err != nil {
		t.Fatalf("delete missing: %v", err)
	}
}

func TestDiskRejectsTraversal(t *testing.T) {
	ctx := context.Background()
	d, err := NewDisk(t.TempDir())
	if err != nil {
		t.Fatal(err)
	}
	if err := d.Put(ctx, "../evil", strings.NewReader("x")); err == nil {
		t.Fatal("put with traversal key succeeded")
	}
	if _, err := d.Get(ctx, "../evil"); err == nil {
		t.Fatal("get with traversal key succeeded")
	}
}
