package model

import (
	"strings"
	"time"

	"github.com/tech/sendico/pkg/db/storable"
	pmodel "github.com/tech/sendico/pkg/model"
	"github.com/tech/sendico/pkg/mservice"
	paytypes "github.com/tech/sendico/pkg/payments/types"
	moneyv1 "github.com/tech/sendico/pkg/proto/common/money/v1"
)

type TransferStatus string

const (
	TransferStatusCreated    TransferStatus = "created"    // record exists, not started
	TransferStatusProcessing TransferStatus = "processing" // we are working on it
	TransferStatusWaiting    TransferStatus = "waiting"    // waiting external world

	TransferStatusSuccess   TransferStatus = "success"   // final success
	TransferStatusFailed    TransferStatus = "failed"    // final failure
	TransferStatusCancelled TransferStatus = "cancelled" // final cancelled
)

// ServiceFee represents a fee component applied to a transfer.
type ServiceFee struct {
	FeeCode     string         `bson:"feeCode" json:"feeCode"`
	Amount      *moneyv1.Money `bson:"amount" json:"amount"`
	Description string         `bson:"description,omitempty" json:"description,omitempty"`
}

type TransferDestination struct {
	ManagedWalletRef        string `bson:"managedWalletRef,omitempty" json:"managedWalletRef,omitempty"`
	ExternalAddress         string `bson:"externalAddress,omitempty" json:"externalAddress,omitempty"`
	ExternalAddressOriginal string `bson:"externalAddressOriginal,omitempty" json:"externalAddressOriginal,omitempty"`
	Memo                    string `bson:"memo,omitempty" json:"memo,omitempty"`
}

// Transfer models an on-chain transfer orchestrated by the gateway.
type Transfer struct {
	storable.Base `bson:",inline" json:",inline"`

	OperationRef    string              `bson:"operationRef" json:"operationRef"`
	TransferRef     string              `bson:"transferRef" json:"transferRef"`
	IdempotencyKey  string              `bson:"intentRef" json:"intentRef"`
	IntentRef       string              `bson:"idempotencyKey" json:"idempotencyKey"`
	OrganizationRef string              `bson:"organizationRef" json:"organizationRef"`
	SourceWalletRef string              `bson:"sourceWalletRef" json:"sourceWalletRef"`
	Destination     TransferDestination `bson:"destination" json:"destination"`
	Network         pmodel.ChainNetwork `bson:"network" json:"network"`
	TokenSymbol     string              `bson:"tokenSymbol" json:"tokenSymbol"`
	ContractAddress string              `bson:"contractAddress" json:"contractAddress"`
	RequestedAmount *paytypes.Money     `bson:"requestedAmount" json:"requestedAmount"`
	NetAmount       *paytypes.Money     `bson:"netAmount" json:"netAmount"`
	Fees            []ServiceFee        `bson:"fees,omitempty" json:"fees,omitempty"`
	Status          TransferStatus      `bson:"status" json:"status"`
	TxHash          string              `bson:"txHash,omitempty" json:"txHash,omitempty"`
	FailureReason   string              `bson:"failureReason,omitempty" json:"failureReason,omitempty"`
	PaymentRef      string              `bson:"paymentRef,omitempty" json:"paymentRef,omitempty"`
	LastStatusAt    time.Time           `bson:"lastStatusAt" json:"lastStatusAt"`
}

// Collection implements storable.Storable.
func (*Transfer) Collection() string {
	return mservice.ChainTransfers
}

// TransferFilter describes the parameters for listing transfers.
type TransferFilter struct {
	SourceWalletRef      string
	DestinationWalletRef string
	Status               TransferStatus
	Cursor               string
	Limit                int32
}

// TransferList contains paginated transfer results.
type TransferList struct {
	Items      []*Transfer
	NextCursor string
}

// Normalize trims strings for consistent indexes.
func (t *Transfer) Normalize() {
	t.TransferRef = strings.TrimSpace(t.TransferRef)
	t.IdempotencyKey = strings.TrimSpace(t.IdempotencyKey)
	t.OrganizationRef = strings.TrimSpace(t.OrganizationRef)
	t.SourceWalletRef = strings.TrimSpace(t.SourceWalletRef)
	t.TokenSymbol = strings.TrimSpace(strings.ToUpper(t.TokenSymbol))
	t.ContractAddress = strings.TrimSpace(strings.ToLower(t.ContractAddress))
	t.Destination.ManagedWalletRef = strings.TrimSpace(t.Destination.ManagedWalletRef)
	t.Destination.ExternalAddress = normalizeWalletAddress(t.Destination.ExternalAddress)
	t.Destination.ExternalAddressOriginal = strings.TrimSpace(t.Destination.ExternalAddressOriginal)
	t.Destination.Memo = strings.TrimSpace(t.Destination.Memo)
	t.PaymentRef = strings.TrimSpace(t.PaymentRef)
}
