package user

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

	"github.com/perfect-panel/server/internal/config"
	"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"
	"gorm.io/gorm"
)

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

// NewDeleteAccountLogic 创建注销账号逻辑实例
func NewDeleteAccountLogic(ctx context.Context, svcCtx *svc.ServiceContext) *DeleteAccountLogic {
	return &DeleteAccountLogic{
		Logger: logger.WithContext(ctx),
		ctx:    ctx,
		svcCtx: svcCtx,
	}
}

// DeleteAccount 保留兼容入口，统一走全量注销登录逻辑
func (l *DeleteAccountLogic) DeleteAccount() (resp *types.DeleteAccountResponse, err error) {
	return l.DeleteAccountAll()
}

// DeleteAccountAll 注销登录 + 退出家庭/解散家庭，不删除账号主体
func (l *DeleteAccountLogic) DeleteAccountAll() (resp *types.DeleteAccountResponse, err error) {
	currentUser, ok := l.ctx.Value(constant.CtxKeyUser).(*user.User)
	if !ok || currentUser == nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.InvalidAccess), "Invalid Access")
	}

	// 事务前：查找家庭关系，收集所有成员 ID
	allMemberIDs := []int64{currentUser.Id}
	var familyId int64
	if relation, relErr := l.findActiveFamilyRelation(currentUser.Id); relErr == nil {
		familyId = relation.FamilyId
		var memberIDs []int64
		if pluckErr := l.svcCtx.DB.WithContext(l.ctx).
			Model(&user.UserFamilyMember{}).
			Where("family_id = ? AND status = ? AND deleted_at IS NULL", familyId, user.FamilyMemberActive).
			Pluck("user_id", &memberIDs).Error; pluckErr == nil {
			idSet := map[int64]struct{}{currentUser.Id: {}}
			for _, id := range memberIDs {
				if id > 0 {
					if _, exists := idSet[id]; !exists {
						idSet[id] = struct{}{}
						allMemberIDs = append(allMemberIDs, id)
					}
				}
			}
		}
	}

	// 事务前：收集所有成员的 AuthMethods（事务后用于精确清缓存）
	allAuthMethods := make([]*user.AuthMethods, 0)
	for _, memberID := range allMemberIDs {
		if ams, amErr := l.svcCtx.UserModel.FindUserAuthMethods(l.ctx, memberID); amErr == nil {
			allAuthMethods = append(allAuthMethods, ams...)
		}
	}

	// 事务内：解散家庭 + 删除所有成员的 AuthMethods + Subscribe
	err = l.svcCtx.UserModel.Transaction(l.ctx, func(tx *gorm.DB) error {
		// 无论 member 还是 owner，都解散整个家庭
		if familyId > 0 {
			now := time.Now()
			if txErr := tx.Model(&user.UserFamilyMember{}).
				Where("family_id = ? AND status = ?", familyId, user.FamilyMemberActive).
				Updates(map[string]interface{}{
					"status":  user.FamilyMemberRemoved,
					"left_at": now,
				}).Error; txErr != nil {
				return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "remove all family members failed")
			}
			if txErr := tx.Model(&user.UserFamily{}).
				Where("id = ?", familyId).
				Updates(map[string]interface{}{
					"status": familyStatusDisabled,
				}).Error; txErr != nil {
				return errors.Wrapf(xerr.NewErrCode(xerr.DatabaseUpdateError), "disable family failed")
			}
		}

		// 删除所有成员的 AuthMethods 和 Subscribe
		for _, memberID := range allMemberIDs {
			if txErr := tx.Where("user_id = ?", memberID).Delete(&user.AuthMethods{}).Error; txErr != nil {
				l.Errorw("delete auth methods failed", logger.Field("user_id", memberID), logger.Field("error", txErr.Error()))
			}
			if txErr := tx.Where("user_id = ?", memberID).Delete(&user.Subscribe{}).Error; txErr != nil {
				l.Errorw("delete subscribes failed", logger.Field("user_id", memberID), logger.Field("error", txErr.Error()))
			}
		}

		return nil
	})
	if err != nil {
		return nil, err
	}

	// 事务后：清除所有成员的 Session + 踢设备
	for _, memberID := range allMemberIDs {
		l.clearAllSessions(memberID)
		var memberDevices []user.Device
		l.svcCtx.DB.WithContext(l.ctx).
			Model(&user.Device{}).
			Where("user_id = ?", memberID).
			Find(&memberDevices)
		for _, d := range memberDevices {
			l.svcCtx.DeviceManager.KickDevice(d.UserId, d.Identifier)
		}
	}

	// 清除 auth method 相关缓存（email key 等）
	if len(allAuthMethods) > 0 {
		var authCacheKeys []string
		for _, am := range allAuthMethods {
			if am.AuthType == "email" && am.AuthIdentifier != "" {
				authCacheKeys = append(authCacheKeys, fmt.Sprintf("cache:user:email:%s", am.AuthIdentifier))
			}
		}
		if len(authCacheKeys) > 0 {
			if delErr := l.svcCtx.Redis.Del(l.ctx, authCacheKeys...).Err(); delErr != nil {
				l.Errorw("clear auth method cache failed",
					logger.Field("user_id", currentUser.Id),
					logger.Field("error", delErr.Error()),
				)
			}
		}
	}

	// 清除所有成员的 user + subscribe 缓存
	if cacheErr := l.clearUserAndSubscribeCaches(allMemberIDs); cacheErr != nil {
		l.Errorw("clear user related cache failed",
			logger.Field("user_id", currentUser.Id),
			logger.Field("affected_user_ids", allMemberIDs),
			logger.Field("error", cacheErr.Error()),
		)
	}

	return &types.DeleteAccountResponse{
		Success: true,
		Message: "注销成功",
		UserId:  currentUser.Id,
		Code:    200,
	}, nil
}

