package model

import (
	"time"

	"github.com/tech/sendico/pkg/db/storable"
	paymenttypes "github.com/tech/sendico/pkg/payments/types"
)

// Quote represents a firm or indicative quote persisted by the oracle.
type Quote struct {
	storable.Base `bson:",inline" json:",inline"`

	QuoteRef               string             `bson:"quoteRef" json:"quoteRef"`
	Firm                   bool               `bson:"firm" json:"firm"`
	Status                 QuoteStatus        `bson:"status" json:"status"`
	Pair                   CurrencyPair       `bson:"pair" json:"pair"`
	Side                   QuoteSide          `bson:"side" json:"side"`
	Price                  string             `bson:"price" json:"price"`
	BaseAmount             paymenttypes.Money `bson:"baseAmount" json:"baseAmount"`
	QuoteAmount            paymenttypes.Money `bson:"quoteAmount" json:"quoteAmount"`
	AmountType             QuoteAmountType    `bson:"amountType" json:"amountType"`
	ExpiresAtUnixMs        int64              `bson:"expiresAtUnixMs" json:"expiresAtUnixMs"`
	PricedAtUnixMs         int64              `bson:"pricedAtUnixMs,omitempty" json:"pricedAtUnixMs,omitempty"`
	ExpiresAt              *time.Time         `bson:"expiresAt,omitempty" json:"expiresAt,omitempty"`
	RateRef                string             `bson:"rateRef" json:"rateRef"`
	Provider               string             `bson:"provider" json:"provider"`
	PreferredProvider      string             `bson:"preferredProvider,omitempty" json:"preferredProvider,omitempty"`
	RequestedTTLMs         int64              `bson:"requestedTtlMs,omitempty" json:"requestedTtlMs,omitempty"`
	MaxAgeToleranceMs      int64              `bson:"maxAgeToleranceMs,omitempty" json:"maxAgeToleranceMs,omitempty"`
	ConsumedByLedgerTxnRef string             `bson:"consumedByLedgerTxnRef,omitempty" json:"consumedByLedgerTxnRef,omitempty"`
	ConsumedAtUnixMs       *int64             `bson:"consumedAtUnixMs,omitempty" json:"consumedAtUnixMs,omitempty"`
	Meta                   *QuoteMeta         `bson:"meta,omitempty" json:"meta,omitempty"`
}

// Collection implements storable.Storable.
func (*Quote) Collection() string {
	return QuotesCollection
}

// MarkConsumed switches the quote to consumed status and links it to a ledger transaction.
func (q *Quote) MarkConsumed(ledgerTxnRef string, consumedAt time.Time) {
	if ledgerTxnRef == "" {
		return
	}
	q.Status = QuoteStatusConsumed
	q.ConsumedByLedgerTxnRef = ledgerTxnRef
	ts := consumedAt.UnixMilli()
	q.ConsumedAtUnixMs = &ts
	q.Update()
}

// MarkExpired marks the quote as expired.
func (q *Quote) MarkExpired() {
	q.Status = QuoteStatusExpired
	q.Update()
}

// IsExpired reports whether the quote has passed its expiration instant.
func (q *Quote) IsExpired(now time.Time) bool {
	if q.ExpiresAtUnixMs == 0 {
		return false
	}
	return now.UnixMilli() >= q.ExpiresAtUnixMs
}
