package user

import (
	"context"
	"fmt"
	"hash/fnv"
	"strconv"

	"github.com/perfect-panel/server/internal/model/user"
	"github.com/perfect-panel/server/internal/svc"
	"github.com/perfect-panel/server/internal/types"
	"github.com/perfect-panel/server/pkg/constant"
	"github.com/perfect-panel/server/pkg/logger"
	"github.com/perfect-panel/server/pkg/xerr"
	"github.com/pkg/errors"
)

type GetInviteSalesLogic struct {
	logger.Logger
	ctx    context.Context
	svcCtx *svc.ServiceContext
}

func NewGetInviteSalesLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetInviteSalesLogic {
	return &GetInviteSalesLogic{
		Logger: logger.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

func (l *GetInviteSalesLogic) GetInviteSales(req *types.GetInviteSalesRequest) (resp *types.GetInviteSalesResponse, err error) {
	// 1. Get current user
	u, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User)
	if !ok {
		l.Errorw("[GetInviteSales] user not found in context")
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access")
	}
	userId := u.Id

	// 2. Count total sales
	var totalSales int64
	db := l.svcCtx.DB.WithContext(l.ctx).
		Table("`order` o").
		Joins("JOIN user u ON o.user_id = u.id").
		Where("u.referer_id = ? AND o.status IN ?", userId, []int{2, 5})

	if req.StartTime > 0 {
		db = db.Where("o.updated_at >= FROM_UNIXTIME(?)", req.StartTime)
	}
	if req.EndTime > 0 {
		db = db.Where("o.updated_at <= FROM_UNIXTIME(?)", req.EndTime)
	}

	err = db.Count(&totalSales).Error
	if err != nil {
		l.Errorw("[GetInviteSales] count sales failed",
			logger.Field("error", err.Error()),
			logger.Field("user_id", userId))
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError),
			"count sales failed: %v", err.Error())
	}

	// 3. Pagination
	if req.Page < 1 {
		req.Page = 1
	}
	if req.Size < 1 {
		req.Size = 10
	}
	if req.Size > 100 {
		req.Size = 100
	}
	offset := (req.Page - 1) * req.Size

	// 4. Get sales data
	type OrderWithUser struct {
		Amount      int64  `gorm:"column:amount"`
		UpdatedAt   int64  `gorm:"column:updated_at"`
		UserId      int64  `gorm:"column:user_id"`
		ProductName string `gorm:"column:product_name"`
		Quantity    int64  `gorm:"column:quantity"`
	}

	var orderData []OrderWithUser
	query := l.svcCtx.DB.WithContext(l.ctx).
		Table("`order` o").
		Select("o.amount, CAST(UNIX_TIMESTAMP(o.updated_at) * 1000 AS SIGNED) as updated_at, u.id as user_id, s.name as product_name, o.quantity").
		Joins("JOIN user u ON o.user_id = u.id").
		Joins("LEFT JOIN subscribe s ON o.subscribe_id = s.id").
		Where("u.referer_id = ? AND o.status IN ?", userId, []int{2, 5}) // status 2: Active, 5: Finished

	if req.StartTime > 0 {
		query = query.Where("o.updated_at >= FROM_UNIXTIME(?)", req.StartTime)
	}
	if req.EndTime > 0 {
		query = query.Where("o.updated_at <= FROM_UNIXTIME(?)", req.EndTime)
	}

	err = query.Order("o.updated_at DESC").
		Limit(req.Size).
		Offset(offset).
		Scan(&orderData).Error
	if err != nil {
		l.Errorw("[GetInviteSales] query sales failed",
			logger.Field("error", err.Error()),
			logger.Field("user_id", userId))
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError),
			"query sales failed: %v", err.Error())
	}

	// 5. Get sales list
	const HashSalt = "ppanel_invite_sales_v1" // Fixed Key
	var list []types.InvitedUserSale
	for _, order := range orderData {
		// Calculate unique numeric hash (FNV-64a)
		h := fnv.New64a()
		h.Write([]byte(HashSalt))
		h.Write([]byte(strconv.FormatInt(order.UserId, 10)))
		// Truncate to 10 digits using modulo 10^10
		hashVal := h.Sum64() % 10000000000
		userHashStr := fmt.Sprintf("%010d", hashVal)

		// Format product name: prefer subscribe name, fallback to quantity-based label
		productName := order.ProductName
		if productName == "" {
			productName = fmt.Sprintf("%d天VPN服务", order.Quantity)
			if order.Quantity <= 0 {
				productName = "VPN服务"
			}
		}

		list = append(list, types.InvitedUserSale{
			Amount:      float64(order.Amount) / 100.0, // Convert cents to dollars
			UpdatedAt:   order.UpdatedAt,
			UserHash:    userHashStr,
			ProductName: productName,
		})
	}

	return &types.GetInviteSalesResponse{
		Total: totalSales,
		List:  list,
	}, nil
}