func (l *DeleteAccountLogic) collectAffectedFamilyUserIDs(tx *gorm.DB, userID int64) ([]int64, error) {
	affected := []int64{userID}

	var relation struct {
		FamilyId int64 `gorm:"column:family_id"`
	}
	err := tx.Model(&user.UserFamilyMember{}).
		Select("user_family_member.family_id").
		Joins("JOIN user_family ON user_family.id = user_family_member.family_id AND user_family.deleted_at IS NULL AND user_family.status = ?", user.FamilyStatusActive).
		Where("user_family_member.user_id = ? AND user_family_member.status = ? AND user_family_member.deleted_at IS NULL", userID, user.FamilyMemberActive).
		First(&relation).Error
	if err != nil {
		if errors.Is(err, gorm.ErrRecordNotFound) {
			return affected, nil
		}
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query family relation failed")
	}

	var memberIDs []int64
	if err = tx.Model(&user.UserFamilyMember{}).
		Where("family_id = ? AND status = ? AND deleted_at IS NULL", relation.FamilyId, user.FamilyMemberActive).
		Pluck("user_id", &memberIDs).Error; err != nil {
		return nil, errors.Wrapf(xerr.NewErrCode(xerr.DatabaseQueryError), "query family members failed")
	}

	affected = append(affected, memberIDs...)
	idSet := make(map[int64]struct{}, len(affected))
	unique := make([]int64, 0, len(affected))
	for _, id := range affected {
		if id <= 0 {
			continue
		}
		if _, exists := idSet[id]; exists {
			continue
		}
		idSet[id] = struct{}{}
		unique = append(unique, id)
	}

	if len(unique) == 0 {
		return []int64{userID}, nil
	}
	return unique, nil
}

func (l *DeleteAccountLogic) clearUserAndSubscribeCaches(userIDs []int64) error {
	if len(userIDs) == 0 {
		return nil
	}

	idSet := make(map[int64]struct{}, len(userIDs))
	uniqueIDs := make([]int64, 0, len(userIDs))
	for _, userID := range userIDs {
		if userID <= 0 {
			continue
		}
		if _, exists := idSet[userID]; exists {
			continue
		}
		idSet[userID] = struct{}{}
		uniqueIDs = append(uniqueIDs, userID)
	}
	if len(uniqueIDs) == 0 {
		return nil
	}

	userModels := make([]*user.User, 0, len(uniqueIDs))
	subscribeModels := make([]*user.Subscribe, 0, len(uniqueIDs))
	for _, userID := range uniqueIDs {
		u, findErr := l.svcCtx.UserModel.FindOne(l.ctx, userID)
		switch {
		case findErr == nil:
			userModels = append(userModels, u)
		case errors.Is(findErr, gorm.ErrRecordNotFound):
			// no-op
		default:
			l.Errorw("find user for cache clearing failed",
				logger.Field("user_id", userID),
				logger.Field("error", findErr.Error()),
			)
		}

		subscribeModels = append(subscribeModels, &user.Subscribe{UserId: userID})
		subscribes, queryErr := l.svcCtx.UserModel.QueryUserSubscribe(l.ctx, userID)
		if queryErr != nil {
			l.Errorw("query user subscribes for cache clearing failed",
				logger.Field("user_id", userID),
				logger.Field("error", queryErr.Error()),
			)
			continue
		}
		for _, subscribe := range subscribes {
			subscribeModels = append(subscribeModels, &user.Subscribe{
				Id:          subscribe.Id,
				UserId:      subscribe.UserId,
				SubscribeId: subscribe.SubscribeId,
				Token:       subscribe.Token,
			})
		}
	}

	if len(userModels) > 0 {
		if err := l.svcCtx.UserModel.ClearUserCache(l.ctx, userModels...); err != nil {
			return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "clear user cache failed")
		}
	}
	if len(subscribeModels) > 0 {
		if err := l.svcCtx.UserModel.ClearSubscribeCache(l.ctx, subscribeModels...); err != nil {
			return errors.Wrapf(xerr.NewErrCode(xerr.ERROR), "clear subscribe cache failed")
		}
	}

	return nil
}

