package service

import (
	"strings"
	"testing"
)

func TestExtractDeployStepName(t *testing.T) {
	tests := []struct {
		name     string
		stepYaml string
		want     string
	}{
		{
			name: "service template with deploy step",
			stepYaml: `build-studio-api:
  depends_on: [preflight]
  image: woodpeckerci/plugin-kaniko

deploy-studio-api:
  depends_on: [verify-studio-api]
  image: bitnami/kubectl:latest`,
			want: "deploy-studio-api",
		},
		{
			name: "worker template with deploy step",
			stepYaml: `build-processor:
  depends_on: [preflight]

deploy-processor:
  image: bitnami/kubectl:latest`,
			want: "deploy-processor",
		},
		{
			name: "CLI template without deploy step",
			stepYaml: `build-mytool:
  depends_on: [deps]
  image: golang:1.25-alpine
  commands:
    - go build ./cmd`,
			want: "",
		},
		{
			name: "empty input",
			stepYaml: "",
			want:     "",
		},
		{
			name: "hyphenated component name",
			stepYaml: `deploy-my-cool-service:
  image: bitnami/kubectl:latest`,
			want: "deploy-my-cool-service",
		},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			got := extractDeployStepName(tc.stepYaml)
			if got != tc.want {
				t.Errorf("extractDeployStepName() = %q, want %q", got, tc.want)
			}
		})
	}
}

func TestAddBuildCompleteDep(t *testing.T) {
	baseYml := `steps:
  preflight:
    depends_on: [deps]
    image: alpine/curl

  # COMPONENT_STEPS_BELOW

  build-complete:
    depends_on: [preflight] # BUILD_COMPLETE_DEPS
    image: alpine:3.19
    commands:
      - echo "All component builds complete"`

	tests := []struct {
		name     string
		yml      string
		stepName string
		wantDeps string
	}{
		{
			name:     "first component added",
			yml:      baseYml,
			stepName: "deploy-studio-api",
			wantDeps: "depends_on: [preflight, deploy-studio-api] # BUILD_COMPLETE_DEPS",
		},
		{
			name: "second component added",
			yml: strings.Replace(baseYml,
				"depends_on: [preflight] # BUILD_COMPLETE_DEPS",
				"depends_on: [preflight, deploy-studio-api] # BUILD_COMPLETE_DEPS", 1),
			stepName: "deploy-studio-ui",
			wantDeps: "depends_on: [preflight, deploy-studio-api, deploy-studio-ui] # BUILD_COMPLETE_DEPS",
		},
		{
			name:     "duplicate detection",
			yml:      strings.Replace(baseYml, "depends_on: [preflight] # BUILD_COMPLETE_DEPS", "depends_on: [preflight, deploy-studio-api] # BUILD_COMPLETE_DEPS", 1),
			stepName: "deploy-studio-api",
			wantDeps: "depends_on: [preflight, deploy-studio-api] # BUILD_COMPLETE_DEPS",
		},
		{
			name:     "missing marker returns unchanged",
			yml:      "steps:\n  build-complete:\n    image: alpine:3.19",
			stepName: "deploy-foo",
			wantDeps: "",
		},
	}

	for _, tc := range tests {
		t.Run(tc.name, func(t *testing.T) {
			got := addBuildCompleteDep(tc.yml, tc.stepName)

			if tc.wantDeps == "" {
				// Expect no change
				if got != tc.yml {
					t.Errorf("expected unchanged yml, but got modification")
				}
				return
			}

			if !strings.Contains(got, tc.wantDeps) {
				t.Errorf("result does not contain expected depends_on line\nwant: %s\ngot:\n%s", tc.wantDeps, got)
			}
		})
	}
}

func TestAddBuildCompleteDep_PreservesIndentation(t *testing.T) {
	yml := `steps:
    build-complete:
        depends_on: [preflight] # BUILD_COMPLETE_DEPS
        image: alpine:3.19`

	got := addBuildCompleteDep(yml, "deploy-foo")

	// The indentation (8 spaces) should be preserved
	want := "        depends_on: [preflight, deploy-foo] # BUILD_COMPLETE_DEPS"
	if !strings.Contains(got, want) {
		t.Errorf("indentation not preserved\nwant line: %q\ngot:\n%s", want, got)
	}
}

