package slack

import (
	"testing"

	"github.com/sipeed/picoclaw/pkg/bus"
	"github.com/sipeed/picoclaw/pkg/config"
)

func TestParseSlackChatID(t *testing.T) {
	tests := []struct {
		name       string
		chatID     string
		wantChanID string
		wantThread string
	}{
		{
			name:       "channel only",
			chatID:     "C123456",
			wantChanID: "C123456",
			wantThread: "",
		},
		{
			name:       "channel with thread",
			chatID:     "C123456/1234567890.123456",
			wantChanID: "C123456",
			wantThread: "1234567890.123456",
		},
		{
			name:       "DM channel",
			chatID:     "D987654",
			wantChanID: "D987654",
			wantThread: "",
		},
		{
			name:       "empty string",
			chatID:     "",
			wantChanID: "",
			wantThread: "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			chanID, threadTS := parseSlackChatID(tt.chatID)
			if chanID != tt.wantChanID {
				t.Errorf("parseSlackChatID(%q) channelID = %q, want %q", tt.chatID, chanID, tt.wantChanID)
			}
			if threadTS != tt.wantThread {
				t.Errorf("parseSlackChatID(%q) threadTS = %q, want %q", tt.chatID, threadTS, tt.wantThread)
			}
		})
	}
}

func TestResolveSlackOutboundTarget_PrefersContextTopicID(t *testing.T) {
	deliveryChatID, channelID, threadTS := resolveSlackOutboundTarget("C123456", &bus.InboundContext{
		Channel: "slack",
		ChatID:  "C123456",
		TopicID: "1234567890.123456",
	})

	if deliveryChatID != "C123456/1234567890.123456" {
		t.Fatalf("deliveryChatID = %q, want %q", deliveryChatID, "C123456/1234567890.123456")
	}
	if channelID != "C123456" {
		t.Fatalf("channelID = %q, want %q", channelID, "C123456")
	}
	if threadTS != "1234567890.123456" {
		t.Fatalf("threadTS = %q, want %q", threadTS, "1234567890.123456")
	}
}

func TestStripBotMention(t *testing.T) {
	ch := &SlackChannel{botUserID: "U12345BOT"}

	tests := []struct {
		name  string
		input string
		want  string
	}{
		{
			name:  "mention at start",
			input: "<@U12345BOT> hello there",
			want:  "hello there",
		},
		{
			name:  "mention in middle",
			input: "hey <@U12345BOT> can you help",
			want:  "hey  can you help",
		},
		{
			name:  "no mention",
			input: "hello world",
			want:  "hello world",
		},
		{
			name:  "empty string",
			input: "",
			want:  "",
		},
		{
			name:  "only mention",
			input: "<@U12345BOT>",
			want:  "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			got := ch.stripBotMention(tt.input)
			if got != tt.want {
				t.Errorf("stripBotMention(%q) = %q, want %q", tt.input, got, tt.want)
			}
		})
	}
}

func TestNewSlackChannel(t *testing.T) {
	msgBus := bus.NewMessageBus()
	bc := &config.Channel{Type: "slack", Enabled: true}

	t.Run("missing bot token", func(t *testing.T) {
		cfg := &config.SlackSettings{}
		cfg.AppToken = *config.NewSecureString("xapp-test")
		_, err := NewSlackChannel(bc, cfg, msgBus)
		if err == nil {
			t.Error("expected error for missing bot_token, got nil")
		}
	})

	t.Run("missing app token", func(t *testing.T) {
		cfg := &config.SlackSettings{}
		cfg.BotToken = *config.NewSecureString("xoxb-test")
		_, err := NewSlackChannel(bc, cfg, msgBus)
		if err == nil {
			t.Error("expected error for missing app_token, got nil")
		}
	})

	t.Run("valid config", func(t *testing.T) {
		cfg := &config.SlackSettings{}
		cfg.BotToken = *config.NewSecureString("xoxb-test")
		cfg.AppToken = *config.NewSecureString("xapp-test")
		bc := &config.Channel{Type: "slack", Enabled: true, AllowFrom: []string{"U123"}}
		ch, err := NewSlackChannel(bc, cfg, msgBus)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if ch.Name() != "slack" {
			t.Errorf("Name() = %q, want %q", ch.Name(), "slack")
		}
		if ch.IsRunning() {
			t.Error("new channel should not be running")
		}
	})
}

func TestSlackChannelIsAllowed(t *testing.T) {
	msgBus := bus.NewMessageBus()

	t.Run("empty allowlist allows all", func(t *testing.T) {
		bc := &config.Channel{Type: config.ChannelSlack, Enabled: true, AllowFrom: []string{}}
		cfg := &config.SlackSettings{}
		cfg.BotToken = *config.NewSecureString("xoxb-test")
		cfg.AppToken = *config.NewSecureString("xapp-test")
		ch, _ := NewSlackChannel(bc, cfg, msgBus)
		if !ch.IsAllowed("U_ANYONE") {
			t.Error("empty allowlist should allow all users")
		}
	})

	t.Run("allowlist restricts users", func(t *testing.T) {
		bc := &config.Channel{Type: config.ChannelSlack, Enabled: true, AllowFrom: []string{"U_ALLOWED"}}
		cfg := &config.SlackSettings{}
		cfg.BotToken = *config.NewSecureString("xoxb-test")
		cfg.AppToken = *config.NewSecureString("xapp-test")
		ch, _ := NewSlackChannel(bc, cfg, msgBus)
		if !ch.IsAllowed("U_ALLOWED") {
			t.Error("allowed user should pass allowlist check")
		}
		if ch.IsAllowed("U_BLOCKED") {
			t.Error("non-allowed user should be blocked")
		}
	})
}
