package intake

import (
	"strings"
	"testing"

	"code.chimeric.al/chimerical/raven/internal/filter"
	"code.chimeric.al/chimerical/raven/internal/imap"
	"code.chimeric.al/chimerical/raven/internal/tracker"

	goimap "github.com/emersion/go-imap/v2"
)

func TestConfigValidate(t *testing.T) {
	tests := []struct {
		name    string
		cfg     Config
		wantErr bool
	}{
		{
			name: "valid idle mode",
			cfg: Config{
				Mode:         ModeIdle,
				PollInterval: "30s",
			},
			wantErr: false,
		},
		{
			name: "valid poll mode",
			cfg: Config{
				Mode:         ModePoll,
				PollInterval: "5m",
			},
			wantErr: false,
		},
		{
			name: "valid poll mode with long interval",
			cfg: Config{
				Mode:         ModePoll,
				PollInterval: "24h",
			},
			wantErr: false,
		},
		{
			name: "invalid mode",
			cfg: Config{
				Mode:         "invalid",
				PollInterval: "30s",
			},
			wantErr: true,
		},
		{
			name: "empty mode",
			cfg: Config{
				Mode:         "",
				PollInterval: "30s",
			},
			wantErr: true,
		},
		{
			name: "missing poll interval",
			cfg: Config{
				Mode:         ModeIdle,
				PollInterval: "",
			},
			wantErr: true,
		},
		{
			name: "invalid poll interval",
			cfg: Config{
				Mode:         ModePoll,
				PollInterval: "invalid",
			},
			wantErr: true,
		},
		{
			name: "zero poll interval",
			cfg: Config{
				Mode:         ModePoll,
				PollInterval: "0s",
			},
			wantErr: true,
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			err := tt.cfg.Validate()
			if (err != nil) != tt.wantErr {
				t.Errorf(
					"Validate() error = %v, wantErr %v",
					err, tt.wantErr,
				)
			}
		})
	}
}

func TestModeValid(t *testing.T) {
	tests := []struct {
		mode Mode
		want bool
	}{
		{ModeIdle, true},
		{ModePoll, true},
		{"idle", true},
		{"poll", true},
		{"", false},
		{"invalid", false},
		{"IDLE", false},
		{"POLL", false},
	}

	for _, tt := range tests {
		t.Run(string(tt.mode), func(t *testing.T) {
			if got := tt.mode.Valid(); got != tt.want {
				t.Errorf(
					"Mode(%q).Valid() = %v, want %v",
					tt.mode, got, tt.want,
				)
			}
		})
	}
}

func TestModeString(t *testing.T) {
	tests := []struct {
		mode Mode
		want string
	}{
		{ModeIdle, "idle"},
		{ModePoll, "poll"},
		{"custom", "custom"},
	}

	for _, tt := range tests {
		t.Run(tt.want, func(t *testing.T) {
			if got := tt.mode.String(); got != tt.want {
				t.Errorf(
					"Mode.String() = %v, want %v",
					got, tt.want,
				)
			}
		})
	}
}

func TestNewWorkerValidation(t *testing.T) {
	validConfig := Config{
		Mode:         ModeIdle,
		PollInterval: "30s",
	}
	validTracker := tracker.New()
	validWork := make(chan goimap.UID, 1)

	tests := []struct {
		name    string
		cfg     Config
		tracker *tracker.Tracker
		work    chan goimap.UID
		wantErr string
	}{
		{
			name:    "nil tracker",
			cfg:     validConfig,
			tracker: nil,
			work:    validWork,
			wantErr: "missing tracker",
		},
		{
			name:    "nil work channel",
			cfg:     validConfig,
			tracker: validTracker,
			work:    nil,
			wantErr: "missing work channel",
		},
		{
			name: "invalid config",
			cfg: Config{
				Mode:         "invalid",
				PollInterval: "30s",
			},
			tracker: validTracker,
			work:    validWork,
			wantErr: "invalid config",
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			_, err := NewWorker(
				tt.cfg,
				filter.Filters{},
				imap.Config{},
				nil, // log
				tt.tracker,
				tt.work,
			)
			if err == nil {
				t.Fatal("NewWorker() expected error, got nil")
			}
			if !strings.Contains(err.Error(), tt.wantErr) {
				t.Errorf(
					"NewWorker() error = %q, want containing %q",
					err.Error(), tt.wantErr,
				)
			}
		})
	}
}
