//go:build !lite

package provider

import (
	"context"
	"time"

	"github.com/shopspring/decimal"
)

// Provider is the abstraction over bank data providers (Plaid, Teller, CSV).
// All methods take a context for cancellation and timeout propagation.
type Provider interface {
	// CreateLinkSession starts a new account connection flow.
	CreateLinkSession(ctx context.Context, userID string) (LinkSession, error)

	// ExchangeToken completes the connection flow after the user authenticates.
	ExchangeToken(ctx context.Context, publicToken string) (Connection, []Account, error)

	// SyncTransactions fetches incremental transaction changes for a connection.
	SyncTransactions(ctx context.Context, conn Connection, cursor string) (SyncResult, error)

	// GetBalances fetches current account balances for a connection.
	GetBalances(ctx context.Context, conn Connection) ([]AccountBalance, error)

	// HandleWebhook parses and validates an inbound webhook payload.
	HandleWebhook(ctx context.Context, payload WebhookPayload) (WebhookEvent, error)

	// CreateReauthSession starts a re-authentication flow for a broken connection.
	CreateReauthSession(ctx context.Context, conn Connection) (LinkSession, error)

	// RemoveConnection revokes the provider's access and marks the connection removed.
	RemoveConnection(ctx context.Context, conn Connection) error

	// ReconcilesPendingByPolling reports whether this provider re-returns its
	// full transaction window on every sync (date-range polling), so the sync
	// engine should soft-delete pending rows no longer present in the window.
	// True for poll-based providers (Teller, SimpleFIN); false for cursor/
	// webhook providers (Plaid) and import-only providers (CSV).
	ReconcilesPendingByPolling() bool
}

type LinkSession struct {
	Token  string
	Expiry time.Time
	// ApplicationID is populated by Teller's reauth flow so the admin
	// reauth page can launch Teller Connect with both the configured app id
	// and the existing enrollment id (carried in Token). Other providers
	// leave it empty.
	ApplicationID string
}

type Connection struct {
	ProviderName         string
	ExternalID           string
	EncryptedCredentials []byte
	InstitutionName      string
	UserID               string // for provider flows that need user identity
}

type Account struct {
	ExternalID      string
	Name            string
	OfficialName    string
	Type            string // depository, credit, loan, investment
	Subtype         string // checking, savings, credit card, etc.
	Mask            string // last 4 digits
	ISOCurrencyCode string
}

type AccountBalance struct {
	AccountExternalID string
	Current           decimal.Decimal
	Available         *decimal.Decimal // nil if not provided
	Limit             *decimal.Decimal // nil if not applicable
	ISOCurrencyCode   string
}

type SyncResult struct {
	Added    []Transaction
	Modified []Transaction
	Removed  []string // external transaction IDs
	Cursor   string
	HasMore  bool
}

type Transaction struct {
	ExternalID         string
	PendingExternalID  *string // set when this transaction posts a pending one
	AccountExternalID  string
	Amount             decimal.Decimal // positive = debit, negative = credit
	Date               time.Time
	AuthorizedDate     *time.Time
	Datetime           *time.Time
	AuthorizedDatetime *time.Time
	Name               string
	MerchantName       *string
	CategoryPrimary    *string
	CategoryDetailed   *string
	CategoryConfidence *string
	PaymentChannel     string // online, in store, other
	Pending            bool
	ISOCurrencyCode    string
	Raw                []byte // provider raw JSON payload; nil if unavailable
}

type WebhookPayload struct {
	RawBody []byte
	Headers map[string]string
}

type WebhookEvent struct {
	Type                  string // "sync_available", "connection_error", "pending_expiration", "new_accounts", "unknown"
	ConnectionID          string
	ErrorCode             *string
	ErrorMessage          *string
	ConsentExpirationTime *string
	NeedsReauth           bool // provider determines if reauth needed
}