// clearAllSessions 清理指定用户的所有会话
func (l *DeleteAccountLogic) clearAllSessions(userId int64) {
	sessionsKey := fmt.Sprintf("%s%v", config.UserSessionsKeyPrefix, userId)
	sessionSet := make(map[string]struct{})

	sessions, err := l.svcCtx.Redis.ZRange(l.ctx, sessionsKey, 0, -1).Result()
	if err != nil {
		l.Errorw("获取用户会话索引失败", logger.Field("user_id", userId), logger.Field("error", err.Error()))
	} else {
		for _, sessionID := range sessions {
			if sessionID != "" {
				sessionSet[sessionID] = struct{}{}
			}
		}
	}

	userIDText := strconv.FormatInt(userId, 10)
	pattern := fmt.Sprintf("%s:*", config.SessionIdKey)
	var cursor uint64
	for {
		keys, nextCursor, scanErr := l.svcCtx.Redis.Scan(l.ctx, cursor, pattern, 200).Result()
		if scanErr != nil {
			l.Errorw("扫描会话键失败", logger.Field("user_id", userId), logger.Field("error", scanErr.Error()))
			break
		}

		for _, sessionKey := range keys {
			value, getErr := l.svcCtx.Redis.Get(l.ctx, sessionKey).Result()
			if getErr != nil || value != userIDText {
				continue
			}
			sessionID := strings.TrimPrefix(sessionKey, config.SessionIdKey+":")
			if sessionID == "" || strings.HasPrefix(sessionID, "detail:") {
				continue
			}
			sessionSet[sessionID] = struct{}{}
		}

		cursor = nextCursor
		if cursor == 0 {
			break
		}
	}

	deviceKeySet := make(map[string]struct{})
	devicePattern := fmt.Sprintf("%s:*", config.DeviceCacheKeyKey)
	cursor = 0
	for {
		keys, nextCursor, scanErr := l.svcCtx.Redis.Scan(l.ctx, cursor, devicePattern, 200).Result()
		if scanErr != nil {
			l.Errorw("扫描设备会话映射失败", logger.Field("user_id", userId), logger.Field("error", scanErr.Error()))
			break
		}
		for _, deviceKey := range keys {
			sessionID, getErr := l.svcCtx.Redis.Get(l.ctx, deviceKey).Result()
			if getErr != nil {
				continue
			}
			if _, exists := sessionSet[sessionID]; exists {
				deviceKeySet[deviceKey] = struct{}{}
			}
		}
		cursor = nextCursor
		if cursor == 0 {
			break
		}
	}

	pipe := l.svcCtx.Redis.TxPipeline()
	for sessionID := range sessionSet {
		sessionKey := fmt.Sprintf("%v:%v", config.SessionIdKey, sessionID)
		pipe.Del(l.ctx, sessionKey)
		pipe.Del(l.ctx, fmt.Sprintf("%s:detail:%s", config.SessionIdKey, sessionID))
		pipe.ZRem(l.ctx, sessionsKey, sessionID)
	}
	pipe.Del(l.ctx, sessionsKey)

	for deviceKey := range deviceKeySet {
		pipe.Del(l.ctx, deviceKey)
	}

	if _, err = pipe.Exec(l.ctx); err != nil {
		l.Errorw("清理会话缓存失败", logger.Field("user_id", userId), logger.Field("error", err.Error()))
	}

	l.Infow("[SessionMonitor] 注销账号-清除所有Session",
		logger.Field("user_id", userId),
		logger.Field("count", len(sessionSet)),
	)
}

// findActiveFamilyRelation 查找用户的活跃家庭成员记录
func (l *DeleteAccountLogic) findActiveFamilyRelation(userID int64) (*user.UserFamilyMember, error) {
	var relation user.UserFamilyMember
	err := l.svcCtx.DB.WithContext(l.ctx).
		Model(&user.UserFamilyMember{}).
		Where("user_id = ? AND status = ?", userID, user.FamilyMemberActive).
		First(&relation).Error
	if err != nil {
		return nil, err
	}
	return &relation, nil
}
