package config_test

import (
	"strings"
	"testing"

	"github.com/leonmika/wails-release/internal/config"
)

func TestLoad_PopulatesAllFieldsFromEnv(t *testing.T) {
	env := map[string]string{
		"INPUT_WORKING_DIRECTORY":           "apps/desktop",
		"INPUT_APP_NAME":                    "MyApp",
		"INPUT_VERSION":                     "1.2.3",
		"INPUT_WAILS_VERSION":               "v2.11.0",
		"INPUT_EXTRA_BUILD_FLAGS":           "-tags release",
		"INPUT_DEVELOPER_ID_CERT_BASE64":    "Y2VydA==",
		"INPUT_DEVELOPER_ID_CERT_PASSWORD":  "pw",
		"INPUT_NOTARIZATION_METHOD":         "api-key",
		"INPUT_NOTARIZATION_API_KEY_BASE64": "a2V5",
		"INPUT_NOTARIZATION_API_KEY_ID":     "ABCD1234",
		"INPUT_NOTARIZATION_API_ISSUER_ID":  "12345678-aaaa-bbbb-cccc-111111111111",
		"INPUT_S3_BUCKET":                   "my-bucket",
		"INPUT_S3_KEY":                      "releases/{version}/{filename}",
		"INPUT_S3_REGION":                   "us-east-1",
	}
	c := config.Load(envGetter(env))
	if c.WorkingDirectory != "apps/desktop" || c.AppName != "MyApp" || c.Version != "1.2.3" {
		t.Fatalf("basic fields wrong: %+v", c)
	}
	if c.NotarizationMethod != "api-key" || c.NotarizationAPIKeyID != "ABCD1234" {
		t.Fatalf("notarization fields wrong: %+v", c)
	}
	if c.S3Bucket != "my-bucket" || c.S3Key != "releases/{version}/{filename}" {
		t.Fatalf("s3 fields wrong: %+v", c)
	}
}

func TestLoad_AppliesDefaults(t *testing.T) {
	c := config.Load(envGetter(nil))
	if c.WorkingDirectory != "." {
		t.Fatalf("expected default working-directory '.', got %q", c.WorkingDirectory)
	}
	if c.S3Region != "us-east-1" {
		t.Fatalf("expected default s3-region us-east-1, got %q", c.S3Region)
	}
	if c.NotarizationMethod != "auto" {
		t.Fatalf("expected default notarization-method auto, got %q", c.NotarizationMethod)
	}
}

func TestValidate(t *testing.T) {
	base := func() *config.Config {
		return &config.Config{
			WorkingDirectory:        ".",
			DeveloperIDCertBase64:   "x",
			DeveloperIDCertPassword: "x",
			NotarizationMethod:      "auto",
			S3Region:                "us-east-1",
		}
	}

	cases := []struct {
		name   string
		mutate func(*config.Config)
		errMsg string // substring expected in error; empty means must succeed
	}{
		{
			name:   "valid with api-key group",
			mutate: func(c *config.Config) { fillAPIKey(c) },
		},
		{
			name:   "valid with apple-id group",
			mutate: func(c *config.Config) { fillAppleID(c) },
		},
		{
			name:   "missing cert base64",
			mutate: func(c *config.Config) { fillAPIKey(c); c.DeveloperIDCertBase64 = "" },
			errMsg: "developer-id-cert-base64",
		},
		{
			name:   "missing cert password",
			mutate: func(c *config.Config) { fillAPIKey(c); c.DeveloperIDCertPassword = "" },
			errMsg: "developer-id-cert-password",
		},
		{
			name:   "method=api-key with missing field",
			mutate: func(c *config.Config) { fillAPIKey(c); c.NotarizationMethod = "api-key"; c.NotarizationAPIKeyID = "" },
			errMsg: "notarization-api-key-id",
		},
		{
			name:   "method=apple-id with missing field",
			mutate: func(c *config.Config) { fillAppleID(c); c.NotarizationMethod = "apple-id"; c.NotarizationTeamID = "" },
			errMsg: "notarization-team-id",
		},
		{
			name:   "auto with both groups populated is ambiguous",
			mutate: func(c *config.Config) { fillAPIKey(c); fillAppleID(c) },
			errMsg: "ambiguous",
		},
		{
			name:   "auto with no group populated",
			mutate: func(c *config.Config) {},
			errMsg: "no notarization credentials",
		},
		{
			name:   "s3 bucket without key",
			mutate: func(c *config.Config) { fillAPIKey(c); c.S3Bucket = "b" },
			errMsg: "s3-key",
		},
		{
			name:   "unknown notarization method",
			mutate: func(c *config.Config) { fillAPIKey(c); c.NotarizationMethod = "smoke-signals" },
			errMsg: "notarization-method",
		},
	}

	for _, tc := range cases {
		t.Run(tc.name, func(t *testing.T) {
			c := base()
			tc.mutate(c)
			err := c.Validate()
			if tc.errMsg == "" {
				if err != nil {
					t.Fatalf("expected ok, got %v", err)
				}
				return
			}
			if err == nil {
				t.Fatalf("expected error containing %q, got nil", tc.errMsg)
			}
			if !strings.Contains(err.Error(), tc.errMsg) {
				t.Fatalf("error %q does not contain %q", err.Error(), tc.errMsg)
			}
		})
	}
}

func envGetter(m map[string]string) func(string) string {
	return func(k string) string { return m[k] }
}

func fillAPIKey(c *config.Config) {
	c.NotarizationAPIKeyBase64 = "k"
	c.NotarizationAPIKeyID = "id"
	c.NotarizationAPIIssuerID = "issuer"
}

func fillAppleID(c *config.Config) {
	c.NotarizationAppleID = "apple"
	c.NotarizationApplePassword = "pw"
	c.NotarizationTeamID = "team"
}
