//go:build test

package admin

import (
	"net/http"
	"net/http/httptest"
	"strings"
	"testing"

	"crussell/testutils"
)

func intPtr(i int) *int             { return &i }
func float64Ptr(f float64) *float64 { return &f }
func boolPtr(b bool) *bool          { return &b }

// ─── Public info ──────────────────────────────────────────────────────────────

// TestGetPublicBusinessInfo verifies that GET /business-info returns the public
// subset of business settings (no admin-only fields like currency_code,
// website_url, gift_card_expiry_months, voucher_type).
func TestGetPublicBusinessInfo(t *testing.T) {
	t.Parallel()
	ctx, tx := testutils.SetupTestTx(t)

	_, err := tx.Exec(ctx, `UPDATE business_settings SET 
		business_name = 'Test Nail Salon',
		business_address = '456 High Street',
		business_phone = '+441234567890',
		business_email = 'info@testsalon.com',
		is_vat_registered = true,
		vat_registration_number = 'GB123456789',
		default_vat_rate = 20.00,
		currency_code = 'GBP',
		website_url = 'https://testsalon.com',
		gift_card_expiry_months = 24,
		voucher_type = 'SPV'
	`)
	if err != nil {
		t.Fatalf("failed to seed business settings: %v", err)
	}

	// GetPublicBusinessInfo does NOT require admin auth — it's a public endpoint.
	handler := http.HandlerFunc(GetPublicBusinessInfo)
	req := httptest.NewRequest("GET", "/business-info", nil)
	req = req.WithContext(ctx)
	w := httptest.NewRecorder()
	handler.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
	}

	var info PublicBusinessInfo
	if err := parseResponseBody(w, &info); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}

	if info.BusinessName != "Test Nail Salon" {
		t.Errorf("expected BusinessName 'Test Nail Salon', got '%s'", info.BusinessName)
	}
	if info.BusinessAddress != "456 High Street" {
		t.Errorf("expected BusinessAddress '456 High Street', got '%s'", info.BusinessAddress)
	}
	if info.BusinessPhone == nil || *info.BusinessPhone != "+441234567890" {
		t.Errorf("expected BusinessPhone '+441234567890', got %v", info.BusinessPhone)
	}
	if info.BusinessEmail == nil || *info.BusinessEmail != "info@testsalon.com" {
		t.Errorf("expected BusinessEmail 'info@testsalon.com', got %v", info.BusinessEmail)
	}
	if !info.IsVATRegistered {
		t.Errorf("expected IsVATRegistered to be true")
	}
	if info.VATRegistrationNumber == nil || *info.VATRegistrationNumber != "GB123456789" {
		t.Errorf("expected VATRegistrationNumber 'GB123456789', got %v", info.VATRegistrationNumber)
	}
	if info.DefaultVATRate != 20.00 {
		t.Errorf("expected DefaultVATRate 20.00, got %f", info.DefaultVATRate)
	}
}

// TestGetPublicBusinessInfo_NotAdminSafe verifies that the public info endpoint
// does NOT expose admin-only fields (currency_code, website_url,
// gift_card_expiry_months, voucher_type).
func TestGetPublicBusinessInfo_NotAdminSafe(t *testing.T) {
	t.Parallel()
	ctx, tx := testutils.SetupTestTx(t)

	_, err := tx.Exec(ctx, `UPDATE business_settings SET 
		business_name = 'Test Salon', business_address = '123 St',
		currency_code = 'GBP', website_url = 'https://secret.admin.url',
		gift_card_expiry_months = 48, voucher_type = 'MPV'
	`)
	if err != nil {
		t.Fatalf("failed to seed business settings: %v", err)
	}

	handler := http.HandlerFunc(GetPublicBusinessInfo)
	req := httptest.NewRequest("GET", "/business-info", nil)
	req = req.WithContext(ctx)
	w := httptest.NewRecorder()
	handler.ServeHTTP(w, req)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
	}

	bodyStr := w.Body.String()
	// Admin-only fields MUST NOT appear in the JSON response
	if strings.Contains(bodyStr, "currency_code") {
		t.Error("expected currency_code to be excluded from public info response")
	}
	if strings.Contains(bodyStr, "website_url") {
		t.Error("expected website_url to be excluded from public info response")
	}
	if strings.Contains(bodyStr, "gift_card_expiry_months") {
		t.Error("expected gift_card_expiry_months to be excluded from public info response")
	}
	if strings.Contains(bodyStr, "voucher_type") {
		t.Error("expected voucher_type to be excluded from public info response")
	}
}

