package db

import (
	"context"
	"encoding/json"
	"fmt"
	"sort"
	"strings"
	"time"

	"github.com/google/uuid"
	"github.com/jackc/pgx/v5"
	"github.com/jackc/pgx/v5/pgxpool"
)

type Repository interface {
	GetTenantBySlug(ctx context.Context, slug string) (TenantRecord, error)
	GetTenantByID(ctx context.Context, tenantID string) (TenantRecord, error)
	GetTenantByBillingCustomerID(ctx context.Context, customerID string) (TenantRecord, error)
	EnsureUserIdentity(ctx context.Context, subject string, email string, displayName string) error
	CreateTenantForUser(ctx context.Context, params CreateTenantForUserParams) (TenantMembershipRecord, error)
	GetTenantMembershipByUserID(ctx context.Context, userID string) (TenantMembershipRecord, error)
	GetBrandProfile(ctx context.Context, tenantID string) (BrandProfileRecord, error)
	ListServicesByTenant(ctx context.Context, tenantID string) ([]ServiceRecord, error)
	ListAvailabilityRulesByTenant(ctx context.Context, tenantID string) ([]AvailabilityRuleRecord, error)
	ListClassSessionsByTenant(ctx context.Context, tenantID string, from time.Time, limit int) ([]ClassSessionRecord, error)
	ListBookingsByTenantBetween(ctx context.Context, tenantID string, from time.Time, to time.Time) ([]BookingRecord, error)
	CreateBooking(ctx context.Context, params CreateBookingParams) (CreatedBooking, error)
	AppendWaitlistEntry(ctx context.Context, params WaitlistEntryParams) error
	CreateReminderJob(ctx context.Context, params ReminderJobParams) error
	ListDueReminderJobs(ctx context.Context, dueBefore time.Time, limit int) ([]ReminderJobRecord, error)
	MarkReminderJobDispatched(ctx context.Context, reminderJobID string, status string, dispatchedAt time.Time) error
	CreateNotificationDeliveryLog(ctx context.Context, params NotificationDeliveryLogParams) error
	GetDashboardMetrics(ctx context.Context, tenantID string, startsAt time.Time, endsAt time.Time) (DashboardMetrics, error)
	GetSubscriptionSnapshot(ctx context.Context, tenantID string) (BillingSnapshotRecord, error)
	UpsertSubscriptionSnapshot(ctx context.Context, params BillingSnapshotRecord) error
	UpdateTenantBillingCustomerID(ctx context.Context, tenantID string, customerID string) error
	UpdateTenantBillingState(ctx context.Context, tenantID string, planCode string, subscriptionStatus string, subscriptionID string) error
	RecordBillingEvent(ctx context.Context, tenantID string, provider string, eventID string, eventType string, payload []byte) (bool, error)

	// Auth methods
	GetUserByEmail(ctx context.Context, email string) (*UserRecord, error)
	GetUserByID(ctx context.Context, userID string) (*UserRecord, error)
	CreateUser(ctx context.Context, email, passwordHash, name, provider, role string) (*UserRecord, error)
	UpdateLastLogin(ctx context.Context, userID string) error
	MarkEmailVerified(ctx context.Context, userID string) error
	CreateMagicLink(ctx context.Context, token, userID, email string, expiresAt time.Time) error
	GetMagicLink(ctx context.Context, token string) (*MagicLinkRecord, error)
	MarkMagicLinkUsed(ctx context.Context, token string) error

	// Admin methods
	ListAllTenants(ctx context.Context, limit, offset int) ([]TenantRecord, int, error)
	ListAllUsers(ctx context.Context, limit, offset int) ([]UserRecord, int, error)
	GetPlatformStats(ctx context.Context) (PlatformStats, error)
	CreateAdminAuditLog(ctx context.Context, params AdminAuditLogParams) error
	UpdateUserRole(ctx context.Context, userID, role string) error

	// Location / Zone Management
	ListLocationsByTenant(ctx context.Context, tenantID string) ([]LocationRecord, error)
	GetLocationByID(ctx context.Context, locationID string) (LocationRecord, error)
	CreateLocation(ctx context.Context, params CreateLocationParams) (LocationRecord, error)
	UpdateLocation(ctx context.Context, locationID string, params UpdateLocationParams) (LocationRecord, error)
	DeleteLocation(ctx context.Context, locationID string) error

	// Blocked Days / Availability Exceptions
	ListBlockedDaysByTenant(ctx context.Context, tenantID string, from time.Time, to time.Time) ([]BlockedDayRecord, error)
	CreateBlockedDay(ctx context.Context, params CreateBlockedDayParams) (BlockedDayRecord, error)
	UpdateBlockedDay(ctx context.Context, blockedDayID string, params UpdateBlockedDayParams) (BlockedDayRecord, error)
	DeleteBlockedDay(ctx context.Context, blockedDayID string) error

	// Customer Management
	ListCustomersByTenant(ctx context.Context, tenantID string, limit int, offset int) ([]CustomerRecord, error)
	GetCustomerByID(ctx context.Context, customerID string) (CustomerRecord, error)
	GetCustomerByEmail(ctx context.Context, tenantID string, email string) (CustomerRecord, error)
	CreateCustomer(ctx context.Context, params CreateCustomerParams) (CustomerRecord, error)
	UpdateCustomer(ctx context.Context, customerID string, params UpdateCustomerParams) (CustomerRecord, error)
	DeleteCustomer(ctx context.Context, customerID string) error
	GetCustomerBookingsCount(ctx context.Context, customerID string) (int, error)
	GetCustomerLastBooking(ctx context.Context, customerID string) (*time.Time, error)

	// Customer Booking Management
	GetBookingByReference(ctx context.Context, reference string) (BookingRecord, error)
	UpdateBookingStatus(ctx context.Context, bookingID string, status string) error
	RescheduleBooking(ctx context.Context, bookingID string, startsAt time.Time, endsAt time.Time) error

	// Working Hours
	ListWorkingHoursByTenant(ctx context.Context, tenantID string) ([]WorkingHoursRecord, error)
	UpdateWorkingHours(ctx context.Context, tenantID string, dayOfWeek int, params UpdateWorkingHoursParams) error

	// SMS
	GetTenantSMSSettings(ctx context.Context, tenantID string) (TenantSMSSettingsRecord, error)
	UpsertTenantSMSSettings(ctx context.Context, params TenantSMSSettingsRecord) error
	CreateSMSUsageLog(ctx context.Context, params SMSUsageLogRecord) (string, error)
	GetSMSUsageThisMonth(ctx context.Context, tenantID string) (SMSUsageSummary, error)
	GetSMSUsageForMonth(ctx context.Context, tenantID string, yearMonth string) (SMSMonthlyReportRecord, error)
	ListSMSUsageLogs(ctx context.Context, tenantID string, limit int) ([]SMSUsageLogRecord, error)
	ListSMSMonthlyReports(ctx context.Context, tenantID string, limit int) ([]SMSMonthlyReportRecord, error)
	UpsertSMSMonthlyReport(ctx context.Context, params SMSMonthlyReportRecord) error
	MarkSMSReportInvoiceSent(ctx context.Context, tenantID string, yearMonth string) error
	ListTenantsWithSMSUsage(ctx context.Context, yearMonth string) ([]TenantRecord, error)
}

