package subscriptions

import (
	"code.secondbit.org/uuid.hg"
)

func stripeSubscriptionInMemstore(stripeSubscription string, m *Memstore) bool {
	for _, sub := range m.subscriptions {
		if sub.StripeSubscription == stripeSubscription {
			return true
		}
	}
	return false
}

func (m *Memstore) CreateSubscription(sub Subscription) error {
	m.subscriptionLock.Lock()
	defer m.subscriptionLock.Unlock()

	if _, ok := m.subscriptions[sub.UserID.String()]; ok {
		return ErrSubscriptionAlreadyExists
	}
	if stripeSubscriptionInMemstore(sub.StripeSubscription, m) {
		return ErrStripeSubscriptionAlreadyExists
	}
	m.subscriptions[sub.UserID.String()] = sub
	return nil
}

func (m *Memstore) UpdateSubscription(id uuid.ID, change SubscriptionChange) error {
	if change.IsEmpty() {
		return ErrSubscriptionChangeEmpty
	}

	m.subscriptionLock.Lock()
	defer m.subscriptionLock.Unlock()

	s, ok := m.subscriptions[id.String()]
	if !ok {
		return ErrSubscriptionNotFound
	}
	if change.StripeSubscription != nil {
		if stripeSubscriptionInMemstore(*change.StripeSubscription, m) {
			return ErrStripeSubscriptionAlreadyExists
		}
	}
	s.ApplyChange(change)
	m.subscriptions[id.String()] = s
	return nil
}

func (m *Memstore) DeleteSubscription(id uuid.ID) error {
	m.subscriptionLock.Lock()
	defer m.subscriptionLock.Unlock()

	_, ok := m.subscriptions[id.String()]
	if !ok {
		return ErrSubscriptionNotFound
	}
	delete(m.subscriptions, id.String())
	return nil
}

func (m *Memstore) GetSubscriptions(ids []uuid.ID) (map[string]Subscription, error) {
	if len(ids) < 1 {
		return map[string]Subscription{}, ErrNoSubscriptionID
	}
	m.subscriptionLock.RLock()
	defer m.subscriptionLock.RUnlock()

	result := map[string]Subscription{}

	for _, id := range ids {
		s, ok := m.subscriptions[id.String()]
		if !ok {
			continue
		}
		result[s.UserID.String()] = s
	}
	return result, nil
}

func (m *Memstore) GetSubscriptionStats() (SubscriptionStats, error) {
	m.subscriptionLock.RLock()
	defer m.subscriptionLock.RUnlock()

	stats := SubscriptionStats{
		Plans: map[string]int64{},
	}

	for _, subscription := range m.subscriptions {
		stats.Number++
		stats.Plans[subscription.Plan]++

		if subscription.Canceling {
			stats.Canceling++
		}
		if subscription.Status == "past_due" || subscription.Status == "unpaid" {
			stats.Failing++
		}
	}
	return stats, nil
}