// ─── GET ─────────────────────────────────────────────────────────────────────

// TestGetBusinessSettings verifies that GET /api/admin/settings returns the
// current business settings row.
func TestGetBusinessSettings(t *testing.T) {
	ctx, tx := testutils.SetupTestTx(t)

	_, err := tx.Exec(ctx, `UPDATE business_settings SET business_name = 'Test Salon', business_address = '123 Test St', currency_code = 'GBP', gift_card_expiry_months = 12, voucher_type = 'SPV'`)
	if err != nil {
		t.Fatalf("failed to seed business settings: %v", err)
	}

	handler := http.HandlerFunc(GetBusinessSettings)
	w := makeAdminRequest(handler, "GET", "/api/admin/settings", nil, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}

	if s.BusinessName != "Test Salon" {
		t.Errorf("expected BusinessName 'Test Salon', got '%s'", s.BusinessName)
	}
	if s.BusinessAddress != "123 Test St" {
		t.Errorf("expected BusinessAddress '123 Test St', got '%s'", s.BusinessAddress)
	}
	if s.CurrencyCode != "GBP" {
		t.Errorf("expected CurrencyCode 'GBP', got '%s'", s.CurrencyCode)
	}
	if s.GiftCardExpiryMonths != 12 {
		t.Errorf("expected GiftCardExpiryMonths 12, got %d", s.GiftCardExpiryMonths)
	}
	if s.VoucherType != "SPV" {
		t.Errorf("expected VoucherType 'SPV', got '%s'", s.VoucherType)
	}
}

// ─── Successful updates ──────────────────────────────────────────────────────

// TestUpdateBusinessSettings_SingleField verifies updating a single field (business_name).
func TestUpdateBusinessSettings_SingleField(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		BusinessName: stringPtr("Updated Salon Name"),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}

	if s.BusinessName != "Updated Salon Name" {
		t.Errorf("expected BusinessName 'Updated Salon Name', got '%s'", s.BusinessName)
	}
}

// TestUpdateBusinessSettings_MultipleFields verifies that updating several fields
// at once works correctly.
func TestUpdateBusinessSettings_MultipleFields(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		BusinessName:         stringPtr("Multi Update Salon"),
		BusinessAddress:      stringPtr("456 New St"),
		BusinessPhone:        stringPtr("+441234567890"),
		BusinessEmail:        stringPtr("salon@example.com"),
		WebsiteURL:           stringPtr("https://salon.example.com"),
		GiftCardExpiryMonths: intPtr(24),
		VoucherType:          stringPtr("MPV"),
		DefaultVATRate:       float64Ptr(20.00),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}

	if s.BusinessName != "Multi Update Salon" {
		t.Errorf("expected BusinessName 'Multi Update Salon', got '%s'", s.BusinessName)
	}
	if s.BusinessAddress != "456 New St" {
		t.Errorf("expected BusinessAddress '456 New St', got '%s'", s.BusinessAddress)
	}
	if s.BusinessPhone == nil || *s.BusinessPhone != "+441234567890" {
		t.Errorf("expected BusinessPhone '+441234567890', got %v", s.BusinessPhone)
	}
	if s.BusinessEmail == nil || *s.BusinessEmail != "salon@example.com" {
		t.Errorf("expected BusinessEmail 'salon@example.com', got %v", s.BusinessEmail)
	}
	if s.WebsiteURL == nil || *s.WebsiteURL != "https://salon.example.com" {
		t.Errorf("expected WebsiteURL 'https://salon.example.com', got %v", s.WebsiteURL)
	}
	if s.GiftCardExpiryMonths != 24 {
		t.Errorf("expected GiftCardExpiryMonths 24, got %d", s.GiftCardExpiryMonths)
	}
	if s.VoucherType != "MPV" {
		t.Errorf("expected VoucherType 'MPV', got '%s'", s.VoucherType)
	}
}

