package message

import (
	"testing"
)

func TestParse_CommandWithPrefix(t *testing.T) {
	opts := ParseOptions{
		CommandPrefix: "!",
		BotUserID:     "@bot:server",
	}

	tests := []struct {
		name    string
		body    string
		wantCmd string
		wantArgs []string
	}{
		{
			name:    "standard command",
			body:    "!help",
			wantCmd: "help",
		},
		{
			name:     "command with args",
			body:     "!deploy prod",
			wantCmd:  "deploy",
			wantArgs: []string{"prod"},
		},
		{
			name:    "no prefix means no command",
			body:    "help",
			wantCmd: "",
		},
		{
			name:    "normal message",
			body:    "hola mundo",
			wantCmd: "",
		},
		{
			name:    "command is lowercased",
			body:    "!HELP",
			wantCmd: "help",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := Parse(tt.body, "@user:server", "!room:server", 0, false, opts)
			if ctx.Command != tt.wantCmd {
				t.Errorf("Command = %q, want %q", ctx.Command, tt.wantCmd)
			}
			if tt.wantArgs != nil {
				if len(ctx.Args) != len(tt.wantArgs) {
					t.Errorf("Args = %v, want %v", ctx.Args, tt.wantArgs)
				}
				for i, arg := range tt.wantArgs {
					if i < len(ctx.Args) && ctx.Args[i] != arg {
						t.Errorf("Args[%d] = %q, want %q", i, ctx.Args[i], arg)
					}
				}
			}
		})
	}
}

func TestParse_CommandWithoutPrefix(t *testing.T) {
	opts := ParseOptions{
		CommandPrefix: "",
		BotUserID:     "@bot:server",
	}

	tests := []struct {
		name     string
		body     string
		wantCmd  string
		wantArgs []string
	}{
		{
			name:    "bare command",
			body:    "help",
			wantCmd: "help",
		},
		{
			name:     "bare command with args",
			body:     "deploy prod",
			wantCmd:  "deploy",
			wantArgs: []string{"prod"},
		},
		{
			name:    "bang prefix stripped for backward compatibility",
			body:    "!help",
			wantCmd: "help",
		},
		{
			name:     "bang prefix stripped with args",
			body:     "!deploy staging",
			wantCmd:  "deploy",
			wantArgs: []string{"staging"},
		},
		{
			name:    "first token is command",
			body:    "hola mundo",
			wantCmd: "hola",
			wantArgs: []string{"mundo"},
		},
		{
			name:    "command is lowercased",
			body:    "HELP",
			wantCmd: "help",
		},
		{
			name:    "bang-only message produces no command",
			body:    "!",
			wantCmd: "",
		},
		{
			name:    "empty message",
			body:    "",
			wantCmd: "",
		},
		{
			name:    "whitespace-only message",
			body:    "   ",
			wantCmd: "",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			ctx := Parse(tt.body, "@user:server", "!room:server", 0, false, opts)
			if ctx.Command != tt.wantCmd {
				t.Errorf("Command = %q, want %q", ctx.Command, tt.wantCmd)
			}
			if tt.wantArgs != nil {
				if len(ctx.Args) != len(tt.wantArgs) {
					t.Errorf("Args = %v, want %v", ctx.Args, tt.wantArgs)
				}
				for i, arg := range tt.wantArgs {
					if i < len(ctx.Args) && ctx.Args[i] != arg {
						t.Errorf("Args[%d] = %q, want %q", i, ctx.Args[i], arg)
					}
				}
			}
		})
	}
}

func TestParse_MentionDetection(t *testing.T) {
	// Ensure mention detection still works regardless of command prefix mode.
	botUID := "@bot:server"

	tests := []struct {
		name        string
		body        string
		mentions    []string
		wantMention bool
	}{
		{
			name:        "mentioned via m.mentions",
			body:        "hello",
			mentions:    []string{botUID},
			wantMention: true,
		},
		{
			name:        "mentioned via body text",
			body:        "hey @bot:server what's up",
			wantMention: true,
		},
		{
			name:        "not mentioned",
			body:        "hello world",
			wantMention: false,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			opts := ParseOptions{
				CommandPrefix:    "!",
				BotUserID:        botUID,
				MentionedUserIDs: tt.mentions,
			}
			ctx := Parse(tt.body, "@user:server", "!room:server", 0, false, opts)
			if ctx.IsMention != tt.wantMention {
				t.Errorf("IsMention = %v, want %v", ctx.IsMention, tt.wantMention)
			}
		})
	}
}

func TestParse_NoPrefixBackwardCompatibility(t *testing.T) {
	// Regression: when prefix is "" and user sends "!help", the result should be
	// identical to when prefix is "!" and user sends "!help".
	prefixed := Parse("!help", "@user:server", "!room:server", 0, false, ParseOptions{
		CommandPrefix: "!",
		BotUserID:     "@bot:server",
	})
	noPrefix := Parse("!help", "@user:server", "!room:server", 0, false, ParseOptions{
		CommandPrefix: "",
		BotUserID:     "@bot:server",
	})

	if prefixed.Command != noPrefix.Command {
		t.Errorf("Command mismatch: prefixed=%q, noPrefix=%q", prefixed.Command, noPrefix.Command)
	}
	if len(prefixed.Args) != len(noPrefix.Args) {
		t.Errorf("Args length mismatch: prefixed=%v, noPrefix=%v", prefixed.Args, noPrefix.Args)
	}
}
