package billing

import (
	"context"
	"testing"

	"bookra/apps/backend/internal/config"
	"bookra/apps/backend/internal/db"
	"bookra/apps/backend/internal/domain"
)

func testConfig() config.Config {
	return config.Config{
		FrontendURL:      "http://localhost:3000",
		PaddleAPIKey:     "pdl_sdbx_apikey_123",
		PaddleWebhookKey: "pdl_ntf_123",
		PaddlePriceMatrix: map[string]map[string]string{
			"starter":  {"czk": "pri_starter_czk", "usd": "pri_starter_usd"},
			"pro":      {"czk": "pri_pro_czk", "usd": "pri_pro_usd"},
			"business": {"czk": "pri_business_czk", "usd": "pri_business_usd"},
		},
	}
}

func TestGetSubscriptionFallsBackToSnapshotAndEntitlements(t *testing.T) {
	service := NewService(testConfig(), db.NewMemoryRepository())

	snapshot, err := service.GetSubscription(context.Background(), domain.Principal{
		Subject: "demo-owner",
		Email:   "owner@bookra.dev",
	})
	if err != nil {
		t.Fatalf("get subscription: %v", err)
	}

	if snapshot.PlanCode != "pro" {
		t.Fatalf("expected pro, got %s", snapshot.PlanCode)
	}
	if snapshot.Provider != "paddle" {
		t.Fatalf("expected paddle provider, got %s", snapshot.Provider)
	}
	if snapshot.Entitlements.MaxLocations != 3 {
		t.Fatalf("expected 3 locations, got %d", snapshot.Entitlements.MaxLocations)
	}
}

func TestCreateCheckoutRequiresPaddleConfig(t *testing.T) {
	cfg := testConfig()
	cfg.PaddleAPIKey = ""
	service := NewService(cfg, db.NewMemoryRepository())

	response, err := service.CreateCheckoutSession(context.Background(), domain.Principal{
		Subject: "demo-owner",
		Email:   "owner@bookra.dev",
	}, "pro", "czk", "monthly")
	if err != ErrPaddleNotConfigured {
		t.Fatalf("expected ErrPaddleNotConfigured, got response=%v err=%v", response, err)
	}
}

func TestCreateCheckoutReturnsLaunchPayload(t *testing.T) {
	service := NewService(testConfig(), db.NewMemoryRepository())

	response, err := service.CreateCheckoutSession(context.Background(), domain.Principal{
		Subject: "demo-owner",
		Email:   "owner@bookra.dev",
	}, "pro", "czk", "monthly")
	if err != nil {
		t.Fatalf("create checkout: %v", err)
	}
	if response.PriceID != "pri_pro_czk" {
		t.Fatalf("expected pri_pro_czk, got %s", response.PriceID)
	}
	if response.CustomData["tenantId"] == "" {
		t.Fatal("expected tenantId in customData")
	}
	if response.SuccessRedirectURL == "" || response.CancelRedirectURL == "" {
		t.Fatal("expected redirect URLs")
	}
}

func TestRefreshRequiresPaddleKeyWhenCustomerExists(t *testing.T) {
	cfg := testConfig()
	cfg.PaddleAPIKey = ""
	service := NewService(cfg, db.NewMemoryRepository())

	snapshot, err := service.Refresh(context.Background(), domain.Principal{
		Subject: "demo-owner",
		Email:   "owner@bookra.dev",
	})
	if err != ErrPaddleNotConfigured {
		t.Fatalf("expected ErrPaddleNotConfigured, got snapshot=%v err=%v", snapshot, err)
	}
}

func TestGetSubscriptionDisablesCheckoutWhenWebhookMissing(t *testing.T) {
	cfg := testConfig()
	cfg.PaddleWebhookKey = ""
	service := NewService(cfg, db.NewMemoryRepository())

	snapshot, err := service.GetSubscription(context.Background(), domain.Principal{
		Subject: "demo-owner",
		Email:   "owner@bookra.dev",
	})
	if err != nil {
		t.Fatalf("get subscription: %v", err)
	}
	if snapshot.CheckoutURLAvailable {
		t.Fatal("expected checkout unavailable without webhook secret")
	}
}

func TestGetSubscriptionEnablesCheckoutWhenPaddleConfigured(t *testing.T) {
	service := NewService(testConfig(), db.NewMemoryRepository())

	snapshot, err := service.GetSubscription(context.Background(), domain.Principal{
		Subject: "demo-owner",
		Email:   "owner@bookra.dev",
	})
	if err != nil {
		t.Fatalf("get subscription: %v", err)
	}
	if !snapshot.CheckoutURLAvailable {
		t.Fatal("expected checkout available when paddle is configured")
	}
	if !snapshot.PortalAvailable {
		t.Fatal("expected portal available when customer exists")
	}
}

func TestCreatePortalSessionRequiresCustomer(t *testing.T) {
	repo := db.NewMemoryRepository()
	membership, err := repo.GetTenantMembershipByUserID(context.Background(), "demo-owner")
	if err != nil {
		t.Fatalf("get membership: %v", err)
	}
	if err := repo.UpdateTenantBillingCustomerID(context.Background(), membership.Tenant.ID, ""); err != nil {
		t.Fatalf("clear billing customer: %v", err)
	}
	service := NewService(testConfig(), repo)

	_, err = service.CreatePortalSession(context.Background(), domain.Principal{
		Subject: "demo-owner",
		Email:   "owner@bookra.dev",
	})
	if err != ErrBillingCustomerMissing {
		t.Fatalf("expected ErrBillingCustomerMissing, got %v", err)
	}
}