type TenantRecord struct {
	ID                  string
	Slug                string
	Name                string
	Preset              string
	Locale              string
	Timezone            string
	PlanCode            string
	SubscriptionStatus  string
	BillingProvider     string
	BillingCustomerID   *string
	BillingSubscription *string
}

type UserRecord struct {
	ID            uuid.UUID
	Email         string
	Name          *string
	PasswordHash  *string
	EmailVerified bool
	Provider      string
	Role          string
	CreatedAt     time.Time
	LastLoginAt   *time.Time
}

type MagicLinkRecord struct {
	Token     string
	UserID    uuid.UUID
	Email     string
	Used      bool
	ExpiresAt time.Time
	CreatedAt time.Time
}

type PlatformStats struct {
	TotalTenants        int64 `json:"totalTenants"`
	TotalUsers          int64 `json:"totalUsers"`
	ActiveSubscriptions int64 `json:"activeSubscriptions"`
	TrialSubscriptions  int64 `json:"trialSubscriptions"`
	BookingsThisMonth   int64 `json:"bookingsThisMonth"`
	RevenueThisMonth    int64 `json:"revenueThisMonthCents"`
}

type AdminAuditLogParams struct {
	AdminUserID  string
	Action       string
	ResourceType string
	ResourceID   string
	Details      map[string]any
	IPAddress    string
	UserAgent    string
}

type TenantMembershipRecord struct {
	Tenant TenantRecord
	UserID string
	Role   string
}

type CreateTenantForUserParams struct {
	Subject             string
	Name                string
	Slug                string
	Preset              string
	Locale              string
	Timezone            string
	BrandName           string
	SiteURL             string
	LogoURL             string
	PrimaryColor        string
	LocationName        string
	ServiceName         string
	DurationMinutes     int
	BufferBeforeMinutes int
	BufferAfterMinutes  int
	CancelWindowHours   int
	AvailabilityBlocks  []AvailabilityBlockRecord
	TeamInvites         []TeamInviteRecord
}

type BrandProfileRecord struct {
	TenantID     string
	Name         string
	SiteURL      string
	LogoURL      string
	PrimaryColor string
	UmamiSiteID  string
}

type AvailabilityBlockRecord struct {
	DayOfWeek   int
	StartsLocal string
	EndsLocal   string
	Busy        bool
}

type TeamInviteRecord struct {
	Email string
	Role  string
}

type ServiceRecord struct {
	ID                  string
	TenantID            string
	Name                string
	DurationMinutes     int
	BufferBeforeMinutes int
	BufferAfterMinutes  int
	PriceCents          int
}

type AvailabilityRuleRecord struct {
	ID          string
	TenantID    string
	StaffID     *string
	DayOfWeek   int
	StartsLocal string
	EndsLocal   string
}

type ClassSessionRecord struct {
	ID         string
	TenantID   string
	TemplateID string
	LocationID *string
	Title      string
	StartsAt   time.Time
	EndsAt     time.Time
	Capacity   int32
}

type BookingRecord struct {
	ID             string
	TenantID       string
	ServiceID      *string
	ClassSessionID *string
	StaffID        *string
	LocationID     *string
	CustomerName   string
	CustomerEmail  string
	CustomerPhone  string
	StartsAt       time.Time
	EndsAt         time.Time
	Status         string
	Reference      string
}

type CreateBookingParams struct {
	TenantID       string
	ServiceID      *string
	ClassSessionID *string
	StaffID        *string
	LocationID     *string
	BookingMode    string
	CustomerName   string
	CustomerEmail  string
	CustomerPhone  string
	StartsAt       time.Time
	EndsAt         time.Time
	Status         string
	Reference      string
	Notes          string
}

type CreatedBooking struct {
	ID        string
	Reference string
	Status    string
}

type WaitlistEntryParams struct {
	TenantID       string
	ClassSessionID string
	CustomerName   string
	CustomerEmail  string
	Position       int
}

type DashboardMetrics struct {
	BookingsCount      int
	CancellationsCount int
	UtilizationPercent int
}

type ReminderJobParams struct {
	TenantID     string
	BookingID    string
	Channel      string
	ScheduledFor time.Time
}

type ReminderJobRecord struct {
	ID            string
	TenantID      string
	TenantName    string
	Locale        string
	Timezone      string
	BookingID     string
	Channel       string
	ScheduledFor  time.Time
	CustomerName  string
	CustomerEmail string
	Reference     string
	StartsAt      time.Time
	Status        string
}

type NotificationDeliveryLogParams struct {
	TenantID      string
	ReminderJobID string
	Channel       string
	Provider      string
	Recipient     string
	Status        string
	ExternalID    string
	ErrorMessage  string
}

type BillingSnapshotRecord struct {
	TenantID              string
	BillingProvider       string
	BillingCustomerID     string
	BillingSubscriptionID string
	Status                string
	PlanCode              string
	Currency              string
	PriceID               string
	CancelAtPeriodEnd     bool
	CurrentPeriodStart    *time.Time
	CurrentPeriodEnd      *time.Time
	PaymentMethodBrand    string
	PaymentMethodLast4    string
	LastSyncedAt          *time.Time
}

// Location / Zone Records
type LocationRecord struct {
	ID        string
	TenantID  string
	Name      string
	Timezone  string
	CreatedAt time.Time
}

type CreateLocationParams struct {
	TenantID string
	Name     string
	Timezone string
}

type UpdateLocationParams struct {
	Name     *string
	Timezone *string
}

// Blocked Day Records
type BlockedDayRecord struct {
	ID        string
	TenantID  string
	StaffID   *string
	StartsAt  time.Time
	EndsAt    time.Time
	Kind      string
	Reason    string
	CreatedAt time.Time
}

type CreateBlockedDayParams struct {
	TenantID string
	StaffID  *string
	StartsAt time.Time
	EndsAt   time.Time
	Kind     string
	Reason   string
}

