package dashboard

import (
	"io/fs"
	"os"
	"path/filepath"
	"regexp"
	"runtime"
	"testing"
)

func TestTemplRuntimePolicyIsDeterministic(t *testing.T) {
	policy := templRuntimePolicy()

	if policy.Mode != "checked-in-generated" {
		t.Fatalf("expected deterministic templ mode checked-in-generated, got %q", policy.Mode)
	}
	if policy.RuntimeGenerationAllowed {
		t.Fatal("expected runtime generation to be disabled")
	}
	if policy.GenerateCommand == "" {
		t.Fatal("expected explicit templ generate command policy")
	}
}

// TestStaticAssetByteFloors asserts that the embedded StaticFS contains real
// (non-stub) static assets. Satisfies REQ-100.
func TestStaticAssetByteFloors(t *testing.T) {
	tests := []struct {
		name     string
		path     string
		minBytes int64
	}{
		{
			name:     "htmx.min.js",
			path:     "static/htmx.min.js",
			minBytes: 40_000,
		},
		{
			name:     "pico.min.css",
			path:     "static/pico.min.css",
			minBytes: 60_000,
		},
		{
			name:     "styles.css",
			path:     "static/styles.css",
			minBytes: 20_000,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			info, err := fs.Stat(StaticFS, tt.path)
			if err != nil {
				t.Fatalf("fs.Stat(%q) failed: %v\nPossible cause: static asset not embedded or path is wrong.", tt.path, err)
			}
			if info.Size() < tt.minBytes {
				t.Fatalf(
					"%s size = %d bytes; expected >= %d bytes.\nPossible cause: the file is still a stub. Copy the real asset from engram-cloud/internal/cloud/dashboard/static/.",
					tt.path, info.Size(), tt.minBytes,
				)
			}
		})
	}
}

// TestTemplGeneratedFilesAreCheckedIn asserts that the templ-generated *_templ.go
// files are committed alongside the .templ sources. Satisfies REQ-101.
func TestTemplGeneratedFilesAreCheckedIn(t *testing.T) {
	_, callerFile, _, ok := runtime.Caller(0)
	if !ok {
		t.Fatal("runtime.Caller failed")
	}
	pkgDir := filepath.Dir(callerFile)

	headerRe := regexp.MustCompile(`(?m)^// Code generated by templ`)

	tests := []struct {
		name     string
		file     string
		minBytes int64
	}{
		{
			name:     "components_templ.go",
			file:     "components_templ.go",
			minBytes: 100_000,
		},
		{
			name:     "layout_templ.go",
			file:     "layout_templ.go",
			minBytes: 1,
		},
		{
			name:     "login_templ.go",
			file:     "login_templ.go",
			minBytes: 1,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			fullPath := filepath.Join(pkgDir, tt.file)
			info, err := os.Stat(fullPath)
			if err != nil {
				t.Fatalf(
					"%s not found at %s: %v\nPossible cause: the *.templ sources changed but the generated *_templ.go files were not committed. Run `make templ` and commit the regenerated files.",
					tt.file, fullPath, err,
				)
			}
			if info.Size() < tt.minBytes {
				t.Fatalf(
					"%s size = %d bytes; expected >= %d bytes.\nPossible cause: the *.templ sources changed but the generated *_templ.go files were not committed. Run `make templ` (or `go tool templ generate ./internal/cloud/dashboard/...`) and commit the regenerated files.",
					tt.file, info.Size(), tt.minBytes,
				)
			}
			content, err := os.ReadFile(fullPath)
			if err != nil {
				t.Fatalf("os.ReadFile(%s) failed: %v", fullPath, err)
			}
			preview := content
			if len(preview) > 1024 {
				preview = preview[:1024]
			}
			if !headerRe.Match(preview) {
				t.Fatalf(
					"%s does not start with '// Code generated by templ' header.\nFirst 1024 bytes: %q\nPossible cause: the file is hand-written, not generated. Run `make templ` and commit.",
					tt.file, string(preview),
				)
			}
		})
	}
}
