package config_test

import (
	"strings"
	"testing"

	"bit.admedia.com/scm/ad/adpilot-indexing-repo-sync.com/internal/config"
)

func TestLoadDefaults(t *testing.T) {
	t.Setenv("PORT", "")
	t.Setenv("ENVIRONMENT", "local")
	t.Setenv("REDIS_URL", "")
	t.Setenv("REDIS_STREAM_PREFIX", "")
	t.Setenv("GIT_WORKSPACE_PATH", "")
	t.Setenv("BITBUCKET_BASE_URL", "")
	t.Setenv("BITBUCKET_USERNAME", "")
	t.Setenv("BITBUCKET_TOKEN", "")
	t.Setenv("BITBUCKET_WEBHOOK_SECRET", "")
	t.Setenv("MONGO_URI", "")
	t.Setenv("MONGODB_DATABASE", "")

	cfg, err := config.Load("repo-sync-service", 6001)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if cfg.Port != 6001 {
		t.Fatalf("expected port 6001, got %d", cfg.Port)
	}
	if cfg.Address() != "0.0.0.0:6001" {
		t.Fatalf("unexpected address: %s", cfg.Address())
	}
	if cfg.Redis.URL != "redis://localhost:6379" {
		t.Fatalf("unexpected redis url: %s", cfg.Redis.URL)
	}
	if cfg.Redis.StreamPrefix != "" {
		t.Fatalf("expected empty stream prefix, got %q", cfg.Redis.StreamPrefix)
	}
	if cfg.Git.WorkspacePath != "./data/repos" {
		t.Fatalf("unexpected workspace path: %s", cfg.Git.WorkspacePath)
	}
	if cfg.Bitbucket.BaseURL != "https://bit.admedia.com" {
		t.Fatalf("unexpected bitbucket base url: %s", cfg.Bitbucket.BaseURL)
	}
	if cfg.Bitbucket.Username != "" {
		t.Fatalf("expected empty username in local env")
	}
	if cfg.Bitbucket.Token != "" {
		t.Fatalf("expected empty token in local env")
	}
	if cfg.Bitbucket.WebhookSecret != "" {
		t.Fatalf("expected empty webhook secret in local env")
	}
	if cfg.Mongo.URI != "mongodb://localhost:27018/adpilot_repo_sync" {
		t.Fatalf("unexpected mongo uri: %s", cfg.Mongo.URI)
	}
	if cfg.Mongo.Database != "adpilot_repo_sync" {
		t.Fatalf("unexpected mongo database: %s", cfg.Mongo.Database)
	}
}

func TestLoadEnvOverrides(t *testing.T) {
	t.Setenv("ENVIRONMENT", "local")
	t.Setenv("REDIS_URL", "redis://redis.example:6380")
	t.Setenv("REDIS_STREAM_PREFIX", "staging.")
	t.Setenv("GIT_WORKSPACE_PATH", "/var/repos")
	t.Setenv("BITBUCKET_BASE_URL", "https://bitbucket.example.com")
	t.Setenv("BITBUCKET_USERNAME", "user@example.com")
	t.Setenv("BITBUCKET_TOKEN", "token")
	t.Setenv("BITBUCKET_WEBHOOK_SECRET", "secret")
	t.Setenv("MONGO_URI", "mongodb://mongo.example:27018/custom")
	t.Setenv("MONGODB_DATABASE", "custom_db")

	cfg, err := config.Load("repo-sync-service", 6001)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if cfg.Redis.URL != "redis://redis.example:6380" {
		t.Fatalf("unexpected redis url: %s", cfg.Redis.URL)
	}
	if cfg.Redis.StreamPrefix != "staging." {
		t.Fatalf("unexpected stream prefix: %s", cfg.Redis.StreamPrefix)
	}
	if cfg.Git.WorkspacePath != "/var/repos" {
		t.Fatalf("unexpected workspace path: %s", cfg.Git.WorkspacePath)
	}
	if cfg.Bitbucket.BaseURL != "https://bitbucket.example.com" {
		t.Fatalf("unexpected bitbucket base url: %s", cfg.Bitbucket.BaseURL)
	}
	if cfg.Bitbucket.Username != "user@example.com" {
		t.Fatalf("unexpected username: %s", cfg.Bitbucket.Username)
	}
	if cfg.Bitbucket.Token != "token" {
		t.Fatalf("unexpected token: %s", cfg.Bitbucket.Token)
	}
	if cfg.Bitbucket.WebhookSecret != "secret" {
		t.Fatalf("unexpected webhook secret: %s", cfg.Bitbucket.WebhookSecret)
	}
	if cfg.Mongo.URI != "mongodb://mongo.example:27018/custom" {
		t.Fatalf("unexpected mongo uri: %s", cfg.Mongo.URI)
	}
	if cfg.Mongo.Database != "custom_db" {
		t.Fatalf("unexpected mongo database: %s", cfg.Mongo.Database)
	}
}