type UpdateBlockedDayParams struct {
	StartsAt *time.Time
	EndsAt   *time.Time
	Kind     *string
	Reason   *string
}

// Customer Records
type CustomerRecord struct {
	ID        string
	TenantID  string
	Name      string
	Email     string
	Phone     *string
	Status    string
	CreatedAt time.Time
	Notes     *string
}

type CreateCustomerParams struct {
	TenantID string
	Name     string
	Email    string
	Phone    *string
	Status   string
	Notes    *string
}

type UpdateCustomerParams struct {
	Name   *string
	Email  *string
	Phone  *string
	Status *string
	Notes  *string
}

// Working Hours Records
type WorkingHoursRecord struct {
	TenantID    string
	StaffID     *string
	DayOfWeek   int
	StartsLocal string
	EndsLocal   string
}

type UpdateWorkingHoursParams struct {
	StartsLocal *string
	EndsLocal   *string
	IsOpen      *bool
}

// SMS Records
type TenantSMSSettingsRecord struct {
	TenantID                 string
	Enabled                  bool
	SenderName               string
	MonthlyLimit             int
	StripeSubscriptionItemID string
}

type SMSUsageLogRecord struct {
	ID                string
	TenantID          string
	RecipientPhone    string
	MessageBody       string
	ExternalMessageID string
	ExternalRequestID string
	Status            string
	CostCents         int
	SentAt            time.Time
	CreatedAt         time.Time
}

type SMSUsageSummary struct {
	MessageCount   int
	TotalCostCents int
}

type SMSMonthlyReportRecord struct {
	ID              string
	TenantID        string
	YearMonth       string
	MessageCount    int
	TotalCostCents  int
	StripeInvoiceID string
	InvoiceSentAt   *time.Time
	CreatedAt       time.Time
}

type PGRepository struct {
	pool *pgxpool.Pool
}

func NewRepository(pools *Pools, demoMode bool) Repository {
	if demoMode {
		return NewMemoryRepository()
	}
	if pools != nil && pools.App != nil {
		return &PGRepository{pool: pools.App}
	}
	return NewMemoryRepository()
}

// ============================================
// LOCATION / ZONE METHODS - PG REPOSITORY (STUBS)
// ============================================

// ============================================
// BLOCKED DAYS METHODS - PG REPOSITORY (STUBS)
// ============================================

// ============================================
// CUSTOMER METHODS - PG REPOSITORY (STUBS)
// ============================================

func (r *PGRepository) ListCustomersByTenant(ctx context.Context, tenantID string, limit int, offset int) ([]CustomerRecord, error) {
	rows, err := r.pool.Query(ctx, `
		SELECT id, tenant_id, name, email, phone, status, created_at, notes
		FROM customers
		WHERE tenant_id = $1
		ORDER BY name
		LIMIT $2 OFFSET $3
	`, tenantID, limit, offset)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	var records []CustomerRecord
	for rows.Next() {
		var rec CustomerRecord
		if err := rows.Scan(&rec.ID, &rec.TenantID, &rec.Name, &rec.Email, &rec.Phone, &rec.Status, &rec.CreatedAt, &rec.Notes); err != nil {
			return nil, err
		}
		records = append(records, rec)
	}
	return records, rows.Err()
}

func (r *PGRepository) GetCustomerByID(ctx context.Context, customerID string) (CustomerRecord, error) {
	var rec CustomerRecord
	err := r.pool.QueryRow(ctx, `
		SELECT id, tenant_id, name, email, phone, status, created_at, notes
		FROM customers
		WHERE id = $1
	`, customerID).Scan(&rec.ID, &rec.TenantID, &rec.Name, &rec.Email, &rec.Phone, &rec.Status, &rec.CreatedAt, &rec.Notes)
	return rec, err
}

func (r *PGRepository) GetCustomerByEmail(ctx context.Context, tenantID string, email string) (CustomerRecord, error) {
	var rec CustomerRecord
	err := r.pool.QueryRow(ctx, `
		SELECT id, tenant_id, name, email, phone, status, created_at, notes
		FROM customers
		WHERE tenant_id = $1 AND email = $2
	`, tenantID, email).Scan(&rec.ID, &rec.TenantID, &rec.Name, &rec.Email, &rec.Phone, &rec.Status, &rec.CreatedAt, &rec.Notes)
	return rec, err
}

func (r *PGRepository) CreateCustomer(ctx context.Context, params CreateCustomerParams) (CustomerRecord, error) {
	var rec CustomerRecord
	err := r.pool.QueryRow(ctx, `
		INSERT INTO customers (tenant_id, name, email, phone, status, notes)
		VALUES ($1, $2, $3, $4, $5, $6)
		RETURNING id, tenant_id, name, email, phone, status, created_at, notes
	`, params.TenantID, params.Name, params.Email, params.Phone, params.Status, params.Notes).Scan(&rec.ID, &rec.TenantID, &rec.Name, &rec.Email, &rec.Phone, &rec.Status, &rec.CreatedAt, &rec.Notes)
	return rec, err
}

func (r *PGRepository) UpdateCustomer(ctx context.Context, customerID string, params UpdateCustomerParams) (CustomerRecord, error) {
	var rec CustomerRecord
	err := r.pool.QueryRow(ctx, `
		UPDATE customers
		SET name = COALESCE($2, name),
		    email = COALESCE($3, email),
		    phone = COALESCE($4, phone),
		    status = COALESCE($5, status),
		    notes = COALESCE($6, notes)
		WHERE id = $1
		RETURNING id, tenant_id, name, email, phone, status, created_at, notes
	`, customerID, params.Name, params.Email, params.Phone, params.Status, params.Notes).Scan(&rec.ID, &rec.TenantID, &rec.Name, &rec.Email, &rec.Phone, &rec.Status, &rec.CreatedAt, &rec.Notes)
	return rec, err
}

func (r *PGRepository) DeleteCustomer(ctx context.Context, customerID string) error {
	_, err := r.pool.Exec(ctx, `DELETE FROM customers WHERE id = $1`, customerID)
	return err
}

func (r *PGRepository) GetCustomerBookingsCount(ctx context.Context, customerID string) (int, error) {
	var count int
	err := r.pool.QueryRow(ctx, `
		SELECT COUNT(*) FROM bookings
		WHERE customer_email = (SELECT email FROM customers WHERE id = $1)
	`, customerID).Scan(&count)
	return count, err
}

func (r *PGRepository) GetCustomerLastBooking(ctx context.Context, customerID string) (*time.Time, error) {
	var lastTime *time.Time
	err := r.pool.QueryRow(ctx, `
		SELECT MAX(starts_at) FROM bookings
		WHERE customer_email = (SELECT email FROM customers WHERE id = $1)
	`, customerID).Scan(&lastTime)
	return lastTime, err
}

