package user

import (
	"context"
	"fmt"
	"strings"
	"time"

	logicCommon "github.com/perfect-panel/server/internal/logic/common"
	"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/logger"
	"github.com/perfect-panel/server/pkg/phone"
	"github.com/perfect-panel/server/pkg/tool"
	"github.com/perfect-panel/server/pkg/xerr"
	"github.com/pkg/errors"
)

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

func NewGetUserListLogic(ctx context.Context, svcCtx *svc.ServiceContext) *GetUserListLogic {
	return &GetUserListLogic{
		ctx:    ctx,
		svcCtx: svcCtx,
		Logger: logger.WithContext(ctx),
	}
}
func (l *GetUserListLogic) GetUserList(req *types.GetUserListRequest) (*types.GetUserListResponse, error) {
	list, total, err := l.svcCtx.UserModel.QueryPageList(l.ctx, req.Page, req.Size, &user.UserFilterParams{
		UserId:            req.UserId,
		Search:            req.Search,
		Unscoped:          req.Unscoped,
		SubscribeId:       req.SubscribeId,
		UserSubscribeId:   req.UserSubscribeId,
		ShortCode:         req.ShortCode,
		DeviceId:          req.DeviceId,
		FamilyJoined:      req.FamilyJoined,
		FamilyStatus:      req.FamilyStatus,
		FamilyOwnerUserId: req.FamilyOwnerUserId,
		FamilyId:          req.FamilyId,
		Order:             req.SortOrder,
	})
	if err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "GetUserListLogic failed: %v", err.Error())
	}

	referCodes := make([]string, 0, len(list))
	for _, item := range list {
		referCode := strings.TrimSpace(item.ReferCode)
		if referCode == "" {
			continue
		}
		referCodes = append(referCodes, referCode)
	}
	inviteLinkMap := logicCommon.NewInviteLinkResolver(l.ctx, l.svcCtx).ResolveInviteLinksBatch(referCodes, 8, 3, 1500*time.Millisecond)

	// Batch fetch active subscriptions
	userIds := make([]int64, 0, len(list))
	for _, u := range list {
		userIds = append(userIds, u.Id)
	}
	activeSubs, err := l.svcCtx.UserModel.FindActiveSubscribesByUserIds(l.ctx, userIds)
	if err != nil {
		// Log error but continue
		l.Logger.Error("FindActiveSubscribesByUserIds failed", logger.Field("error", err.Error()))
	}

	type familyRelation struct {
		UserId       int64
		FamilyId     int64
		Role         uint8
		FamilyStatus uint8
		OwnerUserId  int64
		MaxMembers   int64
	}

	relationMap := map[int64]familyRelation{}
	familyIds := make([]int64, 0)
	if len(userIds) > 0 {
		var relations []familyRelation
		relationErr := l.svcCtx.DB.WithContext(l.ctx).
			Table("user_family_member").
			Select("user_family_member.user_id, user_family_member.family_id, user_family_member.role, user_family.status as family_status, user_family.owner_user_id, user_family.max_members").
			Joins("JOIN user_family ON user_family.id = user_family_member.family_id AND user_family.deleted_at IS NULL").
			Where("user_family_member.user_id IN ? AND user_family_member.deleted_at IS NULL AND user_family_member.status = ?", userIds, user.FamilyMemberActive).
			Scan(&relations).Error
		if relationErr != nil {
			l.Logger.Error("query family relations failed", logger.Field("error", relationErr.Error()))
		}

		familyIdSet := make(map[int64]struct{}, len(relations))
		for _, relation := range relations {
			if _, exists := relationMap[relation.UserId]; !exists {
				relationMap[relation.UserId] = relation
			}
			if _, ok := familyIdSet[relation.FamilyId]; ok {
				continue
			}
			familyIdSet[relation.FamilyId] = struct{}{}
			familyIds = append(familyIds, relation.FamilyId)
		}
	}

	type familyCount struct {
		FamilyId int64
		Count    int64
	}

	familyCountMap := map[int64]int64{}
	if len(familyIds) > 0 {
		var counts []familyCount
		countErr := l.svcCtx.DB.WithContext(l.ctx).
			Table("user_family_member").
			Select("family_id, COUNT(1) as count").
			Where("family_id IN ? AND status = ? AND deleted_at IS NULL", familyIds, user.FamilyMemberActive).
			Group("family_id").
			Scan(&counts).Error
		if countErr != nil {
			l.Logger.Error("query family member count failed", logger.Field("error", countErr.Error()))
		}
		for _, count := range counts {
			familyCountMap[count.FamilyId] = count.Count
		}
	}

	userRespList := make([]types.User, 0, len(list))

	for _, item := range list {
		var u types.User
		tool.DeepCopy(&u, item)

		// Set LastLoginTime
		if item.LastLoginTime != nil {
			u.LastLoginTime = item.LastLoginTime.Unix()
		}

		// Set MemberStatus and update LastLoginTime from traffic
		if activeSubs != nil {
			if info, ok := activeSubs[item.Id]; ok {
				u.MemberStatus = info.MemberStatus
				u.PurchasedPackage = info.PurchasedPackage
				if info.LastTrafficAt != nil {
					trafficTime := info.LastTrafficAt.Unix()
					if trafficTime > u.LastLoginTime {
						u.LastLoginTime = trafficTime
					}
				}
			}
		}

		// 处理 AuthMethods
		authMethods := make([]types.UserAuthMethod, len(u.AuthMethods)) // 直接创建目标 slice
		for i, method := range u.AuthMethods {
			tool.DeepCopy(&authMethods[i], method)
			if method.AuthType == "mobile" {
				authMethods[i].AuthIdentifier = phone.FormatToInternational(method.AuthIdentifier)
			}
		}
		u.AuthMethods = authMethods

		// 填充 DeviceID
		for i, d := range item.UserDevices {
			if i < len(u.UserDevices) {
				u.UserDevices[i].DeviceNo = tool.DeviceIdToHash(d.Id)
			}
		}

		if relation, ok := relationMap[item.Id]; ok {
			u.FamilyJoined = true
			u.FamilyId = relation.FamilyId
			u.FamilyRole = relation.Role
			u.FamilyOwnerUserId = relation.OwnerUserId
			u.FamilyMaxMembers = relation.MaxMembers
			u.FamilyMemberCount = familyCountMap[relation.FamilyId]
			switch relation.FamilyStatus {
			case user.FamilyStatusActive:
				u.FamilyStatus = "active"
			default:
				u.FamilyStatus = "disabled"
			}
			switch relation.Role {
			case user.FamilyRoleOwner:
				u.FamilyRoleName = "owner"
			case user.FamilyRoleMember:
				u.FamilyRoleName = "member"
			default:
				u.FamilyRoleName = fmt.Sprintf("role_%d", relation.Role)
			}
		}
		if referCode := strings.TrimSpace(item.ReferCode); referCode != "" {
			u.ShareLink = inviteLinkMap[referCode]
		}

		userRespList = append(userRespList, u)
	}

	return &types.GetUserListResponse{
		Total: total,
		List:  userRespList,
	}, nil
}
