package models

import (
	"testing"
)

func TestCarryoverMonthsCap(t *testing.T) {
	// Verify the constant is set correctly
	if CarryoverMonthsCap != 5 {
		t.Errorf("CarryoverMonthsCap should be 5, got %d", CarryoverMonthsCap)
	}
}

func TestCalculateMaxTaskBalance(t *testing.T) {
	tests := []struct {
		name            string
		monthlyAllowance int
		expected        int
	}{
		{"Basic plan", 30, 150},
		{"Standard plan", 100, 500},
		{"Premium plan", 1000, 5000},
		{"Zero allowance", 0, 0},
		{"Single task", 1, 5},
	}

	for _, tt := range tests {
		t.Run(tt.name, func(t *testing.T) {
			result := CalculateMaxTaskBalance(tt.monthlyAllowance)
			if result != tt.expected {
				t.Errorf("CalculateMaxTaskBalance(%d) = %d, expected %d",
					tt.monthlyAllowance, result, tt.expected)
			}
		})
	}
}

func TestGetDefaultPlans(t *testing.T) {
	plans := GetDefaultPlans()

	if len(plans) != 3 {
		t.Fatalf("Expected 3 plans, got %d", len(plans))
	}

	// Test Basic plan
	basic := plans[0]
	if basic.ID != PlanBasic {
		t.Errorf("First plan should be Basic, got %s", basic.ID)
	}
	if basic.PriceCents != 990 {
		t.Errorf("Basic price should be 990 cents, got %d", basic.PriceCents)
	}
	if basic.Features.MonthlyTaskAllowance != 30 {
		t.Errorf("Basic monthly allowance should be 30, got %d", basic.Features.MonthlyTaskAllowance)
	}
	if basic.Features.MaxTaskBalance != 150 {
		t.Errorf("Basic max balance should be 150, got %d", basic.Features.MaxTaskBalance)
	}
	if basic.Features.FairUseMode {
		t.Error("Basic should not have FairUseMode")
	}

	// Test Standard plan
	standard := plans[1]
	if standard.ID != PlanStandard {
		t.Errorf("Second plan should be Standard, got %s", standard.ID)
	}
	if standard.PriceCents != 1990 {
		t.Errorf("Standard price should be 1990 cents, got %d", standard.PriceCents)
	}
	if standard.Features.MonthlyTaskAllowance != 100 {
		t.Errorf("Standard monthly allowance should be 100, got %d", standard.Features.MonthlyTaskAllowance)
	}
	if !standard.Features.BatchProcessing {
		t.Error("Standard should have BatchProcessing")
	}
	if !standard.Features.CustomTemplates {
		t.Error("Standard should have CustomTemplates")
	}

	// Test Premium plan
	premium := plans[2]
	if premium.ID != PlanPremium {
		t.Errorf("Third plan should be Premium, got %s", premium.ID)
	}
	if premium.PriceCents != 3990 {
		t.Errorf("Premium price should be 3990 cents, got %d", premium.PriceCents)
	}
	if !premium.Features.FairUseMode {
		t.Error("Premium should have FairUseMode")
	}
	if !premium.Features.PrioritySupport {
		t.Error("Premium should have PrioritySupport")
	}
	if !premium.Features.CustomBranding {
		t.Error("Premium should have CustomBranding")
	}
}

func TestPlanIDConstants(t *testing.T) {
	if PlanBasic != "basic" {
		t.Errorf("PlanBasic should be 'basic', got '%s'", PlanBasic)
	}
	if PlanStandard != "standard" {
		t.Errorf("PlanStandard should be 'standard', got '%s'", PlanStandard)
	}
	if PlanPremium != "premium" {
		t.Errorf("PlanPremium should be 'premium', got '%s'", PlanPremium)
	}
}

func TestSubscriptionStatusConstants(t *testing.T) {
	statuses := []struct {
		status   SubscriptionStatus
		expected string
	}{
		{StatusTrialing, "trialing"},
		{StatusActive, "active"},
		{StatusPastDue, "past_due"},
		{StatusCanceled, "canceled"},
		{StatusExpired, "expired"},
	}

	for _, tt := range statuses {
		if string(tt.status) != tt.expected {
			t.Errorf("Status %s should be '%s'", tt.status, tt.expected)
		}
	}
}

func TestTaskTypeConstants(t *testing.T) {
	types := []struct {
		taskType TaskType
		expected string
	}{
		{TaskTypeCorrection, "correction"},
		{TaskTypeLetter, "letter"},
		{TaskTypeMeeting, "meeting"},
		{TaskTypeBatch, "batch"},
		{TaskTypeOther, "other"},
	}

	for _, tt := range types {
		if string(tt.taskType) != tt.expected {
			t.Errorf("TaskType %s should be '%s'", tt.taskType, tt.expected)
		}
	}
}

func TestPlanFeatures_CarryoverCalculation(t *testing.T) {
	plans := GetDefaultPlans()

	for _, plan := range plans {
		expectedMax := plan.Features.MonthlyTaskAllowance * CarryoverMonthsCap
		if plan.Features.MaxTaskBalance != expectedMax {
			t.Errorf("Plan %s: MaxTaskBalance should be %d (allowance * 5), got %d",
				plan.ID, expectedMax, plan.Features.MaxTaskBalance)
		}
	}
}