// ============================================
// BOOKING MANAGEMENT METHODS - PG REPOSITORY (STUBS)
// ============================================

func (r *PGRepository) GetBookingByReference(ctx context.Context, reference string) (BookingRecord, error) {
	var rec BookingRecord
	err := r.pool.QueryRow(ctx, `
		SELECT id, tenant_id, service_id, class_session_id, staff_id, location_id,
		       customer_name, customer_email, customer_phone, starts_at, ends_at, status, reference
		FROM bookings
		WHERE reference = $1
	`, reference).Scan(&rec.ID, &rec.TenantID, &rec.ServiceID, &rec.ClassSessionID, &rec.StaffID, &rec.LocationID,
		&rec.CustomerName, &rec.CustomerEmail, &rec.CustomerPhone, &rec.StartsAt, &rec.EndsAt, &rec.Status, &rec.Reference)
	return rec, err
}

func (r *PGRepository) UpdateBookingStatus(ctx context.Context, bookingID string, status string) error {
	_, err := r.pool.Exec(ctx, `
		UPDATE bookings SET status = $2, updated_at = now() WHERE id = $1
	`, bookingID, status)
	return err
}

func (r *PGRepository) RescheduleBooking(ctx context.Context, bookingID string, startsAt time.Time, endsAt time.Time) error {
	_, err := r.pool.Exec(ctx, `
		UPDATE bookings SET starts_at = $2, ends_at = $3, updated_at = now() WHERE id = $1
	`, bookingID, startsAt, endsAt)
	return err
}

// ============================================
// WORKING HOURS METHODS - PG REPOSITORY (STUBS)
// ============================================

type MemoryRepository struct {
	tenant          TenantRecord
	membership      TenantMembershipRecord
	brand           BrandProfileRecord
	services        []ServiceRecord
	rules           []AvailabilityRuleRecord
	classSessions   []ClassSessionRecord
	bookings        []BookingRecord
	waitlistSize    int
	reminderJobs    []ReminderJobRecord
	deliveryLogs    []NotificationDeliveryLogParams
	billingSnapshot BillingSnapshotRecord
	recordedEvents  map[string]struct{}
	locations       []LocationRecord
	blockedDays     []BlockedDayRecord
	customers       []CustomerRecord
	workingHours    []WorkingHoursRecord
	smsSettings     TenantSMSSettingsRecord
	smsLogs         []SMSUsageLogRecord
	smsReports      []SMSMonthlyReportRecord
}

func NewMemoryRepository() *MemoryRepository {
	tenantID := "5d6b3551-0a3e-4b86-bdf0-e9df20a47148"
	locationID := "659f1cc0-a850-46d6-b3b8-cb15d55d8daf"
	staffID := "6936c444-c7d0-4a7d-b596-a9b72d2f4fc0"
	serviceID := "d5d76a61-3d49-467c-8dd4-bf61ee754e39"
	templateID := "d13fe5fd-727f-4d69-bfd8-47f1b92a2cf7"
	sessionID := "4bf74c12-44dd-45ca-86bb-b104f16f2435"
	now := time.Now().UTC()

	return &MemoryRepository{
		tenant: TenantRecord{
			ID:                 tenantID,
			Slug:               "studio-atelier",
			Name:               "Studio Atelier",
			Preset:             "studio",
			Locale:             "cs",
			Timezone:           "Europe/Prague",
			PlanCode:           "pro",
			SubscriptionStatus: "active",
			BillingProvider:    "paddle",
			BillingCustomerID:  stringPtr("ctm_demo_bookra"),
		},
		membership: TenantMembershipRecord{
			Tenant: TenantRecord{
				ID:                 tenantID,
				Slug:               "studio-atelier",
				Name:               "Studio Atelier",
				Preset:             "studio",
				Locale:             "cs",
				Timezone:           "Europe/Prague",
				PlanCode:           "pro",
				SubscriptionStatus: "active",
				BillingProvider:    "paddle",
				BillingCustomerID:  stringPtr("ctm_demo_bookra"),
			},
			UserID: "demo-owner",
			Role:   "owner",
		},
		brand: BrandProfileRecord{
			TenantID:     tenantID,
			Name:         "Studio Atelier",
			SiteURL:      "https://studio-atelier.example",
			PrimaryColor: "#a65c3e",
		},
		services: []ServiceRecord{
			{
				ID:                  serviceID,
				TenantID:            tenantID,
				Name:                "Signature treatment",
				DurationMinutes:     60,
				BufferBeforeMinutes: 0,
				BufferAfterMinutes:  15,
				PriceCents:          120000,
			},
		},
		rules: []AvailabilityRuleRecord{
			{ID: uuid.NewString(), TenantID: tenantID, StaffID: &staffID, DayOfWeek: 1, StartsLocal: "09:00:00", EndsLocal: "17:00:00"},
			{ID: uuid.NewString(), TenantID: tenantID, StaffID: &staffID, DayOfWeek: 2, StartsLocal: "09:00:00", EndsLocal: "17:00:00"},
			{ID: uuid.NewString(), TenantID: tenantID, StaffID: &staffID, DayOfWeek: 3, StartsLocal: "09:00:00", EndsLocal: "17:00:00"},
			{ID: uuid.NewString(), TenantID: tenantID, StaffID: &staffID, DayOfWeek: 4, StartsLocal: "09:00:00", EndsLocal: "17:00:00"},
			{ID: uuid.NewString(), TenantID: tenantID, StaffID: &staffID, DayOfWeek: 5, StartsLocal: "09:00:00", EndsLocal: "17:00:00"},
		},
		classSessions: []ClassSessionRecord{
			{
				ID:         sessionID,
				TenantID:   tenantID,
				TemplateID: templateID,
				LocationID: &locationID,
				Title:      "Small group mobility class",
				StartsAt:   now.Add(48 * time.Hour),
				EndsAt:     now.Add(49 * time.Hour),
				Capacity:   4,
			},
		},
		bookings:     []BookingRecord{},
		reminderJobs: []ReminderJobRecord{},
		deliveryLogs: []NotificationDeliveryLogParams{},
		billingSnapshot: BillingSnapshotRecord{
			TenantID:              tenantID,
			BillingProvider:       "paddle",
			BillingCustomerID:     "ctm_demo_bookra",
			BillingSubscriptionID: "",
			Status:                "active",
			PlanCode:              "pro",
			Currency:              "czk",
			PriceID:               "",
		},
		recordedEvents: map[string]struct{}{},
		locations: []LocationRecord{
			{ID: locationID, TenantID: tenantID, Name: "Main Studio", Timezone: "Europe/Prague", CreatedAt: now},
		},
		blockedDays: []BlockedDayRecord{},
		customers: []CustomerRecord{
			{ID: uuid.NewString(), TenantID: tenantID, Name: "Alice Johnson", Email: "alice@example.com", Phone: stringPtr("+420123456789"), Status: "vip", CreatedAt: now},
			{ID: uuid.NewString(), TenantID: tenantID, Name: "Bob Smith", Email: "bob@example.com", Status: "active", CreatedAt: now},
			{ID: uuid.NewString(), TenantID: tenantID, Name: "Carol White", Email: "carol@example.com", Status: "active", CreatedAt: now},
		},
		workingHours: []WorkingHoursRecord{
			{TenantID: tenantID, DayOfWeek: 1, StartsLocal: "09:00", EndsLocal: "17:00"},
			{TenantID: tenantID, DayOfWeek: 2, StartsLocal: "09:00", EndsLocal: "17:00"},
			{TenantID: tenantID, DayOfWeek: 3, StartsLocal: "09:00", EndsLocal: "17:00"},
			{TenantID: tenantID, DayOfWeek: 4, StartsLocal: "09:00", EndsLocal: "17:00"},
			{TenantID: tenantID, DayOfWeek: 5, StartsLocal: "09:00", EndsLocal: "17:00"},
			{TenantID: tenantID, DayOfWeek: 6, StartsLocal: "10:00", EndsLocal: "14:00"},
			{TenantID: tenantID, DayOfWeek: 0, StartsLocal: "", EndsLocal: ""},
		},
	}
}