// TestUpdateBusinessSettings_PartialUpdate verifies that updating a single field
// leaves other fields unchanged.
func TestUpdateBusinessSettings_PartialUpdate(t *testing.T) {
	ctx, tx := testutils.SetupTestTx(t)

	_, err := tx.Exec(ctx, `UPDATE business_settings SET business_name = 'Test Salon', business_address = '123 Test St', currency_code = 'GBP', gift_card_expiry_months = 12, voucher_type = 'SPV'`)
	if err != nil {
		t.Fatalf("failed to seed business settings: %v", err)
	}

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		GiftCardExpiryMonths: intPtr(36),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}

	if s.GiftCardExpiryMonths != 36 {
		t.Errorf("expected GiftCardExpiryMonths 36, got %d", s.GiftCardExpiryMonths)
	}
	if s.BusinessName != "Test Salon" {
		t.Errorf("expected BusinessName 'Test Salon' (unchanged), got '%s'", s.BusinessName)
	}
	if s.BusinessAddress != "123 Test St" {
		t.Errorf("expected BusinessAddress '123 Test St' (unchanged), got '%s'", s.BusinessAddress)
	}
	if s.VoucherType != "SPV" {
		t.Errorf("expected VoucherType 'SPV' (unchanged), got '%s'", s.VoucherType)
	}
	if s.CurrencyCode != "GBP" {
		t.Errorf("expected CurrencyCode 'GBP' (unchanged), got '%s'", s.CurrencyCode)
	}
}

// ─── Empty request ───────────────────────────────────────────────────────────

// TestUpdateBusinessSettings_NoFields verifies that an empty request body
// (no fields to update) returns 400.
func TestUpdateBusinessSettings_NoFields(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", UpdateBusinessSettingsRequest{}, ctx)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400, got %d. body: %s", w.Code, w.Body.String())
	}
	if w.Body.String() != "No fields to update\n" {
		t.Errorf("unexpected error message: %s", w.Body.String())
	}
}

// ─── business_name validation ────────────────────────────────────────────────

// TestUpdateBusinessSettings_Name_Empty rejects an empty business_name.
func TestUpdateBusinessSettings_Name_Empty(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		BusinessName: stringPtr(""),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400 for empty name, got %d. body: %s", w.Code, w.Body.String())
	}
	if !strings.Contains(w.Body.String(), "business_name") {
		t.Errorf("expected error about business_name, got: %s", w.Body.String())
	}
}

// TestUpdateBusinessSettings_Name_TooLong rejects a business_name > 255 chars.
func TestUpdateBusinessSettings_Name_TooLong(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	longName := strings.Repeat("A", 256)
	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		BusinessName: stringPtr(longName),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400 for long name, got %d. body: %s", w.Code, w.Body.String())
	}
	if !strings.Contains(w.Body.String(), "business_name") {
		t.Errorf("expected error about business_name, got: %s", w.Body.String())
	}
}

// TestUpdateBusinessSettings_Name_Boundary accepts a 255-char name (DB max).
func TestUpdateBusinessSettings_Name_Boundary(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	name := strings.Repeat("A", 255)
	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		BusinessName: stringPtr(name),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 for 255-char name, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}
	if s.BusinessName != name {
		t.Errorf("expected business name to match, got %q", s.BusinessName)
	}
}

// ─── business_address validation ─────────────────────────────────────────────

// TestUpdateBusinessSettings_Address_Empty rejects an empty business_address.
func TestUpdateBusinessSettings_Address_Empty(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		BusinessAddress: stringPtr(""),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400 for empty address, got %d. body: %s", w.Code, w.Body.String())
	}
	if !strings.Contains(w.Body.String(), "business_address") {
		t.Errorf("expected error about business_address, got: %s", w.Body.String())
	}
}

// ─── business_phone validation ───────────────────────────────────────────────

// TestUpdateBusinessSettings_Phone_TooLong rejects a phone > 20 chars.
func TestUpdateBusinessSettings_Phone_TooLong(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		BusinessPhone: stringPtr("+44" + strings.Repeat("1", 18)),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400 for long phone, got %d. body: %s", w.Code, w.Body.String())
	}
	if !strings.Contains(w.Body.String(), "business_phone") {
		t.Errorf("expected error about business_phone, got: %s", w.Body.String())
	}
}

