package imap_test

import (
	"testing"
	"time"

	"inboxer/src/internal/imap"
)

func TestNewClient(t *testing.T) {
	cfg := imap.Config{
		Host:     "imap.example.com",
		Port:     993,
		User:     "user",
		Password: "pass",
		TLS:      true,
	}

	cl := imap.NewClient(cfg)
	if cl == nil {
		t.Fatal("expected non-nil client")
	}
}

func TestConfigValues(t *testing.T) {
	tests := []struct {
		name   string
		config imap.Config
	}{
		{
			name: "TLS config",
			config: imap.Config{
				Host:     "imap.example.com",
				Port:     993,
				User:     "user",
				Password: "pass",
				TLS:      true,
			},
		},
		{
			name: "plain config",
			config: imap.Config{
				Host:     "imap.example.com",
				Port:     143,
				User:     "user",
				Password: "pass",
				TLS:      false,
			},
		},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			c := imap.NewClient(tt.config)
			if c == nil {
				t.Fatal("NewClient returned nil")
			}
		})
	}
}

func TestConnectInvalid(t *testing.T) {
	// Test with invalid host / connection refused
	cfg := imap.Config{
		Host:     "127.0.0.1",
		Port:     1, // unlikely to be open
		User:     "test",
		Password: "test",
		TLS:      false,
	}

	cl := imap.NewClient(cfg)
	err := cl.Connect()
	if err == nil {
		t.Fatal("expected connection error on invalid port")
	}
}

func TestEnsureConnectedNeverConnected(t *testing.T) {
	cfg := imap.Config{
		Host:     "127.0.0.1",
		Port:     1,
		User:     "test",
		Password: "test",
		TLS:      false,
	}

	cl := imap.NewClient(cfg)
	err := cl.EnsureConnected()
	if err == nil {
		t.Fatal("expected error on connecting to closed port")
	}
}

func TestCloseIdempotent(t *testing.T) {
	cfg := imap.Config{
		Host:     "imap.example.com",
		Port:     993,
		User:     "test",
		Password: "test",
		TLS:      true,
	}

	cl := imap.NewClient(cfg)
	// Close when never connected should not panic
	err := cl.Close()
	if err != nil {
		t.Fatalf("unexpected error on close: %v", err)
	}
}

func TestSelectMailboxNotConnected(t *testing.T) {
	cfg := imap.Config{
		Host:     "imap.example.com",
		Port:     993,
		User:     "test",
		Password: "test",
		TLS:      true,
	}

	cl := imap.NewClient(cfg)
	_, err := cl.SelectMailbox("INBOX", true)
	if err == nil {
		t.Fatal("expected error on select with no connection")
	}
}

func TestFetchUnseenNotConnected(t *testing.T) {
	cfg := imap.Config{
		Host:     "imap.example.com",
		Port:     993,
		User:     "test",
		Password: "test",
		TLS:      true,
	}

	cl := imap.NewClient(cfg)
	_, _, err := cl.FetchUnseen("INBOX")
	if err == nil {
		t.Fatal("expected error on fetch with no connection")
	}
}

func TestMoveMessagesNotConnected(t *testing.T) {
	cfg := imap.Config{
		Host:     "imap.example.com",
		Port:     993,
		User:     "test",
		Password: "test",
		TLS:      true,
	}

	cl := imap.NewClient(cfg)
	err := cl.MoveMessages("INBOX", []uint32{1}, "INBOX/Archive")
	if err == nil {
		t.Fatal("expected error on move with no connection")
	}
}

func TestEnsureFoldersNoConnection(t *testing.T) {
	cfg := imap.Config{
		Host:     "imap.example.com",
		Port:     993,
		User:     "test",
		Password: "test",
		TLS:      true,
	}

	cl := imap.NewClient(cfg)
	err := cl.EnsureFolders([]string{"INBOX/Work"})
	if err == nil {
		t.Fatal("expected error with no connection")
	}
}