func (r *MemoryRepository) GetTenantBySlug(_ context.Context, slug string) (TenantRecord, error) {
	if slug != r.tenant.Slug {
		return TenantRecord{}, pgx.ErrNoRows
	}
	return r.tenant, nil
}

func (r *MemoryRepository) GetTenantByID(_ context.Context, tenantID string) (TenantRecord, error) {
	if tenantID == r.tenant.ID {
		return r.tenant, nil
	}
	return TenantRecord{}, pgx.ErrNoRows
}

func (r *MemoryRepository) GetTenantByBillingCustomerID(_ context.Context, customerID string) (TenantRecord, error) {
	if r.billingSnapshot.BillingCustomerID == customerID {
		return r.tenant, nil
	}
	return TenantRecord{}, pgx.ErrNoRows
}

func (r *MemoryRepository) EnsureUserIdentity(_ context.Context, subject string, email string, displayName string) error {
	if strings.TrimSpace(subject) == "" {
		return nil
	}
	r.membership.UserID = subject
	_ = email
	_ = displayName
	return nil
}

func (r *MemoryRepository) CreateTenantForUser(_ context.Context, params CreateTenantForUserParams) (TenantMembershipRecord, error) {
	tenantID := uuid.NewString()
	r.tenant = TenantRecord{
		ID:                 tenantID,
		Slug:               params.Slug,
		Name:               params.Name,
		Preset:             params.Preset,
		Locale:             params.Locale,
		Timezone:           params.Timezone,
		PlanCode:           "starter",
		SubscriptionStatus: "trialing",
	}
	r.membership = TenantMembershipRecord{
		Tenant: r.tenant,
		UserID: params.Subject,
		Role:   "owner",
	}
	r.brand = BrandProfileRecord{
		TenantID:     tenantID,
		Name:         firstNonEmpty(params.BrandName, params.Name),
		SiteURL:      params.SiteURL,
		LogoURL:      params.LogoURL,
		PrimaryColor: params.PrimaryColor,
	}
	serviceName := firstNonEmpty(params.ServiceName, "First appointment")
	duration := params.DurationMinutes
	if duration <= 0 {
		duration = 60
	}
	r.services = []ServiceRecord{{
		ID:                  uuid.NewString(),
		TenantID:            tenantID,
		Name:                serviceName,
		DurationMinutes:     duration,
		BufferBeforeMinutes: maxInt(params.BufferBeforeMinutes, 0),
		BufferAfterMinutes:  maxInt(params.BufferAfterMinutes, 0),
		PriceCents:          0,
	}}
	r.rules = nil
	blocks := params.AvailabilityBlocks
	if len(blocks) == 0 {
		blocks = defaultAvailabilityBlocks()
	}
	for _, block := range blocks {
		if block.Busy {
			continue
		}
		r.rules = append(r.rules, AvailabilityRuleRecord{
			ID:          uuid.NewString(),
			TenantID:    tenantID,
			DayOfWeek:   block.DayOfWeek,
			StartsLocal: block.StartsLocal,
			EndsLocal:   block.EndsLocal,
		})
	}
	r.classSessions = nil
	r.bookings = nil
	r.reminderJobs = nil
	return r.membership, nil
}

func (r *MemoryRepository) GetTenantMembershipByUserID(_ context.Context, userID string) (TenantMembershipRecord, error) {
	if userID == "" || userID == "demo-owner" {
		return r.membership, nil
	}
	if userID == r.membership.UserID {
		return r.membership, nil
	}
	return TenantMembershipRecord{}, pgx.ErrNoRows
}

func (r *MemoryRepository) GetBrandProfile(_ context.Context, tenantID string) (BrandProfileRecord, error) {
	if tenantID != r.tenant.ID {
		return BrandProfileRecord{}, pgx.ErrNoRows
	}
	if r.brand.Name == "" {
		r.brand = BrandProfileRecord{TenantID: tenantID, Name: r.tenant.Name}
	}
	return r.brand, nil
}

func (r *MemoryRepository) ListServicesByTenant(_ context.Context, tenantID string) ([]ServiceRecord, error) {
	if tenantID != r.tenant.ID {
		return nil, nil
	}
	return append([]ServiceRecord(nil), r.services...), nil
}

func (r *MemoryRepository) ListAvailabilityRulesByTenant(_ context.Context, tenantID string) ([]AvailabilityRuleRecord, error) {
	if tenantID != r.tenant.ID {
		return nil, nil
	}
	return append([]AvailabilityRuleRecord(nil), r.rules...), nil
}

func (r *MemoryRepository) ListClassSessionsByTenant(_ context.Context, tenantID string, from time.Time, limit int) ([]ClassSessionRecord, error) {
	if tenantID != r.tenant.ID {
		return nil, nil
	}
	var out []ClassSessionRecord
	for _, session := range r.classSessions {
		if session.StartsAt.Before(from) {
			continue
		}
		out = append(out, session)
	}
	sort.Slice(out, func(i, j int) bool { return out[i].StartsAt.Before(out[j].StartsAt) })
	if len(out) > limit {
		out = out[:limit]
	}
	return out, nil
}