// TestUpdateBusinessSettings_Phone_Boundary accepts a 20-char phone (DB max).
func TestUpdateBusinessSettings_Phone_Boundary(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	phone := "+44" + strings.Repeat("1", 16) // 19 chars — within limit
	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		BusinessPhone: stringPtr(phone),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 for valid phone, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}
	if s.BusinessPhone == nil || *s.BusinessPhone != phone {
		t.Errorf("expected phone %q, got %v", phone, s.BusinessPhone)
	}
}

// TestUpdateBusinessSettings_Phone_Null clears phone by setting it to null.
func TestUpdateBusinessSettings_Phone_Null(t *testing.T) {
	ctx, tx := testutils.SetupTestTx(t)

	// Seed a phone value first
	_, err := tx.Exec(ctx, `UPDATE business_settings SET business_phone = '+441234567890'`)
	if err != nil {
		t.Fatalf("failed to seed phone: %v", err)
	}

	handler := http.HandlerFunc(UpdateBusinessSettings)
	nullPhone := ""
	body := UpdateBusinessSettingsRequest{
		BusinessPhone: &nullPhone,
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 for clearing phone, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}
	if s.BusinessPhone == nil || *s.BusinessPhone != "" {
		t.Errorf("expected BusinessPhone to be cleared, got %v", s.BusinessPhone)
	}
}

// ─── business_email validation ───────────────────────────────────────────────

// TestUpdateBusinessSettings_Email_TooLong rejects an email > 254 chars.
func TestUpdateBusinessSettings_Email_TooLong(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	local := strings.Repeat("a", 250)
	email := local + "@b.co"
	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		BusinessEmail: stringPtr(email),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400 for long email, got %d. body: %s", w.Code, w.Body.String())
	}
	if !strings.Contains(w.Body.String(), "business_email") {
		t.Errorf("expected error about business_email, got: %s", w.Body.String())
	}
}

// TestUpdateBusinessSettings_Email_Null clears email by setting it to null.
func TestUpdateBusinessSettings_Email_Null(t *testing.T) {
	ctx, tx := testutils.SetupTestTx(t)

	_, err := tx.Exec(ctx, `UPDATE business_settings SET business_email = 'test@example.com'`)
	if err != nil {
		t.Fatalf("failed to seed email: %v", err)
	}

	handler := http.HandlerFunc(UpdateBusinessSettings)
	nullEmail := ""
	body := UpdateBusinessSettingsRequest{
		BusinessEmail: &nullEmail,
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 for clearing email, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}
	if s.BusinessEmail == nil || *s.BusinessEmail != "" {
		t.Errorf("expected BusinessEmail to be cleared, got %v", s.BusinessEmail)
	}
}

// ─── vat_registration_number validation ──────────────────────────────────────

// TestUpdateBusinessSettings_VatNumber_TooLong rejects a VAT number > 20 chars.
func TestUpdateBusinessSettings_VatNumber_TooLong(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		VATRegistrationNumber: stringPtr(strings.Repeat("A", 21)),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400 for long VAT number, got %d. body: %s", w.Code, w.Body.String())
	}
	if !strings.Contains(w.Body.String(), "vat_registration_number") {
		t.Errorf("expected error about vat_registration_number, got: %s", w.Body.String())
	}
}

// TestUpdateBusinessSettings_VatNumber_Boundary accepts a valid UK VAT number.
func TestUpdateBusinessSettings_VatNumber_Boundary(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	// Standard UK VAT number: GB + 9 digits
	vatNum := "GB123456789"
	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		VATRegistrationNumber: stringPtr(vatNum),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 for valid VAT number, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}
	if s.VATRegistrationNumber == nil || *s.VATRegistrationNumber != vatNum {
		t.Errorf("expected VAT number %q, got %v", vatNum, s.VATRegistrationNumber)
	}

	// UK branch VAT number: GB + 12 digits
	branchVat := "GB123456789012"
	body2 := UpdateBusinessSettingsRequest{
		VATRegistrationNumber: stringPtr(branchVat),
	}
	w2 := makeAdminRequest(handler, "PUT", "/api/admin/settings", body2, ctx)
	if w2.Code != http.StatusOK {
		t.Errorf("expected status 200 for valid branch VAT number, got %d. body: %s", w2.Code, w2.Body.String())
	}
}