func TestUpdateWoodpeckerYml_WiresBuildCompleteDeps(t *testing.T) {
	skeleton := `steps:
  preflight:
    depends_on: [deps]
    image: alpine/curl

  # COMPONENT_STEPS_BELOW
  # Do not remove the marker above

  build-complete:
    depends_on: [preflight] # BUILD_COMPLETE_DEPS
    image: alpine:3.19
    commands:
      - echo "All component builds complete"`

	stepYaml := `build-studio-api:
  depends_on: [preflight]
  image: woodpeckerci/plugin-kaniko

verify-studio-api:
  depends_on: [build-studio-api]
  image: alpine/curl

deploy-studio-api:
  depends_on: [verify-studio-api]
  image: bitnami/kubectl:latest`

	svc := &ComponentService{}
	result := svc.updateWoodpeckerYml(skeleton, stepYaml)

	// Verify step YAML was inserted after marker
	if !strings.Contains(result, "  build-studio-api:") {
		t.Error("component build step not inserted")
	}
	if !strings.Contains(result, "  verify-studio-api:") {
		t.Error("component verify step not inserted")
	}
	if !strings.Contains(result, "  deploy-studio-api:") {
		t.Error("component deploy step not inserted")
	}

	// Verify build-complete depends_on was updated
	if !strings.Contains(result, "depends_on: [preflight, deploy-studio-api] # BUILD_COMPLETE_DEPS") {
		t.Errorf("build-complete depends_on not updated\ngot:\n%s", result)
	}

	// Verify marker is preserved for future components
	if !strings.Contains(result, "# COMPONENT_STEPS_BELOW") {
		t.Error("COMPONENT_STEPS_BELOW marker was removed")
	}
}

func TestUpdateWoodpeckerYml_TwoComponents(t *testing.T) {
	skeleton := `steps:
  preflight:
    depends_on: [deps]

  # COMPONENT_STEPS_BELOW

  build-complete:
    depends_on: [preflight] # BUILD_COMPLETE_DEPS
    image: alpine:3.19`

	step1 := `build-studio-api:
  depends_on: [preflight]

verify-studio-api:
  depends_on: [build-studio-api]

deploy-studio-api:
  depends_on: [verify-studio-api]`

	step2 := `build-studio-ui:
  depends_on: [preflight]

verify-studio-ui:
  depends_on: [build-studio-ui]

deploy-studio-ui:
  depends_on: [verify-studio-ui]`

	svc := &ComponentService{}

	// Add first component
	result := svc.updateWoodpeckerYml(skeleton, step1)

	// Add second component
	result = svc.updateWoodpeckerYml(result, step2)

	// Both deploy steps should be in build-complete depends_on
	if !strings.Contains(result, "depends_on: [preflight, deploy-studio-api, deploy-studio-ui] # BUILD_COMPLETE_DEPS") {
		t.Errorf("build-complete doesn't depend on both deploy steps\ngot:\n%s", result)
	}
}

func TestUpdateWoodpeckerYml_CLISkipsBuildCompleteDep(t *testing.T) {
	skeleton := `steps:
  # COMPONENT_STEPS_BELOW

  build-complete:
    depends_on: [preflight] # BUILD_COMPLETE_DEPS
    image: alpine:3.19`

	cliStep := `build-mytool:
  depends_on: [deps]
  image: golang:1.25-alpine
  commands:
    - go build ./cmd`

	svc := &ComponentService{}
	result := svc.updateWoodpeckerYml(skeleton, cliStep)

	// CLI has no deploy step, so build-complete should stay unchanged
	if !strings.Contains(result, "depends_on: [preflight] # BUILD_COMPLETE_DEPS") {
		t.Errorf("build-complete was modified for CLI component (no deploy step)\ngot:\n%s", result)
	}
}

func TestUpdateWoodpeckerYml_MissingMarker(t *testing.T) {
	noMarker := `steps:
  build:
    image: golang:1.25`

	svc := &ComponentService{}
	result := svc.updateWoodpeckerYml(noMarker, "deploy-foo:\n  image: test")

	if result != noMarker {
		t.Error("expected unchanged yml when marker is missing")
	}
}