func (r *MemoryRepository) ListBookingsByTenantBetween(_ context.Context, tenantID string, from time.Time, to time.Time) ([]BookingRecord, error) {
	var out []BookingRecord
	for _, booking := range r.bookings {
		if booking.TenantID != tenantID {
			continue
		}
		if booking.StartsAt.Before(to) && booking.EndsAt.After(from) {
			out = append(out, booking)
		}
	}
	sort.Slice(out, func(i, j int) bool { return out[i].StartsAt.Before(out[j].StartsAt) })
	return out, nil
}

func (r *MemoryRepository) CreateBooking(_ context.Context, params CreateBookingParams) (CreatedBooking, error) {
	created := CreatedBooking{
		ID:        uuid.NewString(),
		Reference: params.Reference,
		Status:    params.Status,
	}
	r.bookings = append(r.bookings, BookingRecord{
		ID:             created.ID,
		TenantID:       params.TenantID,
		ServiceID:      params.ServiceID,
		ClassSessionID: params.ClassSessionID,
		StaffID:        params.StaffID,
		LocationID:     params.LocationID,
		CustomerName:   params.CustomerName,
		CustomerEmail:  params.CustomerEmail,
		StartsAt:       params.StartsAt,
		EndsAt:         params.EndsAt,
		Status:         params.Status,
		Reference:      params.Reference,
	})
	return created, nil
}

func (r *MemoryRepository) AppendWaitlistEntry(_ context.Context, _ WaitlistEntryParams) error {
	r.waitlistSize++
	return nil
}

func (r *MemoryRepository) CreateReminderJob(_ context.Context, params ReminderJobParams) error {
	reference := params.BookingID
	startsAt := time.Now().UTC()
	customerName := "Booking Customer"
	customerEmail := "customer@example.com"
	for _, booking := range r.bookings {
		if booking.ID == params.BookingID {
			reference = booking.Reference
			startsAt = booking.StartsAt
			customerName = booking.CustomerName
			customerEmail = booking.CustomerEmail
			break
		}
	}
	r.reminderJobs = append(r.reminderJobs, ReminderJobRecord{
		ID:            uuid.NewString(),
		TenantID:      params.TenantID,
		TenantName:    r.tenant.Name,
		Locale:        r.tenant.Locale,
		Timezone:      r.tenant.Timezone,
		BookingID:     params.BookingID,
		Channel:       params.Channel,
		ScheduledFor:  params.ScheduledFor,
		CustomerName:  customerName,
		CustomerEmail: customerEmail,
		Reference:     reference,
		StartsAt:      startsAt,
		Status:        "pending",
	})
	return nil
}

func (r *MemoryRepository) ListDueReminderJobs(_ context.Context, dueBefore time.Time, limit int) ([]ReminderJobRecord, error) {
	var out []ReminderJobRecord
	for _, job := range r.reminderJobs {
		if job.Status == "pending" && !job.ScheduledFor.After(dueBefore) {
			out = append(out, job)
		}
	}
	sort.Slice(out, func(i, j int) bool { return out[i].ScheduledFor.Before(out[j].ScheduledFor) })
	if len(out) > limit {
		out = out[:limit]
	}
	return out, nil
}

func (r *MemoryRepository) MarkReminderJobDispatched(_ context.Context, reminderJobID string, status string, _ time.Time) error {
	for index := range r.reminderJobs {
		if r.reminderJobs[index].ID == reminderJobID {
			r.reminderJobs[index].Status = status
			return nil
		}
	}
	return pgx.ErrNoRows
}

func (r *MemoryRepository) CreateNotificationDeliveryLog(_ context.Context, params NotificationDeliveryLogParams) error {
	r.deliveryLogs = append(r.deliveryLogs, params)
	return nil
}

func (r *MemoryRepository) GetDashboardMetrics(_ context.Context, tenantID string, startsAt time.Time, endsAt time.Time) (DashboardMetrics, error) {
	metrics := DashboardMetrics{}
	for _, booking := range r.bookings {
		if booking.TenantID != tenantID {
			continue
		}
		if booking.StartsAt.Before(startsAt) || !booking.StartsAt.Before(endsAt) {
			continue
		}
		metrics.BookingsCount++
		if booking.Status == "cancelled" {
			metrics.CancellationsCount++
		}
		if booking.Status == "confirmed" {
			metrics.UtilizationPercent++
		}
	}
	if metrics.BookingsCount == 0 {
		metrics.UtilizationPercent = 0
	} else {
		metrics.UtilizationPercent = int(float64(metrics.UtilizationPercent) / float64(metrics.BookingsCount) * 100)
	}
	return metrics, nil
}

func (r *MemoryRepository) GetSubscriptionSnapshot(_ context.Context, tenantID string) (BillingSnapshotRecord, error) {
	if tenantID != r.tenant.ID {
		return BillingSnapshotRecord{}, pgx.ErrNoRows
	}
	return r.billingSnapshot, nil
}

func (r *MemoryRepository) UpsertSubscriptionSnapshot(_ context.Context, params BillingSnapshotRecord) error {
	r.billingSnapshot = params
	return nil
}

func (r *MemoryRepository) UpdateTenantBillingCustomerID(_ context.Context, tenantID string, customerID string) error {
	if tenantID != r.tenant.ID {
		return pgx.ErrNoRows
	}
	r.tenant.BillingProvider = "paddle"
	r.tenant.BillingCustomerID = &customerID
	r.membership.Tenant.BillingProvider = "paddle"
	r.membership.Tenant.BillingCustomerID = &customerID
	r.billingSnapshot.BillingProvider = "paddle"
	r.billingSnapshot.BillingCustomerID = customerID
	return nil
}

func (r *MemoryRepository) UpdateTenantBillingState(_ context.Context, tenantID string, planCode string, subscriptionStatus string, subscriptionID string) error {
	if tenantID != r.tenant.ID {
		return pgx.ErrNoRows
	}
	r.tenant.PlanCode = planCode
	r.tenant.SubscriptionStatus = subscriptionStatus
	r.tenant.BillingProvider = "paddle"
	r.membership.Tenant.PlanCode = planCode
	r.membership.Tenant.SubscriptionStatus = subscriptionStatus
	r.membership.Tenant.BillingProvider = "paddle"
	r.billingSnapshot.PlanCode = planCode
	r.billingSnapshot.Status = subscriptionStatus
	r.billingSnapshot.BillingProvider = "paddle"
	r.billingSnapshot.BillingSubscriptionID = subscriptionID
	return nil
}