// ─── website_url validation ──────────────────────────────────────────────────

// TestUpdateBusinessSettings_Website_NoScheme rejects a URL without http/https.
func TestUpdateBusinessSettings_Website_NoScheme(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		WebsiteURL: stringPtr("www.example.com"),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400 for no scheme, got %d. body: %s", w.Code, w.Body.String())
	}
	if !strings.Contains(w.Body.String(), "website_url") {
		t.Errorf("expected error about website_url, got: %s", w.Body.String())
	}
}

// TestUpdateBusinessSettings_Website_FTPScheme rejects a URL with ftp://.
func TestUpdateBusinessSettings_Website_FTPScheme(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		WebsiteURL: stringPtr("ftp://files.example.com"),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400 for ftp scheme, got %d. body: %s", w.Code, w.Body.String())
	}
}

// TestUpdateBusinessSettings_Website_EmptyString clears the website URL.
func TestUpdateBusinessSettings_Website_EmptyString(t *testing.T) {
	ctx, tx := testutils.SetupTestTx(t)

	_, err := tx.Exec(ctx, `UPDATE business_settings SET website_url = 'https://example.com'`)
	if err != nil {
		t.Fatalf("failed to seed website: %v", err)
	}

	handler := http.HandlerFunc(UpdateBusinessSettings)
	empty := ""
	body := UpdateBusinessSettingsRequest{
		WebsiteURL: &empty,
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 for clearing website, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}
	if s.WebsiteURL != nil && *s.WebsiteURL != "" {
		t.Errorf("expected WebsiteURL to be cleared, got %v", *s.WebsiteURL)
	}
}

// TestUpdateBusinessSettings_Website_ValidHTTPS accepts a valid https URL.
func TestUpdateBusinessSettings_Website_ValidHTTPS(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		WebsiteURL: stringPtr("https://www.example.com"),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 for valid website, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}
	if s.WebsiteURL == nil || *s.WebsiteURL != "https://www.example.com" {
		t.Errorf("expected website URL, got %v", s.WebsiteURL)
	}
}

// TestUpdateBusinessSettings_Website_ValidHTTP accepts a valid http URL.
func TestUpdateBusinessSettings_Website_ValidHTTP(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		WebsiteURL: stringPtr("http://localhost:3000"),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 for valid website, got %d. body: %s", w.Code, w.Body.String())
	}
}

// ─── voucher_type validation ─────────────────────────────────────────────────

// TestUpdateBusinessSettings_InvalidVoucherType verifies that an invalid
// voucher_type value returns 400.
func TestUpdateBusinessSettings_InvalidVoucherType(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		VoucherType: stringPtr("INVALID"),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400, got %d. body: %s", w.Code, w.Body.String())
	}
	if w.Body.String() != "voucher_type must be 'SPV' or 'MPV'\n" {
		t.Errorf("unexpected error message: %s", w.Body.String())
	}
}

// TestUpdateBusinessSettings_InvalidVoucherType_Empty rejects an empty voucher_type.
func TestUpdateBusinessSettings_InvalidVoucherType_Empty(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		VoucherType: stringPtr(""),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400 for empty voucher_type, got %d. body: %s", w.Code, w.Body.String())
	}
}

// TestUpdateBusinessSettings_VoucherType_SPV accepts SPV.
func TestUpdateBusinessSettings_VoucherType_SPV(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		VoucherType: stringPtr("SPV"),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 for SPV, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}
	if s.VoucherType != "SPV" {
		t.Errorf("expected VoucherType 'SPV', got '%s'", s.VoucherType)
	}
}

// TestUpdateBusinessSettings_VoucherType_MPV accepts MPV.
func TestUpdateBusinessSettings_VoucherType_MPV(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		VoucherType: stringPtr("MPV"),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 for MPV, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}
	if s.VoucherType != "MPV" {
		t.Errorf("expected VoucherType 'MPV', got '%s'", s.VoucherType)
	}
}

// ─── gift_card_expiry_months validation ──────────────────────────────────────