func TestCountUnseenNotConnected(t *testing.T) {
	cfg := imap.Config{
		Host:     "imap.example.com",
		Port:     993,
		User:     "test",
		Password: "test",
		TLS:      true,
	}

	cl := imap.NewClient(cfg)
	_, err := cl.CountUnseen("INBOX")
	if err == nil {
		t.Fatal("expected error with no connection")
	}
}

func TestFetchBatchNotConnected(t *testing.T) {
	cfg := imap.Config{
		Host:     "imap.example.com",
		Port:     993,
		User:     "test",
		Password: "test",
		TLS:      true,
	}

	cl := imap.NewClient(cfg)
	_, _, err := cl.FetchBatch("INBOX", 1, 100, 10)
	if err == nil {
		t.Fatal("expected error with no connection")
	}
}

func TestCopyMessagesNotConnected(t *testing.T) {
	cfg := imap.Config{
		Host:     "imap.example.com",
		Port:     993,
		User:     "test",
		Password: "test",
		TLS:      true,
	}

	cl := imap.NewClient(cfg)
	err := cl.CopyMessages("INBOX", []uint32{1}, "INBOX/Archive")
	if err == nil {
		t.Fatal("expected error with no connection")
	}
}

func TestMarkSeenNotConnected(t *testing.T) {
	cfg := imap.Config{
		Host:     "imap.example.com",
		Port:     993,
		User:     "test",
		Password: "test",
		TLS:      true,
	}

	cl := imap.NewClient(cfg)
	err := cl.MarkSeen("INBOX", []uint32{1})
	if err == nil {
		t.Fatal("expected error with no connection")
	}
}

func TestFetchByUIDsNotConnected(t *testing.T) {
	cfg := imap.Config{
		Host:     "imap.example.com",
		Port:     993,
		User:     "test",
		Password: "test",
		TLS:      true,
	}

	cl := imap.NewClient(cfg)
	_, err := cl.FetchByUIDs("INBOX", []uint32{1})
	if err == nil {
		t.Fatal("expected error with no connection")
	}
}

func TestFetchBodySectionNotConnected(t *testing.T) {
	cfg := imap.Config{
		Host:     "imap.example.com",
		Port:     993,
		User:     "test",
		Password: "test",
		TLS:      true,
	}

	cl := imap.NewClient(cfg)
	_, err := cl.FetchBodySection("INBOX", 1, nil)
	if err == nil {
		t.Fatal("expected error with no connection")
	}
}

// TestEmailSummaryFields validates EmailSummary struct
func TestEmailSummaryFields(t *testing.T) {
	now := time.Now()
	s := imap.EmailSummary{
		UID:       42,
		Subject:   "Test",
		From:      "user@example.com",
		Date:      now,
		MessageID: "<abc@example.com>",
		Body:      "Hello world",
	}

	if s.UID != 42 {
		t.Errorf("expected UID 42, got %d", s.UID)
	}
	if s.Subject != "Test" {
		t.Errorf("expected Subject Test, got %s", s.Subject)
	}
	if s.From != "user@example.com" {
		t.Errorf("expected From user@example.com, got %s", s.From)
	}
	if s.MessageID != "<abc@example.com>" {
		t.Errorf("expected MessageID, got %s", s.MessageID)
	}
	if s.Body != "Hello world" {
		t.Errorf("expected body text, got %s", s.Body)
	}
}

func TestIsConnected(t *testing.T) {
	cfg := imap.Config{
		Host:     "imap.example.com",
		Port:     993,
		User:     "test",
		Password: "test",
		TLS:      true,
	}

	cl := imap.NewClient(cfg)
	if cl.IsConnected() {
		t.Fatal("should not be connected after NewClient")
	}
}

func TestLoggedOutNoConnection(t *testing.T) {
	cfg := imap.Config{
		Host:     "imap.example.com",
		Port:     993,
		User:     "test",
		Password: "test",
		TLS:      true,
	}

	cl := imap.NewClient(cfg)
	ch := cl.LoggedOut()
	// Channel should be closed immediately (no connection)
	select {
	case <-ch:
		// OK, closed
	default:
		t.Fatal("expected logged out channel to be closed when not connected")
	}
}
