package cli

import (
	"encoding/json"
	"os"
	"path/filepath"
	"strings"
	"testing"
	"time"

	"github.com/floatpane/matcha/config"
)

func testContact(name, email string, lastUsed time.Time, useCount int) config.Contact {
	return config.Contact{
		Name:  name,
		Email: email,
		Usage: map[string]config.ContactUsage{
			"account-1": {
				LastUsed: lastUsed,
				UseCount: useCount,
			},
		},
	}
}

func TestExportToJSON(t *testing.T) {
	contacts := []config.Contact{
		testContact("John Doe", "john@example.com", time.Date(2024, 1, 15, 10, 30, 0, 0, time.UTC), 5),
		testContact("Jane Smith", "jane@test.com", time.Date(2024, 2, 20, 14, 0, 0, 0, time.UTC), 10),
	}

	data, err := exportToJSON(contacts)
	if err != nil {
		t.Fatalf("exportToJSON failed: %v", err)
	}

	var result []config.Contact
	if err := json.Unmarshal(data, &result); err != nil {
		t.Fatalf("failed to unmarshal JSON: %v", err)
	}

	if len(result) != 2 {
		t.Errorf("expected 2 contacts, got %d", len(result))
	}

	if result[0].Name != "John Doe" {
		t.Errorf("expected first contact name 'John Doe', got '%s'", result[0].Name)
	}
}

func TestExportToCSV(t *testing.T) {
	contacts := []config.Contact{
		testContact("John Doe", "john@example.com", time.Date(2024, 1, 15, 10, 30, 0, 0, time.UTC), 5),
		testContact("Jane Smith", "jane@test.com", time.Date(2024, 2, 20, 14, 0, 0, 0, time.UTC), 10),
	}

	data, err := exportToCSV(contacts, false)
	if err != nil {
		t.Fatalf("exportToCSV failed: %v", err)
	}

	output := string(data)
	expectedFields := "name,email,last_used,use_count"
	if len(output) < len(expectedFields) {
		t.Fatalf("CSV output too short: %s", output)
	}

	// Check header
	if output[:len(expectedFields)] != expectedFields {
		t.Errorf("expected CSV header '%s', got '%s'", expectedFields, output[:len(expectedFields)])
	}

	// Check that both contacts are present
	if !contains(output, "john@example.com") {
		t.Error("expected john@example.com in CSV output")
	}
	if !contains(output, "jane@test.com") {
		t.Error("expected jane@test.com in CSV output")
	}
}

func TestExportToCSVNoHeader(t *testing.T) {
	contacts := []config.Contact{
		testContact("John Doe", "john@example.com", time.Date(2024, 1, 15, 10, 30, 0, 0, time.UTC), 5),
		testContact("Jane Smith", "jane@test.com", time.Date(2024, 2, 20, 14, 0, 0, 0, time.UTC), 10),
	}

	data, err := exportToCSV(contacts, true)
	if err != nil {
		t.Fatalf("exportToCSV failed: %v", err)
	}

	output := string(data)
	expectedFields := "name,email,last_used,use_count"

	// Check that header is NOT present anywhere in the output
	if strings.Contains(output, expectedFields) {
		t.Errorf("expected no CSV header, but found '%s' in output", expectedFields)
	}

	// Check that both contacts are present
	if !contains(output, "john@example.com") {
		t.Error("expected john@example.com in CSV output")
	}
	if !contains(output, "jane@test.com") {
		t.Error("expected jane@test.com in CSV output")
	}

	// Check that the first line is data, not header
	lines := strings.Split(strings.TrimSpace(output), "\n")
	if len(lines) < 2 {
		t.Fatal("expected at least 2 lines in CSV output")
	}
	firstLine := lines[0]
	if !strings.Contains(firstLine, "john@example.com") {
		t.Errorf("expected first line to contain contact email, got '%s'", firstLine)
	}
}

func TestEscapeCSV(t *testing.T) {
	tests := []struct {
		input    string
		expected string
	}{
		{"simple", "simple"},
		{"with,comma", `"with,comma"`},
		{"with\"quote", `"with""quote"`},
		{"with,comma\"both", `"with,comma""both"`},
	}

	for _, tt := range tests {
		result := escapeCSV(tt.input)
		if result != tt.expected {
			t.Errorf("escapeCSV(%q) = %q, expected %q", tt.input, result, tt.expected)
		}
	}
}

func TestExportToCSVWithSpecialChars(t *testing.T) {
	contacts := []config.Contact{
		testContact("Test, User", "test@example.com", time.Now(), 1),
		testContact(`Test "Quotes"`, "quotes@test.com", time.Now(), 2),
	}

	data, err := exportToCSV(contacts, false)
	if err != nil {
		t.Fatalf("exportToCSV failed: %v", err)
	}

	output := string(data)
	if !contains(output, `"Test, User"`) {
		t.Error("expected escaped comma in name")
	}
	// Go's csv package escapes quotes by doubling them inside quotes
	if !contains(output, `"Test ""Quotes""")`) {
		// Also check for the single-quote version that the test helper might find
		t.Logf("CSV output: %s", output)
	}
}

func contains(s, substr string) bool {
	return len(s) > 0 && len(substr) > 0 && len(s) >= len(substr) && (s == substr || len(s) > 0 && (s[:len(substr)] == substr || contains(s[1:], substr)))
}

func TestExportJSONToFile(t *testing.T) {
	tmpDir := t.TempDir()
	outputPath := filepath.Join(tmpDir, "contacts.json")

	contacts := []config.Contact{
		testContact("Test User", "test@example.com", time.Now(), 1),
	}

	data, err := exportToJSON(contacts)
	if err != nil {
		t.Fatalf("exportToJSON failed: %v", err)
	}

	if err := os.WriteFile(outputPath, data, 0644); err != nil {
		t.Fatalf("failed to write file: %v", err)
	}

	// Verify the file was written
	readData, err := os.ReadFile(outputPath)
	if err != nil {
		t.Fatalf("failed to read file: %v", err)
	}

	var result []config.Contact
	if err := json.Unmarshal(readData, &result); err != nil {
		t.Fatalf("failed to unmarshal: %v", err)
	}

	if len(result) != 1 || result[0].Email != "test@example.com" {
		t.Errorf("unexpected file contents")
	}
}

func TestExportCSVToFile(t *testing.T) {
	tmpDir := t.TempDir()
	outputPath := filepath.Join(tmpDir, "contacts.csv")

	contacts := []config.Contact{
		testContact("Test User", "test@example.com", time.Now(), 1),
	}

	data, err := exportToCSV(contacts, false)
	if err != nil {
		t.Fatalf("exportToCSV failed: %v", err)
	}

	if err := os.WriteFile(outputPath, data, 0644); err != nil {
		t.Fatalf("failed to write file: %v", err)
	}

	// Verify the file was written
	readData, err := os.ReadFile(outputPath)
	if err != nil {
		t.Fatalf("failed to read file: %v", err)
	}

	output := string(readData)
	if !contains(output, "test@example.com") {
		t.Error("expected email in CSV file")
	}
}