// TestUpdateBusinessSettings_NegativeExpiryMonths verifies that a
// gift_card_expiry_months value less than 1 returns 400.
func TestUpdateBusinessSettings_NegativeExpiryMonths(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		GiftCardExpiryMonths: intPtr(0),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400, got %d. body: %s", w.Code, w.Body.String())
	}
	if w.Body.String() != "gift_card_expiry_months must be at least 1\n" {
		t.Errorf("unexpected error message: %s", w.Body.String())
	}
}

// TestUpdateBusinessSettings_ExpiryMonths_Negative rejects negative values.
func TestUpdateBusinessSettings_ExpiryMonths_Negative(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		GiftCardExpiryMonths: intPtr(-5),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400 for negative expiry, got %d. body: %s", w.Code, w.Body.String())
	}
	if w.Body.String() != "gift_card_expiry_months must be at least 1\n" {
		t.Errorf("unexpected error message: %s", w.Body.String())
	}
}

// TestUpdateBusinessSettings_ExpiryMonths_LargeValue accepts a large but valid value.
func TestUpdateBusinessSettings_ExpiryMonths_LargeValue(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		GiftCardExpiryMonths: intPtr(9999),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 for large expiry, got %d. body: %s", w.Code, w.Body.String())
	}
}

// ─── default_vat_rate validation ─────────────────────────────────────────────

// TestUpdateBusinessSettings_InvalidVATRate verifies that a default_vat_rate
// outside the 0-100 range returns 400.
func TestUpdateBusinessSettings_InvalidVATRate(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)

	body := UpdateBusinessSettingsRequest{
		DefaultVATRate: float64Ptr(-1),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusBadRequest {
		t.Errorf("expected status 400 for negative rate, got %d. body: %s", w.Code, w.Body.String())
	}
	if w.Body.String() != "default_vat_rate must be between 0 and 100\n" {
		t.Errorf("unexpected error message: %s", w.Body.String())
	}

	body2 := UpdateBusinessSettingsRequest{
		DefaultVATRate: float64Ptr(101),
	}
	w2 := makeAdminRequest(handler, "PUT", "/api/admin/settings", body2, ctx)

	if w2.Code != http.StatusBadRequest {
		t.Errorf("expected status 400 for rate > 100, got %d. body: %s", w2.Code, w2.Body.String())
	}
	if w2.Body.String() != "default_vat_rate must be between 0 and 100\n" {
		t.Errorf("unexpected error message: %s", w2.Body.String())
	}
}

// TestUpdateBusinessSettings_VATRate_Boundary_Zero accepts 0% VAT rate.
func TestUpdateBusinessSettings_VATRate_Boundary_Zero(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		DefaultVATRate: float64Ptr(0),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 for 0%% VAT rate, got %d. body: %s", w.Code, w.Body.String())
	}
}

// TestUpdateBusinessSettings_VATRate_Boundary_100 accepts 100% VAT rate.
func TestUpdateBusinessSettings_VATRate_Boundary_100(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		DefaultVATRate: float64Ptr(100),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 for 100%% VAT rate, got %d. body: %s", w.Code, w.Body.String())
	}
}

// TestUpdateBusinessSettings_VATRate_Fractional accepts fractional VAT rates.
func TestUpdateBusinessSettings_VATRate_Fractional(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	body := UpdateBusinessSettingsRequest{
		DefaultVATRate: float64Ptr(5.5),
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 for 5.5%% VAT rate, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}
	if s.DefaultVATRate != 5.5 {
		t.Errorf("expected DefaultVATRate 5.5, got %f", s.DefaultVATRate)
	}
}

// ─── is_vat_registered toggle ────────────────────────────────────────────────

// TestUpdateBusinessSettings_EnableVATRegistration enables VAT registration.
func TestUpdateBusinessSettings_EnableVATRegistration(t *testing.T) {
	ctx, _ := testutils.SetupTestTx(t)

	handler := http.HandlerFunc(UpdateBusinessSettings)
	trueVal := true
	vatRate := 20.0
	vatNum := "GB123456789"
	body := UpdateBusinessSettingsRequest{
		IsVATRegistered:       &trueVal,
		DefaultVATRate:        &vatRate,
		VATRegistrationNumber: &vatNum,
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 when enabling VAT, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}
	if !s.IsVATRegistered {
		t.Errorf("expected IsVATRegistered to be true")
	}
	if s.DefaultVATRate != 20.0 {
		t.Errorf("expected DefaultVATRate 20.0, got %f", s.DefaultVATRate)
	}
	if s.VATRegistrationNumber == nil || *s.VATRegistrationNumber != "GB123456789" {
		t.Errorf("expected VATRegistrationNumber 'GB123456789', got %v", s.VATRegistrationNumber)
	}
}