func TestBillingPlan_AllPlansActive(t *testing.T) {
	plans := GetDefaultPlans()

	for _, plan := range plans {
		if !plan.IsActive {
			t.Errorf("Plan %s should be active", plan.ID)
		}
	}
}

func TestBillingPlan_CurrencyIsEuro(t *testing.T) {
	plans := GetDefaultPlans()

	for _, plan := range plans {
		if plan.Currency != "eur" {
			t.Errorf("Plan %s currency should be 'eur', got '%s'", plan.ID, plan.Currency)
		}
	}
}

func TestBillingPlan_IntervalIsMonth(t *testing.T) {
	plans := GetDefaultPlans()

	for _, plan := range plans {
		if plan.Interval != "month" {
			t.Errorf("Plan %s interval should be 'month', got '%s'", plan.ID, plan.Interval)
		}
	}
}

func TestBillingPlan_SortOrder(t *testing.T) {
	plans := GetDefaultPlans()

	for i, plan := range plans {
		expectedOrder := i + 1
		if plan.SortOrder != expectedOrder {
			t.Errorf("Plan %s sort order should be %d, got %d",
				plan.ID, expectedOrder, plan.SortOrder)
		}
	}
}

func TestTaskUsageInfo_FormatStrings(t *testing.T) {
	usage := TaskUsageInfo{
		TasksAvailable: 45,
		MaxTasks:       150,
		InfoText:       "Aufgaben verfuegbar: 45 von max. 150",
		TooltipText:    "Aufgaben koennen sich bis zu 5 Monate ansammeln.",
	}

	if usage.TasksAvailable != 45 {
		t.Errorf("TasksAvailable should be 45, got %d", usage.TasksAvailable)
	}
	if usage.MaxTasks != 150 {
		t.Errorf("MaxTasks should be 150, got %d", usage.MaxTasks)
	}
}

func TestCheckTaskAllowedResponse_Allowed(t *testing.T) {
	response := CheckTaskAllowedResponse{
		Allowed:        true,
		TasksAvailable: 50,
		MaxTasks:       150,
		PlanID:         PlanBasic,
	}

	if !response.Allowed {
		t.Error("Response should be allowed")
	}
	if response.Message != "" {
		t.Errorf("Message should be empty for allowed response, got '%s'", response.Message)
	}
}

func TestCheckTaskAllowedResponse_NotAllowed(t *testing.T) {
	response := CheckTaskAllowedResponse{
		Allowed:        false,
		TasksAvailable: 0,
		MaxTasks:       150,
		PlanID:         PlanBasic,
		Message:        "Dein Aufgaben-Kontingent ist aufgebraucht.",
	}

	if response.Allowed {
		t.Error("Response should not be allowed")
	}
	if response.TasksAvailable != 0 {
		t.Errorf("TasksAvailable should be 0, got %d", response.TasksAvailable)
	}
}

func TestTaskLimitError(t *testing.T) {
	err := TaskLimitError{
		Error:          "TASK_LIMIT_REACHED",
		CurrentBalance: 0,
		Plan:           PlanBasic,
	}

	if err.Error != "TASK_LIMIT_REACHED" {
		t.Errorf("Error should be 'TASK_LIMIT_REACHED', got '%s'", err.Error)
	}
	if err.CurrentBalance != 0 {
		t.Errorf("CurrentBalance should be 0, got %d", err.CurrentBalance)
	}
	if err.Plan != PlanBasic {
		t.Errorf("Plan should be basic, got '%s'", err.Plan)
	}
}

func TestConsumeTaskRequest(t *testing.T) {
	req := ConsumeTaskRequest{
		UserID:   "550e8400-e29b-41d4-a716-446655440000",
		TaskType: TaskTypeCorrection,
	}

	if req.UserID == "" {
		t.Error("UserID should not be empty")
	}
	if req.TaskType != TaskTypeCorrection {
		t.Errorf("TaskType should be correction, got '%s'", req.TaskType)
	}
}

func TestConsumeTaskResponse_Success(t *testing.T) {
	resp := ConsumeTaskResponse{
		Success:        true,
		TaskID:         "task-123",
		TasksRemaining: 49,
	}

	if !resp.Success {
		t.Error("Response should be successful")
	}
	if resp.TasksRemaining != 49 {
		t.Errorf("TasksRemaining should be 49, got %d", resp.TasksRemaining)
	}
}

func TestEntitlementInfo_Premium(t *testing.T) {
	premium := GetDefaultPlans()[2]

	info := EntitlementInfo{
		Features:        premium.Features.FeatureFlags,
		MaxTeamMembers:  premium.Features.MaxTeamMembers,
		PrioritySupport: premium.Features.PrioritySupport,
		CustomBranding:  premium.Features.CustomBranding,
		BatchProcessing: premium.Features.BatchProcessing,
		CustomTemplates: premium.Features.CustomTemplates,
		FairUseMode:     premium.Features.FairUseMode,
	}

	if !info.FairUseMode {
		t.Error("Premium should have FairUseMode")
	}
	if info.MaxTeamMembers != 10 {
		t.Errorf("Premium MaxTeamMembers should be 10, got %d", info.MaxTeamMembers)
	}
}
