package payment

import (
	"time"

	"cloud.o-forge.io/core/oc-lib/models/common/pricing"
)

type ScheduleStatus int

const (
	SCHEDULE_ACTIVE    ScheduleStatus = iota
	SCHEDULE_PAUSED                   // mis en pause manuellement
	SCHEDULE_CANCELLED                // résilié
	SCHEDULE_COMPLETED                // terminé normalement (abonnement expiré)
	SCHEDULE_FAILED                   // trop d'échecs consécutifs
)

func (s ScheduleStatus) String() string {
	return [...]string{"active", "paused", "cancelled", "completed", "failed"}[s]
}

// PaymentSchedule pilote la récurrence des paiements d'un abonnement.
type PaymentSchedule struct {
	SubscriptionID  string             `json:"subscription_id" bson:"subscription_id"`
	Frequency       pricing.PaymentType `json:"frequency" bson:"frequency"` // PAY_EVERY_WEEK / PAY_EVERY_MONTH / PAY_EVERY_YEAR
	Amount          float64            `json:"amount" bson:"amount"`
	Currency        string             `json:"currency" bson:"currency"`
	Status          ScheduleStatus     `json:"status" bson:"status"`
	NextPaymentDate time.Time          `json:"next_payment_date" bson:"next_payment_date"`
	LastExecutedAt  *time.Time         `json:"last_executed_at,omitempty" bson:"last_executed_at,omitempty"`
	FailureCount    int                `json:"failure_count" bson:"failure_count"`
	MaxRetries      int                `json:"max_retries" bson:"max_retries" default:"3"`
}

// nextDate calcule la prochaine date selon la fréquence.
func (ps *PaymentSchedule) nextDate() time.Time {
	switch ps.Frequency {
	case pricing.PAY_EVERY_WEEK:
		return ps.NextPaymentDate.AddDate(0, 0, 7)
	case pricing.PAY_EVERY_MONTH:
		return ps.NextPaymentDate.AddDate(0, 1, 0)
	case pricing.PAY_EVERY_YEAR:
		return ps.NextPaymentDate.AddDate(1, 0, 0)
	}
	return ps.NextPaymentDate
}

// Advance enregistre l'exécution réussie et avance à la prochaine échéance.
func (ps *PaymentSchedule) Advance() {
	now := time.Now().UTC()
	ps.LastExecutedAt = &now
	ps.FailureCount = 0
	ps.NextPaymentDate = ps.nextDate()
}

// RecordFailure incrémente le compteur d'échecs et désactive après MaxRetries.
func (ps *PaymentSchedule) RecordFailure() {
	ps.FailureCount++
	if ps.MaxRetries > 0 && ps.FailureCount >= ps.MaxRetries {
		ps.Status = SCHEDULE_FAILED
	}
}

// IsDue retourne vrai si le paiement est dû maintenant.
func (ps *PaymentSchedule) IsDue() bool {
	return ps.Status == SCHEDULE_ACTIVE && !time.Now().UTC().Before(ps.NextPaymentDate)
}

// Pause suspend temporairement le calendrier.
func (ps *PaymentSchedule) Pause() {
	if ps.Status == SCHEDULE_ACTIVE {
		ps.Status = SCHEDULE_PAUSED
	}
}

// Resume réactive un calendrier mis en pause.
func (ps *PaymentSchedule) Resume() {
	if ps.Status == SCHEDULE_PAUSED {
		ps.Status = SCHEDULE_ACTIVE
	}
}