func (r *MemoryRepository) RecordBillingEvent(_ context.Context, _ string, provider string, eventID string, _ string, payload []byte) (bool, error) {
	key := firstNonEmpty(provider, "paddle") + ":" + eventID
	if _, exists := r.recordedEvents[key]; exists {
		return false, nil
	}
	if len(payload) > 0 {
		var raw json.RawMessage
		if err := json.Unmarshal(payload, &raw); err != nil {
			return false, err
		}
	}
	r.recordedEvents[key] = struct{}{}
	return true, nil
}

// ============================================
// LOCATION / ZONE METHODS - MEMORY REPOSITORY
// ============================================

func (r *MemoryRepository) ListLocationsByTenant(_ context.Context, tenantID string) ([]LocationRecord, error) {
	if tenantID != r.tenant.ID {
		return nil, pgx.ErrNoRows
	}
	return r.locations, nil
}

func (r *MemoryRepository) GetLocationByID(_ context.Context, locationID string) (LocationRecord, error) {
	for _, loc := range r.locations {
		if loc.ID == locationID {
			return loc, nil
		}
	}
	return LocationRecord{}, pgx.ErrNoRows
}

func (r *MemoryRepository) CreateLocation(_ context.Context, params CreateLocationParams) (LocationRecord, error) {
	loc := LocationRecord{
		ID:        uuid.NewString(),
		TenantID:  params.TenantID,
		Name:      params.Name,
		Timezone:  params.Timezone,
		CreatedAt: time.Now(),
	}
	r.locations = append(r.locations, loc)
	return loc, nil
}

func (r *MemoryRepository) UpdateLocation(_ context.Context, locationID string, params UpdateLocationParams) (LocationRecord, error) {
	for i, loc := range r.locations {
		if loc.ID == locationID {
			if params.Name != nil {
				r.locations[i].Name = *params.Name
			}
			if params.Timezone != nil {
				r.locations[i].Timezone = *params.Timezone
			}
			return r.locations[i], nil
		}
	}
	return LocationRecord{}, pgx.ErrNoRows
}

func (r *MemoryRepository) DeleteLocation(_ context.Context, locationID string) error {
	for i, loc := range r.locations {
		if loc.ID == locationID {
			r.locations = append(r.locations[:i], r.locations[i+1:]...)
			return nil
		}
	}
	return pgx.ErrNoRows
}

// ============================================
// BLOCKED DAYS METHODS - MEMORY REPOSITORY
// ============================================

func (r *MemoryRepository) ListBlockedDaysByTenant(_ context.Context, tenantID string, from time.Time, to time.Time) ([]BlockedDayRecord, error) {
	if tenantID != r.tenant.ID {
		return nil, pgx.ErrNoRows
	}
	var out []BlockedDayRecord
	for _, bd := range r.blockedDays {
		if bd.TenantID == tenantID && !bd.StartsAt.After(to) && !bd.EndsAt.Before(from) {
			out = append(out, bd)
		}
	}
	return out, nil
}

func (r *MemoryRepository) CreateBlockedDay(_ context.Context, params CreateBlockedDayParams) (BlockedDayRecord, error) {
	bd := BlockedDayRecord{
		ID:        uuid.NewString(),
		TenantID:  params.TenantID,
		StaffID:   params.StaffID,
		StartsAt:  params.StartsAt,
		EndsAt:    params.EndsAt,
		Kind:      params.Kind,
		Reason:    params.Reason,
		CreatedAt: time.Now(),
	}
	r.blockedDays = append(r.blockedDays, bd)
	return bd, nil
}

func (r *MemoryRepository) UpdateBlockedDay(_ context.Context, blockedDayID string, params UpdateBlockedDayParams) (BlockedDayRecord, error) {
	for i, bd := range r.blockedDays {
		if bd.ID == blockedDayID {
			if params.StartsAt != nil {
				r.blockedDays[i].StartsAt = *params.StartsAt
			}
			if params.EndsAt != nil {
				r.blockedDays[i].EndsAt = *params.EndsAt
			}
			if params.Kind != nil {
				r.blockedDays[i].Kind = *params.Kind
			}
			if params.Reason != nil {
				r.blockedDays[i].Reason = *params.Reason
			}
			return r.blockedDays[i], nil
		}
	}
	return BlockedDayRecord{}, pgx.ErrNoRows
}

func (r *MemoryRepository) DeleteBlockedDay(_ context.Context, blockedDayID string) error {
	for i, bd := range r.blockedDays {
		if bd.ID == blockedDayID {
			r.blockedDays = append(r.blockedDays[:i], r.blockedDays[i+1:]...)
			return nil
		}
	}
	return pgx.ErrNoRows
}

// ============================================
// CUSTOMER METHODS - MEMORY REPOSITORY
// ============================================

func (r *MemoryRepository) ListCustomersByTenant(_ context.Context, tenantID string, limit int, offset int) ([]CustomerRecord, error) {
	if tenantID != r.tenant.ID {
		return nil, pgx.ErrNoRows
	}
	start := offset
	if start > len(r.customers) {
		return []CustomerRecord{}, nil
	}
	end := start + limit
	if end > len(r.customers) {
		end = len(r.customers)
	}
	return r.customers[start:end], nil
}

func (r *MemoryRepository) GetCustomerByID(_ context.Context, customerID string) (CustomerRecord, error) {
	for _, c := range r.customers {
		if c.ID == customerID {
			return c, nil
		}
	}
	return CustomerRecord{}, pgx.ErrNoRows
}

func (r *MemoryRepository) GetCustomerByEmail(_ context.Context, tenantID string, email string) (CustomerRecord, error) {
	for _, c := range r.customers {
		if c.TenantID == tenantID && c.Email == email {
			return c, nil
		}
	}
	return CustomerRecord{}, pgx.ErrNoRows
}

func (r *MemoryRepository) CreateCustomer(_ context.Context, params CreateCustomerParams) (CustomerRecord, error) {
	c := CustomerRecord{
		ID:        uuid.NewString(),
		TenantID:  params.TenantID,
		Name:      params.Name,
		Email:     params.Email,
		Phone:     params.Phone,
		Status:    params.Status,
		CreatedAt: time.Now(),
		Notes:     params.Notes,
	}
	r.customers = append(r.customers, c)
	return c, nil
}

