package emit

import (
	"encoding/json"
	"strings"
	"testing"
)

func TestArtifactValidate_valid(t *testing.T) {
	a := &Artifact{
		SchemaVersion: SchemaVersion,
		Kind:          KindSystemd,
		Path:          "/etc/systemd/system/orca-alloc.service",
		Content:       "[Service]\nExecStart=/bin/true\n",
		Mode:          "0644",
	}
	if err := a.Validate(); err != nil {
		t.Fatalf("expected valid, got %v", err)
	}
}

func TestArtifactValidate_schemaVersionMismatch(t *testing.T) {
	a := &Artifact{SchemaVersion: "orca.emit/v0", Kind: KindSystemd, Path: "/x", Mode: "0644"}
	err := a.Validate()
	if err == nil {
		t.Fatal("expected error for mismatched schema_version")
	}
	if !strings.Contains(err.Error(), "schema_version mismatch") {
		t.Fatalf("expected schema_version error, got %v", err)
	}
}

func TestArtifactValidate_missingKind(t *testing.T) {
	a := &Artifact{SchemaVersion: SchemaVersion, Path: "/x", Mode: "0644"}
	err := a.Validate()
	if err == nil || !strings.Contains(err.Error(), "kind is required") {
		t.Fatalf("expected kind-required error, got %v", err)
	}
}

func TestArtifactValidate_missingPath(t *testing.T) {
	a := &Artifact{SchemaVersion: SchemaVersion, Kind: KindTraefik, Mode: "0644"}
	err := a.Validate()
	if err == nil || !strings.Contains(err.Error(), "path is required") {
		t.Fatalf("expected path-required error, got %v", err)
	}
}

func TestArtifactValidate_missingMode(t *testing.T) {
	a := &Artifact{SchemaVersion: SchemaVersion, Kind: KindSudoers, Path: "/x"}
	err := a.Validate()
	if err == nil || !strings.Contains(err.Error(), "mode is required") {
		t.Fatalf("expected mode-required error, got %v", err)
	}
}

func TestMarshalValidate_rejectsInvalid(t *testing.T) {
	a := &Artifact{SchemaVersion: "bad", Kind: "", Path: "", Mode: ""}
	if _, err := a.Marshal(); err == nil {
		t.Fatal("expected Marshal to reject invalid artifact")
	}
}

func TestUnmarshalArtifact_valid(t *testing.T) {
	raw := `{"schema_version":"orca.emit/v1","kind":"systemd","path":"/x","content":"c","mode":"0644"}`
	a, err := UnmarshalArtifact([]byte(raw))
	if err != nil {
		t.Fatalf("expected valid, got %v", err)
	}
	if a.Kind != KindSystemd {
		t.Fatalf("expected kind systemd, got %s", a.Kind)
	}
}

func TestUnmarshalArtifact_rejectsBadJSON(t *testing.T) {
	if _, err := UnmarshalArtifact([]byte("not json")); err == nil {
		t.Fatal("expected error for bad JSON")
	}
}

func TestUnmarshalArtifact_rejectsSchemaMismatch(t *testing.T) {
	raw := `{"schema_version":"orca.emit/v2","kind":"x","path":"/x","mode":"0644"}`
	if _, err := UnmarshalArtifact([]byte(raw)); err == nil {
		t.Fatal("expected error for schema mismatch")
	}
}

func TestRoundTrip(t *testing.T) {
	orig := &Artifact{
		SchemaVersion: SchemaVersion,
		Kind:          KindSyncthing,
		Path:          "/etc/syncthing/config.xml",
		Content:       "<config/>",
		Mode:          "0600",
	}
	data, err := orig.Marshal()
	if err != nil {
		t.Fatalf("Marshal: %v", err)
	}
	back, err := UnmarshalArtifact(data)
	if err != nil {
		t.Fatalf("Unmarshal: %v", err)
	}
	if back.Path != orig.Path || back.Kind != orig.Kind || back.Mode != orig.Mode {
		t.Fatalf("round-trip mismatch: %+v vs %+v", orig, back)
	}
}

func TestAllKinds(t *testing.T) {
	for _, k := range []Kind{KindSystemd, KindTraefik, KindSyncthing, KindSudoers, KindSSHD, KindEnvFile, KindCredential} {
		a := &Artifact{SchemaVersion: SchemaVersion, Kind: k, Path: "/x", Mode: "0644"}
		if err := a.Validate(); err != nil {
			t.Errorf("kind %s: %v", k, err)
		}
		// verify it marshals
		if _, err := json.Marshal(a); err != nil {
			t.Errorf("marshal kind %s: %v", k, err)
		}
	}
}
