package store_test

import (
	"context"
	"errors"
	"os"
	"path/filepath"
	"strings"
	"testing"

	"bit.admedia.com/scm/ad/adpilot-indexing-commit-intel.com/internal/contracts/graph"
	"bit.admedia.com/scm/ad/adpilot-indexing-commit-intel.com/internal/store"
)

func TestLoadDeltaByURI(t *testing.T) {
	dir := t.TempDir()
	copyDeltaFixture(t, dir, "delta_sample.json", "delta_target456_a1b2.json")

	reader, err := store.NewFilesystemReader(dir)
	if err != nil {
		t.Fatalf("NewFilesystemReader: %v", err)
	}

	uri := "file://" + filepath.Join(dir, "delta_target456_a1b2.json")
	delta, err := reader.LoadDeltaByURI(context.Background(), uri)
	if err != nil {
		t.Fatalf("LoadDeltaByURI: %v", err)
	}
	if delta.RepoID != "ad/example" {
		t.Fatalf("repo_id: got %q", delta.RepoID)
	}
	if len(delta.ChangedFiles) != 1 || delta.ChangedFiles[0] != "internal/main.go" {
		t.Fatalf("changed_files: %#v", delta.ChangedFiles)
	}
	if len(delta.FileDeltas) != 1 {
		t.Fatalf("file_deltas: got %d", len(delta.FileDeltas))
	}
	added, removed, _ := delta.Counts()
	if added != 1 || removed != 1 {
		t.Fatalf("counts: added=%d removed=%d", added, removed)
	}
}

func TestLoadDeltaByID(t *testing.T) {
	dir := t.TempDir()
	copyDeltaFixture(t, dir, "delta_sample.json", "delta_target456_a1b2.json")

	reader, err := store.NewFilesystemReader(dir)
	if err != nil {
		t.Fatalf("NewFilesystemReader: %v", err)
	}

	delta, err := reader.LoadDeltaByID(context.Background(), "delta_target456_a1b2")
	if err != nil {
		t.Fatalf("LoadDeltaByID: %v", err)
	}
	if delta.TargetCommitSHA != "target4567890ab" {
		t.Fatalf("target_commit_sha: got %q", delta.TargetCommitSHA)
	}
}

func TestLoadDeltaByURINotFound(t *testing.T) {
	dir := t.TempDir()
	reader, err := store.NewFilesystemReader(dir)
	if err != nil {
		t.Fatalf("NewFilesystemReader: %v", err)
	}

	uri := "file://" + filepath.Join(dir, "missing.json")
	_, err = reader.LoadDeltaByURI(context.Background(), uri)
	if err == nil {
		t.Fatal("expected error")
	}
	if !errors.Is(err, store.ErrArtifactNotFound) {
		t.Fatalf("expected ErrArtifactNotFound, got %v", err)
	}
}

func TestLoadDeltaInvalidSchemaVersion(t *testing.T) {
	dir := t.TempDir()
	path := filepath.Join(dir, "delta_bad.json")
	payload := `{
		"schema_version": "v2",
		"repo_id": "ad/example",
		"base_commit_sha": "base",
		"target_commit_sha": "target"
	}`
	if err := os.WriteFile(path, []byte(payload), 0o644); err != nil {
		t.Fatalf("write file: %v", err)
	}

	reader, err := store.NewFilesystemReader(dir)
	if err != nil {
		t.Fatalf("NewFilesystemReader: %v", err)
	}

	_, err = reader.LoadDeltaByURI(context.Background(), "file://"+path)
	if err == nil {
		t.Fatal("expected schema validation error")
	}
	if !strings.Contains(err.Error(), "schema_version") {
		t.Fatalf("unexpected error: %v", err)
	}
}

func TestLoadDeltaByIDInvalidID(t *testing.T) {
	reader, err := store.NewFilesystemReader(t.TempDir())
	if err != nil {
		t.Fatalf("NewFilesystemReader: %v", err)
	}

	_, err = reader.LoadDeltaByID(context.Background(), "../escape")
	if !errors.Is(err, store.ErrInvalidArtifactID) {
		t.Fatalf("expected ErrInvalidArtifactID, got %v", err)
	}
}

func TestLoadDeltaURIOutsideStore(t *testing.T) {
	storeDir := t.TempDir()
	otherDir := t.TempDir()
	otherFile := filepath.Join(otherDir, "outside.json")
	if err := os.WriteFile(otherFile, []byte(`{"schema_version":"v1","repo_id":"x","base_commit_sha":"a","target_commit_sha":"b"}`), 0o644); err != nil {
		t.Fatalf("write file: %v", err)
	}

	reader, err := store.NewFilesystemReader(storeDir)
	if err != nil {
		t.Fatalf("NewFilesystemReader: %v", err)
	}

	_, err = reader.LoadDeltaByURI(context.Background(), "file://"+otherFile)
	if err == nil {
		t.Fatal("expected path outside store error")
	}
	if !strings.Contains(err.Error(), "outside artifact store") {
		t.Fatalf("unexpected error: %v", err)
	}
}

func TestLoadArtifactByURI(t *testing.T) {
	dir := t.TempDir()
	path := filepath.Join(dir, "art_snap_01_deadbeef.json")
	payload := `{
		"schema_version": "v1",
		"repo_id": "ad/example",
		"snapshot_id": "snap_01",
		"commit_sha": "abc123",
		"nodes": [
			{"id": "file:main.go", "kind": "file", "name": "main.go", "path": "main.go"}
		],
		"edges": []
	}`
	if err := os.WriteFile(path, []byte(payload), 0o644); err != nil {
		t.Fatalf("write file: %v", err)
	}

	reader, err := store.NewFilesystemReader(dir)
	if err != nil {
		t.Fatalf("NewFilesystemReader: %v", err)
	}

	artifact, err := reader.LoadArtifactByURI(context.Background(), "file://"+path)
	if err != nil {
		t.Fatalf("LoadArtifactByURI: %v", err)
	}
	if artifact.CommitSHA != "abc123" {
		t.Fatalf("commit_sha: got %q", artifact.CommitSHA)
	}
	if len(artifact.Nodes) != 1 {
		t.Fatalf("nodes: got %d", len(artifact.Nodes))
	}
}

func copyDeltaFixture(t *testing.T, dir, srcName, destName string) {
	t.Helper()
	data, err := os.ReadFile(filepath.Join("testdata", srcName))
	if err != nil {
		t.Fatalf("read fixture: %v", err)
	}
	if err := os.WriteFile(filepath.Join(dir, destName), data, 0o644); err != nil {
		t.Fatalf("write fixture: %v", err)
	}
}

func TestFilesystemReaderSatisfiesArtifactReader(t *testing.T) {
	var _ interface {
		LoadArtifactByURI(context.Context, string) (graph.Artifact, error)
		LoadDeltaByURI(context.Context, string) (graph.Delta, error)
	} = (*store.FilesystemReader)(nil)
}