func (r *MemoryRepository) UpdateCustomer(_ context.Context, customerID string, params UpdateCustomerParams) (CustomerRecord, error) {
	for i, c := range r.customers {
		if c.ID == customerID {
			if params.Name != nil {
				r.customers[i].Name = *params.Name
			}
			if params.Email != nil {
				r.customers[i].Email = *params.Email
			}
			if params.Phone != nil {
				r.customers[i].Phone = params.Phone
			}
			if params.Status != nil {
				r.customers[i].Status = *params.Status
			}
			if params.Notes != nil {
				r.customers[i].Notes = params.Notes
			}
			return r.customers[i], nil
		}
	}
	return CustomerRecord{}, pgx.ErrNoRows
}

func (r *MemoryRepository) DeleteCustomer(_ context.Context, customerID string) error {
	for i, c := range r.customers {
		if c.ID == customerID {
			r.customers = append(r.customers[:i], r.customers[i+1:]...)
			return nil
		}
	}
	return pgx.ErrNoRows
}

func (r *MemoryRepository) GetCustomerBookingsCount(_ context.Context, customerID string) (int, error) {
	count := 0
	for _, b := range r.bookings {
		for _, c := range r.customers {
			if c.ID == customerID && b.CustomerEmail == c.Email {
				count++
			}
		}
	}
	return count, nil
}

func (r *MemoryRepository) GetCustomerLastBooking(_ context.Context, customerID string) (*time.Time, error) {
	var lastTime *time.Time
	var customerEmail string
	for _, c := range r.customers {
		if c.ID == customerID {
			customerEmail = c.Email
			break
		}
	}
	if customerEmail == "" {
		return nil, nil
	}
	for _, b := range r.bookings {
		if b.CustomerEmail == customerEmail {
			if lastTime == nil || b.StartsAt.After(*lastTime) {
				lastTime = &b.StartsAt
			}
		}
	}
	return lastTime, nil
}

// ============================================
// BOOKING MANAGEMENT METHODS - MEMORY REPOSITORY
// ============================================

func (r *MemoryRepository) GetBookingByReference(_ context.Context, reference string) (BookingRecord, error) {
	for _, b := range r.bookings {
		if b.Reference == reference {
			return b, nil
		}
	}
	return BookingRecord{}, pgx.ErrNoRows
}

func (r *MemoryRepository) UpdateBookingStatus(_ context.Context, bookingID string, status string) error {
	for i, b := range r.bookings {
		if b.ID == bookingID {
			r.bookings[i].Status = status
			return nil
		}
	}
	return pgx.ErrNoRows
}

func (r *MemoryRepository) RescheduleBooking(_ context.Context, bookingID string, startsAt time.Time, endsAt time.Time) error {
	for i, b := range r.bookings {
		if b.ID == bookingID {
			r.bookings[i].StartsAt = startsAt
			r.bookings[i].EndsAt = endsAt
			return nil
		}
	}
	return pgx.ErrNoRows
}

// ============================================
// WORKING HOURS METHODS - MEMORY REPOSITORY
// ============================================

func (r *MemoryRepository) ListWorkingHoursByTenant(_ context.Context, tenantID string) ([]WorkingHoursRecord, error) {
	if tenantID != r.tenant.ID {
		return nil, pgx.ErrNoRows
	}
	return r.workingHours, nil
}

func (r *MemoryRepository) UpdateWorkingHours(_ context.Context, tenantID string, dayOfWeek int, params UpdateWorkingHoursParams) error {
	if tenantID != r.tenant.ID {
		return pgx.ErrNoRows
	}
	for i, wh := range r.workingHours {
		if wh.TenantID == tenantID && wh.DayOfWeek == dayOfWeek {
			if params.StartsLocal != nil {
				r.workingHours[i].StartsLocal = *params.StartsLocal
			}
			if params.EndsLocal != nil {
				r.workingHours[i].EndsLocal = *params.EndsLocal
			}
			return nil
		}
	}
	return pgx.ErrNoRows
}

// Auth methods for MemoryRepository
func (r *MemoryRepository) GetUserByEmail(_ context.Context, email string) (*UserRecord, error) {
	return nil, nil
}

func (r *MemoryRepository) GetUserByID(_ context.Context, userID string) (*UserRecord, error) {
	return nil, nil
}

func (r *MemoryRepository) CreateUser(_ context.Context, email, passwordHash, name, provider, role string) (*UserRecord, error) {
	return &UserRecord{ID: uuid.New(), Email: email, Name: &name, Provider: provider, Role: role}, nil
}

func (r *MemoryRepository) UpdateLastLogin(_ context.Context, userID string) error {
	return nil
}

func (r *MemoryRepository) MarkEmailVerified(_ context.Context, userID string) error {
	return nil
}

func (r *MemoryRepository) CreateMagicLink(_ context.Context, token, userID, email string, expiresAt time.Time) error {
	return nil
}

func (r *MemoryRepository) GetMagicLink(_ context.Context, token string) (*MagicLinkRecord, error) {
	return nil, nil
}

func (r *MemoryRepository) MarkMagicLinkUsed(_ context.Context, token string) error {
	return nil
}

// Admin methods for MemoryRepository
func (r *MemoryRepository) ListAllTenants(_ context.Context, limit, offset int) ([]TenantRecord, int, error) {
	return []TenantRecord{r.tenant}, 1, nil
}

func (r *MemoryRepository) ListAllUsers(_ context.Context, limit, offset int) ([]UserRecord, int, error) {
	return []UserRecord{}, 0, nil
}

func (r *MemoryRepository) GetPlatformStats(_ context.Context) (PlatformStats, error) {
	return PlatformStats{TotalTenants: 1, TotalUsers: 1, ActiveSubscriptions: 1}, nil
}

func (r *MemoryRepository) CreateAdminAuditLog(_ context.Context, params AdminAuditLogParams) error {
	return nil
}

func (r *MemoryRepository) UpdateUserRole(_ context.Context, userID, role string) error {
	return nil
}

func Reference(prefix string, at time.Time) string {
	return fmt.Sprintf("%s-%s-%s", prefix, at.UTC().Format("20060102150405"), strings.Split(uuid.NewString(), "-")[0])
}

func stringPtr(value string) *string {
	return &value
}

func maxInt(left int, right int) int {
	if left > right {
		return left
	}
	return right
}

func firstNonEmpty(values ...string) string {
	for _, value := range values {
		if strings.TrimSpace(value) != "" {
			return strings.TrimSpace(value)
		}
	}
	return ""
}

func defaultAvailabilityBlocks() []AvailabilityBlockRecord {
	blocks := make([]AvailabilityBlockRecord, 0, 5)
	for day := 1; day <= 5; day++ {
		blocks = append(blocks, AvailabilityBlockRecord{
			DayOfWeek:   day,
			StartsLocal: "09:00:00",
			EndsLocal:   "17:00:00",
		})
	}
	return blocks
}
