package deployments

import (
	"os"
	"path/filepath"
	"runtime"
	"strings"
	"testing"

	"gopkg.in/yaml.v3"
)

func repoRoot(t *testing.T) string {
	t.Helper()

	_, filename, _, ok := runtime.Caller(0)
	if !ok {
		t.Fatalf("failed to resolve caller path")
	}

	return filepath.Clean(filepath.Join(filepath.Dir(filename), "..", "..", ".."))
}

func asMap(t *testing.T, v any) map[string]any {
	t.Helper()

	m, ok := v.(map[string]any)
	if !ok {
		t.Fatalf("expected map[string]any, got %T", v)
	}
	return m
}

func asSlice(t *testing.T, v any) []any {
	t.Helper()

	s, ok := v.([]any)
	if !ok {
		t.Fatalf("expected []any, got %T", v)
	}
	return s
}

func TestProdTraefikComposeHasExpectedConfig(t *testing.T) {
	t.Parallel()

	composePath := filepath.Join(repoRoot(t), "deployments", "docker-compose.prod.yml")
	b, err := os.ReadFile(composePath)
	if err != nil {
		t.Fatalf("read compose file: %v", err)
	}

	var doc map[string]any
	if err := yaml.Unmarshal(b, &doc); err != nil {
		t.Fatalf("parse compose yaml: %v", err)
	}

	services := asMap(t, doc["services"])
	api := asMap(t, services["api-server"])

	labels := asSlice(t, api["labels"])
	labelStrs := make([]string, 0, len(labels))
	for _, l := range labels {
		ls, ok := l.(string)
		if !ok {
			t.Fatalf("expected label string, got %T", l)
		}
		labelStrs = append(labelStrs, ls)
	}

	wantLabelPrefixes := []string{
		"traefik.enable=true",
		"traefik.docker.network=",
		"traefik.http.services.fetchml.loadbalancer.server.port=9101",
		"traefik.http.routers.fetchml.rule=",
		"traefik.http.routers.fetchml.entrypoints=",
		"traefik.http.routers.fetchml.tls=true",
	}

	for _, wantPrefix := range wantLabelPrefixes {
		found := false
		for _, l := range labelStrs {
			if strings.HasPrefix(l, wantPrefix) {
				found = true
				break
			}
		}
		if !found {
			t.Fatalf("missing label with prefix %q; labels=%v", wantPrefix, labelStrs)
		}
	}

	nets := asSlice(t, api["networks"])
	foundTraefikNet := false
	for _, n := range nets {
		ns, ok := n.(string)
		if !ok {
			t.Fatalf("expected network name string, got %T", n)
		}
		if ns == "traefik" {
			foundTraefikNet = true
			break
		}
	}
	if !foundTraefikNet {
		t.Fatalf("api-server is not attached to traefik network; networks=%v", nets)
	}

	networks := asMap(t, doc["networks"])
	traefik := asMap(t, networks["traefik"])

	external, ok := traefik["external"].(bool)
	if !ok {
		t.Fatalf("expected networks.traefik.external to be bool, got %T", traefik["external"])
	}
	if !external {
		t.Fatalf("expected networks.traefik.external to be true")
	}
}
