package services

import (
	"context"
	"errors"
	"time"

	"quyun/v2/app/errorx"
	user_dto "quyun/v2/app/http/v1/dto"
	"quyun/v2/database/fields"
	"quyun/v2/database/models"
	"quyun/v2/pkg/consts"

	"github.com/google/uuid"
	"go.ipao.vip/gen/field"
	"go.ipao.vip/gen/types"
	"gorm.io/gorm"
)

// @provider
type wallet struct{}

func (s *wallet) GetWallet(ctx context.Context, tenantID, userID int64) (*user_dto.WalletResponse, error) {
	// Get Balance
	u, err := models.UserQuery.WithContext(ctx).Where(models.UserQuery.ID.Eq(userID)).First()
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return nil, errorx.ErrRecordNotFound
		}
		return nil, errorx.ErrDatabaseError.WithCause(err)
	}

	// Get Transactions (Orders)
	// Both purchase (expense) and recharge (income - if paid)
	tbl, q := models.OrderQuery.QueryContext(ctx)
	if tenantID > 0 {
		q = q.Where(tbl.Status.Eq(consts.OrderStatusPaid)).
			Where(field.Or(
				field.And(tbl.UserID.Eq(userID), tbl.TenantID.Eq(tenantID)),
				field.And(tbl.UserID.Eq(userID), tbl.Type.Eq(consts.OrderTypeRecharge)),
			))
	} else {
		q = q.Where(tbl.UserID.Eq(userID), tbl.Status.Eq(consts.OrderStatusPaid))
	}
	orders, err := q.
		Order(tbl.CreatedAt.Desc()).
		Limit(20). // Limit to recent 20
		Find()
	if err != nil {
		return nil, errorx.ErrDatabaseError.WithCause(err)
	}

	var txs []user_dto.Transaction
	for _, o := range orders {
		var txType string
		var title string
		switch o.Type {
		case consts.OrderTypeContentPurchase:
			txType = "expense"
			title = "购买内容"
		case consts.OrderTypeRecharge:
			txType = "income"
			title = "钱包充值"
		}

		txs = append(txs, user_dto.Transaction{
			ID:     o.ID,
			Title:  title,
			Amount: float64(o.AmountPaid) / 100.0,
			Type:   txType,
			Date:   o.CreatedAt.Format(time.RFC3339),
		})
	}

	return &user_dto.WalletResponse{
		Balance:      float64(u.Balance) / 100.0,
		Transactions: txs,
	}, nil
}

func (s *wallet) Recharge(
	ctx context.Context,
	tenantID int64,
	userID int64,
	form *user_dto.RechargeForm,
) (*user_dto.RechargeResponse, error) {
	amount := int64(form.Amount * 100)
	if amount <= 0 {
		return nil, errorx.ErrBadRequest.WithMsg("金额无效")
	}

	// Create Recharge Order
	order := &models.Order{
		TenantID:       0, // Platform / System
		UserID:         userID,
		Type:           consts.OrderTypeRecharge,
		Status:         consts.OrderStatusCreated,
		Currency:       consts.CurrencyCNY,
		AmountOriginal: amount,
		AmountPaid:     amount,
		IdempotencyKey: uuid.NewString(),
		Snapshot:       types.NewJSONType(fields.OrdersSnapshot{}),
	}

	if err := models.OrderQuery.WithContext(ctx).Create(order); err != nil {
		return nil, errorx.ErrDatabaseError.WithCause(err)
	}

	// MOCK: Automatically pay for recharge order to close the loop
	// In production, this would be a callback from payment gateway
	if err := Order.ProcessExternalPayment(ctx, tenantID, order.ID, "mock_auto_pay"); err != nil {
		return nil, err
	}

	// Mock Pay Params
	return &user_dto.RechargeResponse{
		PayParams: "mock_paid_success",
		OrderID:   order.ID,
	}, nil
}
