package user

import (
	"context"

	adminInvite "github.com/perfect-panel/server/internal/logic/admin/invite"
	"github.com/perfect-panel/server/internal/svc"
	"github.com/perfect-panel/server/internal/types"
	"github.com/perfect-panel/server/pkg/logger"
	"github.com/perfect-panel/server/pkg/xerr"
	"github.com/pkg/errors"
	"gorm.io/gorm"
)

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

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

func (l *GetAdminUserInviteListLogic) GetAdminUserInviteList(req *types.GetAdminUserInviteListRequest) (resp *types.GetAdminUserInviteListResponse, err error) {
	req.Page, req.Size = adminInvite.NormalizePage(req.Page, req.Size)

	type InvitedUser struct {
		Id         int64  `gorm:"column:id"`
		Avatar     string `gorm:"column:avatar"`
		Identifier string `gorm:"column:identifier"`
		Enable     bool   `gorm:"column:enable"`
		CreatedAt  int64  `gorm:"column:created_at"`
	}

	var total int64
	baseQuery := applyAdminUserInviteFilters(l.svcCtx.DB.WithContext(l.ctx).
		Table("user u").
		Where("u.referer_id = ? AND u.deleted_at IS NULL", req.UserId), req)

	if err = baseQuery.Count(&total).Error; err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "count invited users failed: %v", err)
	}

	var rows []InvitedUser
	err = applyAdminUserInviteFilters(l.svcCtx.DB.WithContext(l.ctx).
		Table("user u").
		Select("u.id, u.avatar, u.enable, CAST(UNIX_TIMESTAMP(u.created_at) AS SIGNED) as created_at, COALESCE((SELECT uam.auth_identifier FROM user_auth_methods uam WHERE uam.user_id = u.id ORDER BY uam.id ASC LIMIT 1), '') as identifier").
		Where("u.referer_id = ? AND u.deleted_at IS NULL", req.UserId), req).
		Order("u.created_at DESC").
		Limit(req.Size).
		Offset((req.Page - 1) * req.Size).
		Scan(&rows).Error
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query invited users failed: %v", err)
	}

	relations := make([]adminInvite.InviteRelation, 0, len(rows))
	for _, r := range rows {
		relations = append(relations, adminInvite.InviteRelation{InviteeId: r.Id, InviterId: req.UserId})
	}
	benefits, err := adminInvite.QueryBenefits(l.ctx, l.svcCtx.DB, relations)
	if err != nil {
		return nil, err
	}

	list := make([]types.AdminInvitedUser, 0, len(rows))
	for _, r := range rows {
		benefit := benefits[r.Id]
		list = append(list, types.AdminInvitedUser{
			Id:                r.Id,
			Avatar:            r.Avatar,
			Identifier:        r.Identifier,
			Enable:            r.Enable,
			CreatedAt:         r.CreatedAt,
			OrderCount:        benefit.OrderCount,
			HasPurchased:      benefit.HasPurchased,
			InviterCommission: benefit.InviterCommission,
			InviterGiftDays:   benefit.InviterGiftDays,
			InviteeGiftDays:   benefit.InviteeGiftDays,
		})
	}

	return &types.GetAdminUserInviteListResponse{
		Total: total,
		List:  list,
	}, nil
}

func applyAdminUserInviteFilters(db *gorm.DB, req *types.GetAdminUserInviteListRequest) *gorm.DB {
	if req.Search != "" {
		db = db.Where("EXISTS (SELECT 1 FROM user_auth_methods uam WHERE uam.user_id = u.id AND uam.auth_identifier LIKE ?)", "%"+req.Search+"%")
	}
	if req.Enable != nil {
		db = db.Where("u.enable = ?", *req.Enable)
	}
	if req.UserIdSearch > 0 {
		db = db.Where("u.id = ?", req.UserIdSearch)
	}
	return db
}
