package apple

import (
	"context"
	"crypto/sha256"
	"encoding/hex"
	"fmt"

	"github.com/perfect-panel/server/pkg/cache"
	"github.com/redis/go-redis/v9"
	"gorm.io/gorm"
)

type Model interface {
	Insert(ctx context.Context, data *Transaction, tx ...*gorm.DB) error
	FindByOriginalId(ctx context.Context, originalId string) (*Transaction, error)
	FindByUserAndProduct(ctx context.Context, userId int64, productId string) (*Transaction, error)
	FindLatestByUserId(ctx context.Context, userId int64) (*Transaction, error)
}

type defaultModel struct {
	cache.CachedConn
	table string
}

type customModel struct {
	*defaultModel
}

func NewModel(db *gorm.DB, c *redis.Client) Model {
	return &customModel{
		defaultModel: &defaultModel{
			CachedConn: cache.NewConn(db, c),
			table:      "`apple_iap_transactions`",
		},
	}
}

func (m *defaultModel) jwsKey(jws string) string {
	sum := sha256.Sum256([]byte(jws))
	return fmt.Sprintf("cache:iap:jws:%s", hex.EncodeToString(sum[:]))
}

func (m *customModel) Insert(ctx context.Context, data *Transaction, tx ...*gorm.DB) error {
	return m.ExecCtx(ctx, func(conn *gorm.DB) error {
		if len(tx) > 0 {
			conn = tx[0]
		}
		return conn.Model(&Transaction{}).Create(data).Error
	}, m.jwsKey(data.JWSHash))
}

func (m *customModel) FindByOriginalId(ctx context.Context, originalId string) (*Transaction, error) {
	var data Transaction
	key := fmt.Sprintf("cache:iap:original:%s", originalId)
	err := m.QueryCtx(ctx, &data, key, func(conn *gorm.DB, v interface{}) error {
		return conn.Model(&Transaction{}).Where("original_transaction_id = ?", originalId).First(&data).Error
	})
	return &data, err
}

func (m *customModel) FindByUserAndProduct(ctx context.Context, userId int64, productId string) (*Transaction, error) {
	var data Transaction
	err := m.QueryNoCacheCtx(ctx, &data, func(conn *gorm.DB, v interface{}) error {
		return conn.Model(&Transaction{}).Where("user_id = ? AND product_id = ?", userId, productId).Order("purchase_at DESC").First(&data).Error
	})
	return &data, err
}

// FindLatestByUserId 查找指定用户最近的一条交易记录
// 用于获取已知的 originalTransactionId，以便查询 Apple 交易历史
func (m *customModel) FindLatestByUserId(ctx context.Context, userId int64) (*Transaction, error) {
	var data Transaction
	err := m.QueryNoCacheCtx(ctx, &data, func(conn *gorm.DB, v interface{}) error {
		return conn.Model(&Transaction{}).Where("user_id = ?", userId).Order("purchase_at DESC").First(&data).Error
	})
	return &data, err
}