// TestUpdateBusinessSettings_DisableVATRegistration disables VAT registration.
// ─── validateURL tests ───────────────────────────────────────────────────────

func TestValidateURL_ValidHTTPS(t *testing.T) {
	if err := validateURL("https://example.com"); err != nil {
		t.Errorf("expected no error, got %v", err)
	}
}

func TestValidateURL_ValidHTTP(t *testing.T) {
	if err := validateURL("http://example.com"); err != nil {
		t.Errorf("expected no error, got %v", err)
	}
}

func TestValidateURL_ValidHTTP_Localhost(t *testing.T) {
	if err := validateURL("http://localhost:3000"); err != nil {
		t.Errorf("expected no error, got %v", err)
	}
}

func TestValidateURL_ValidHTTPS_WithPath(t *testing.T) {
	if err := validateURL("https://example.com/path/to/page?q=1"); err != nil {
		t.Errorf("expected no error, got %v", err)
	}
}

func TestValidateURL_NoScheme(t *testing.T) {
	err := validateURL("www.example.com")
	if err == nil {
		t.Fatal("expected error for missing scheme")
	}
	if !strings.Contains(err.Error(), "http") {
		t.Errorf("expected error mentioning http/https, got: %v", err)
	}
}

func TestValidateURL_FTPScheme(t *testing.T) {
	err := validateURL("ftp://files.example.com")
	if err == nil {
		t.Fatal("expected error for ftp scheme")
	}
	if !strings.Contains(err.Error(), "http") {
		t.Errorf("expected error mentioning http/https, got: %v", err)
	}
}

func TestValidateURL_EmptyHost(t *testing.T) {
	err := validateURL("https://")
	if err == nil {
		t.Fatal("expected error for empty host")
	}
	if !strings.Contains(err.Error(), "host") {
		t.Errorf("expected error about host, got: %v", err)
	}
}

func TestValidateURL_InvalidString(t *testing.T) {
	err := validateURL("not a url at all")
	if err == nil {
		t.Fatal("expected error for invalid URL")
	}
}

func TestValidateURL_EmptyString(t *testing.T) {
	err := validateURL("")
	// url.Parse("") returns a valid url.URL with empty Scheme
	// So validateURL should reject it (no scheme, no host)
	if err == nil {
		t.Fatal("expected error for empty string")
	}
}

func TestValidateURL_HTTPSOnlyScheme(t *testing.T) {
	if err := validateURL("https://"); err == nil {
		t.Fatal("expected error for https:// with no host")
	}
}

func TestValidateURL_IPAddress(t *testing.T) {
	if err := validateURL("https://192.168.1.1"); err != nil {
		t.Errorf("expected no error for HTTPS IP, got %v", err)
	}
}

// ─── Disable VAT registration ─────────────────────────────────────────────────

func TestUpdateBusinessSettings_DisableVATRegistration(t *testing.T) {
	ctx, tx := testutils.SetupTestTx(t)

	_, err := tx.Exec(ctx, `UPDATE business_settings SET is_vat_registered = TRUE, default_vat_rate = 20.00`)
	if err != nil {
		t.Fatalf("failed to enable VAT: %v", err)
	}

	handler := http.HandlerFunc(UpdateBusinessSettings)
	falseVal := false
	body := UpdateBusinessSettingsRequest{
		IsVATRegistered: &falseVal,
	}
	w := makeAdminRequest(handler, "PUT", "/api/admin/settings", body, ctx)

	if w.Code != http.StatusOK {
		t.Errorf("expected status 200 when disabling VAT, got %d. body: %s", w.Code, w.Body.String())
	}

	var s BusinessSettings
	if err := parseResponseBody(w, &s); err != nil {
		t.Fatalf("failed to parse response: %v", err)
	}
	if s.IsVATRegistered {
		t.Errorf("expected IsVATRegistered to be false")
	}
}