func TestValidateNonLocalMissingFields(t *testing.T) {
	t.Setenv("ENVIRONMENT", "staging")
	t.Setenv("REDIS_URL", "")
	t.Setenv("GIT_WORKSPACE_PATH", "")
	t.Setenv("BITBUCKET_BASE_URL", "")
	t.Setenv("BITBUCKET_USERNAME", "")
	t.Setenv("BITBUCKET_TOKEN", "")
	t.Setenv("BITBUCKET_WEBHOOK_SECRET", "")
	t.Setenv("MONGO_URI", "")
	t.Setenv("MONGODB_DATABASE", "")

	_, err := config.Load("repo-sync-service", 6001)
	if err == nil {
		t.Fatal("expected validation error")
	}
	msg := err.Error()
	for _, field := range []string{"REDIS_URL", "GIT_WORKSPACE_PATH", "BITBUCKET_BASE_URL", "BITBUCKET_USERNAME", "BITBUCKET_TOKEN", "BITBUCKET_WEBHOOK_SECRET", "MONGO_URI", "MONGODB_DATABASE"} {
		if !strings.Contains(msg, field) {
			t.Fatalf("expected error to mention %s, got: %s", field, msg)
		}
	}
}

func TestValidateNonLocalOK(t *testing.T) {
	t.Setenv("ENVIRONMENT", "staging")
	t.Setenv("REDIS_URL", "redis://redis.example:6379")
	t.Setenv("GIT_WORKSPACE_PATH", "/var/repos")
	t.Setenv("BITBUCKET_BASE_URL", "https://bit.admedia.com")
	t.Setenv("BITBUCKET_USERNAME", "user@example.com")
	t.Setenv("BITBUCKET_TOKEN", "token")
	t.Setenv("BITBUCKET_WEBHOOK_SECRET", "secret")
	t.Setenv("MONGO_URI", "mongodb://mongo.example:6379/adpilot_repo_sync")
	t.Setenv("MONGODB_DATABASE", "adpilot_repo_sync")

	cfg, err := config.Load("repo-sync-service", 6001)
	if err != nil {
		t.Fatalf("unexpected error: %v", err)
	}
	if cfg.Environment != "staging" {
		t.Fatalf("expected staging environment, got %s", cfg.Environment)
	}
}

func TestRedisStreamName(t *testing.T) {
	tests := []struct {
		name   string
		prefix string
		base   string
		want   string
	}{
		{name: "no prefix", prefix: "", base: "repo.snapshot.ready", want: "repo.snapshot.ready"},
		{name: "prefix without dot", prefix: "staging", base: "files.changed", want: "staging.files.changed"},
		{name: "prefix with dot", prefix: "staging.", base: "commits.changed", want: "staging.commits.changed"},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			r := config.RedisConfig{StreamPrefix: tt.prefix}
			if got := r.StreamName(tt.base); got != tt.want {
				t.Fatalf("StreamName() = %q, want %q", got, tt.want)
			}
		})
	}
}
