package irc

import (
	"testing"

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

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

	t.Run("missing server", func(t *testing.T) {
		bc := &config.Channel{Type: config.ChannelIRC, Enabled: true}
		cfg := &config.IRCSettings{Nick: "bot"}
		_, err := NewIRCChannel(bc, cfg, msgBus)
		if err == nil {
			t.Error("expected error for missing server, got nil")
		}
	})

	t.Run("missing nick", func(t *testing.T) {
		bc := &config.Channel{Type: config.ChannelIRC, Enabled: true}
		cfg := &config.IRCSettings{Server: "irc.example.com:6667"}
		_, err := NewIRCChannel(bc, cfg, msgBus)
		if err == nil {
			t.Error("expected error for missing nick, got nil")
		}
	})

	t.Run("valid config", func(t *testing.T) {
		bc := &config.Channel{Type: config.ChannelIRC, Enabled: true}
		cfg := &config.IRCSettings{
			Server:   "irc.example.com:6667",
			Nick:     "testbot",
			Channels: []string{"#test"},
		}
		ch, err := NewIRCChannel(bc, cfg, msgBus)
		if err != nil {
			t.Fatalf("unexpected error: %v", err)
		}
		if ch.Name() != "irc" {
			t.Errorf("Name() = %q, want %q", ch.Name(), "irc")
		}
		if ch.IsRunning() {
			t.Error("new channel should not be running")
		}
	})
}

func TestExtractHost(t *testing.T) {
	tests := []struct {
		server string
		want   string
	}{
		{"irc.libera.chat:6697", "irc.libera.chat"},
		{"localhost:6667", "localhost"},
		{"irc.example.com", "irc.example.com"},
		{"", ""},
	}

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

func TestNickMentionedAt(t *testing.T) {
	tests := []struct {
		name    string
		content string
		nick    string
		want    int
	}{
		{"colon prefix", "bot: hello", "bot", 0},
		{"comma prefix", "bot, hello", "bot", 0},
		{"case insensitive", "BOT: hello", "bot", 0},
		{"word boundary mid", "hey bot what's up", "bot", 4},
		{"no mention", "hello world", "bot", -1},
		{"substring mismatch", "robotics are cool", "bot", -1},
		{"nick at end", "hello bot", "bot", 6},
		{"empty content", "", "bot", -1},
	}

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

func TestIsBotMentioned(t *testing.T) {
	tests := []struct {
		name    string
		content string
		nick    string
		want    bool
	}{
		{"colon prefix", "bot: hello", "bot", true},
		{"comma prefix", "bot, hello", "bot", true},
		{"case insensitive", "BOT: hello", "bot", true},
		{"word boundary mid", "hey bot what's up", "bot", true},
		{"no mention", "hello world", "bot", false},
		{"substring mismatch", "robotics are cool", "bot", false},
		{"nick at end", "hello bot", "bot", true},
		{"empty content", "", "bot", false},
	}

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

func TestStripBotMention(t *testing.T) {
	tests := []struct {
		name    string
		content string
		nick    string
		want    string
	}{
		{"colon prefix", "bot: hello there", "bot", "hello there"},
		{"comma prefix", "bot, help me", "bot", "help me"},
		{"case insensitive", "BOT: hello", "bot", "hello"},
		{"no prefix match", "hello bot", "bot", "hello bot"},
		{"only prefix", "bot:", "bot", ""},
	}

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