package invite

import (
	"context"
	"database/sql"
	"encoding/json"
	"strings"

	"hyapp/pkg/appcode"
	"hyapp/pkg/xerr"
	invitedomain "hyapp/services/user-service/internal/domain/invite"
)

// WalletOutboxReader reads recharge facts from wallet-service outbox without mutating wallet state.
type WalletOutboxReader struct {
	db *sql.DB
}

// NewWalletOutboxReader creates a read-only wallet outbox scanner.
func NewWalletOutboxReader(db *sql.DB) *WalletOutboxReader {
	return &WalletOutboxReader{db: db}
}

// ListRechargeEventsAfter returns wallet recharge events after the caller's in-memory cursor.
func (r *WalletOutboxReader) ListRechargeEventsAfter(ctx context.Context, cursor invitedomain.WalletRechargeCursor, batchSize int) ([]invitedomain.RechargeEvent, error) {
	if r == nil || r.db == nil {
		return nil, xerr.New(xerr.Unavailable, "wallet outbox reader is not configured")
	}
	if batchSize <= 0 {
		batchSize = 100
	}
	rows, err := r.db.QueryContext(ctx, `
		SELECT app_code, event_id, event_type, transaction_id, command_id, user_id, asset_type, available_delta,
		       COALESCE(CAST(payload AS CHAR), '{}'), created_at_ms
		FROM wallet_outbox
		WHERE event_type = ?
		  AND (created_at_ms > ? OR (created_at_ms = ? AND event_id > ?))
		ORDER BY created_at_ms ASC, event_id ASC
		LIMIT ?
	`, invitedomain.RechargeEventWalletRecorded, cursor.CreatedAtMs, cursor.CreatedAtMs, cursor.EventID, batchSize)
	if err != nil {
		return nil, err
	}
	defer rows.Close()

	events := make([]invitedomain.RechargeEvent, 0, batchSize)
	for rows.Next() {
		var event invitedomain.RechargeEvent
		if err := rows.Scan(&event.AppCode, &event.EventID, &event.EventType, &event.TransactionID, &event.CommandID, &event.InvitedUserID, &event.AssetType, &event.RechargeCoinAmount, &event.PayloadJSON, &event.OccurredAtMs); err != nil {
			return nil, err
		}
		event.AppCode = appcode.Normalize(event.AppCode)
		event.RechargeType = rechargeTypeFromPayload(event.PayloadJSON)
		events = append(events, event)
	}
	return events, rows.Err()
}

func rechargeTypeFromPayload(payload string) string {
	var decoded map[string]any
	if err := json.Unmarshal([]byte(payload), &decoded); err == nil {
		if value, ok := decoded["recharge_type"].(string); ok && strings.TrimSpace(value) != "" {
			return strings.TrimSpace(value)
		}
	}
	// 当前 wallet-service 的 WalletRechargeRecorded 来源是币商转账充值事实。
	return invitedomain.RechargeTypeCoinSellerTransfer
}
