package task

import (
	"context"
	"time"

	"github.com/bytedance/sonic"
	"github.com/hibiken/asynq"
	"go.uber.org/zap"

	"github.com/break/junhong_cmp_fiber/internal/gateway"
	iot_card_svc "github.com/break/junhong_cmp_fiber/internal/service/iot_card"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
)

// PollingRealnameHandler 实名检查任务处理器
// 职责：调 Gateway 查实名状态 → 写 DB → 触发首次实名激活任务
// 不做：停复机决策（实名状态 0→1 时通过 EvaluateAndAct 触发 not_realname 复机）
type PollingRealnameHandler struct {
	base                  *PollingBase
	gateway               *gateway.Client
	iotCardStore          *postgres.IotCardStore
	asynqClient           *asynq.Client
	stopResumeSvc         iot_card_svc.StopResumeServiceInterface
	deviceSimBindingStore *postgres.DeviceSimBindingStore
}

// NewPollingRealnameHandler 创建实名检查任务处理器
func NewPollingRealnameHandler(
	base *PollingBase,
	gw *gateway.Client,
	iotCardStore *postgres.IotCardStore,
	asynqClient *asynq.Client,
	stopResumeSvc iot_card_svc.StopResumeServiceInterface,
	deviceSimBindingStore *postgres.DeviceSimBindingStore,
) *PollingRealnameHandler {
	return &PollingRealnameHandler{
		base:                  base,
		gateway:               gw,
		iotCardStore:          iotCardStore,
		asynqClient:           asynqClient,
		stopResumeSvc:         stopResumeSvc,
		deviceSimBindingStore: deviceSimBindingStore,
	}
}

// Handle 处理实名检查任务
func (h *PollingRealnameHandler) Handle(ctx context.Context, t *asynq.Task) error {
	startTime := time.Now()

	cardID, ok := parseTaskPayload(t.Payload(), h.base.logger)
	if !ok {
		return nil
	}

	if !h.base.acquireConcurrency(ctx, constants.TaskTypePollingRealname) {
		h.base.logger.Debug("并发已满，重新入队", zap.Uint("card_id", cardID))
		return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingRealname)
	}
	defer h.base.releaseConcurrency(ctx, constants.TaskTypePollingRealname)

	card, err := h.base.getCardWithCache(ctx, cardID)
	if err != nil {
		if isNotFound(err) {
			return nil
		}
		h.base.logger.Error("获取卡信息失败", zap.Uint("card_id", cardID), zap.Error(err))
		h.base.updateStats(ctx, constants.TaskTypePollingRealname, false, time.Since(startTime))
		return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingRealname)
	}

	if card.CardCategory == constants.CardCategoryIndustry {
		return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingRealname)
	}

	var newStatus int
	var realStatusBool bool
	if h.gateway != nil {
		result, gwErr := h.gateway.QueryRealnameStatus(ctx, &gateway.CardStatusReq{CardNo: card.ICCID})
		if gwErr != nil {
			h.base.logger.Warn("查询实名状态失败",
				zap.Uint("card_id", cardID), zap.String("iccid", card.ICCID), zap.Error(gwErr))
			h.base.updateStats(ctx, constants.TaskTypePollingRealname, false, time.Since(startTime))
			return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingRealname)
		}
		// 上游接口故障时 Gateway 可能返回 data=null，
		// sonic 将其解析为零值结构体（ICCID="" RealStatus=false），
		// 需通过 ICCID 是否回填来判断响应是否有效。
		if result.ICCID == "" {
			h.base.logger.Warn("实名查询响应异常：ICCID 为空，疑似上游接口故障，跳过本次同步",
				zap.Uint("card_id", cardID),
				zap.String("iccid", card.ICCID))
			h.base.updateStats(ctx, constants.TaskTypePollingRealname, false, time.Since(startTime))
			return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingRealname)
		}

		realStatusBool = result.RealStatus
		if result.RealStatus {
			newStatus = constants.RealNameStatusVerified
		} else {
			newStatus = constants.RealNameStatusNotVerified
		}

		if h.base.verboseLog {
			h.base.logger.Info("实名状态轮询详情",
				zap.Uint("card_id", cardID),
				zap.String("iccid", card.ICCID),
				zap.Bool("real_status", realStatusBool),
				zap.Int("new_status", newStatus),
				zap.Bool("changed", newStatus != card.RealNameStatus))
		}
	} else {
		newStatus = card.RealNameStatus
	}

	statusChanged := newStatus != card.RealNameStatus
	isFirstRealname := statusChanged &&
		card.RealNameStatus != constants.RealNameStatusVerified &&
		newStatus == constants.RealNameStatusVerified

	now := time.Now()
	fields := map[string]any{"last_real_name_check_at": now}
	if h.gateway != nil {
		fields["last_sync_time"] = now
	}
	if statusChanged {
		fields["real_name_status"] = newStatus
	}
	if isFirstRealname {
		fields["first_realname_at"] = now
	}
	if err := h.iotCardStore.UpdateFields(ctx, cardID, fields); err != nil {
		h.base.logger.Error("更新卡实名信息失败", zap.Uint("card_id", cardID), zap.Error(err))
		h.base.invalidateCardCache(ctx, cardID)
		h.base.updateStats(ctx, constants.TaskTypePollingRealname, false, time.Since(startTime))
		return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingRealname)
	}

	if statusChanged {
		h.base.updateCardCache(ctx, cardID, map[string]any{"real_name_status": newStatus})
		h.base.logger.Info("实名状态已变化",
			zap.Uint("card_id", cardID),
			zap.Int("old_status", card.RealNameStatus),
			zap.Int("new_status", newStatus))

		if isFirstRealname {
			// 0→1 时清除逆转计数器
			h.base.redis.Del(ctx, constants.RedisPollingRealnameReversalCountKey(cardID))
			// 0→1：首次实名，触发套餐激活并立即复机评估（不等待下一个 carddata/package 周期）
			h.triggerFirstRealnameActivation(ctx, cardID)
			h.triggerDeviceRealnameActivation(ctx, cardID)
			if h.stopResumeSvc != nil {
				freshCard, loadErr := h.iotCardStore.GetByID(ctx, cardID)
				if loadErr == nil {
					if evalErr := h.stopResumeSvc.EvaluateAndAct(ctx, freshCard); evalErr != nil {
						h.base.logger.Warn("实名完成后触发复机评估失败",
							zap.Uint("card_id", cardID), zap.Error(evalErr))
					}
				}
			}
		} else if newStatus == constants.RealNameStatusNotVerified {
			reversalKey := constants.RedisPollingRealnameReversalCountKey(cardID)
			count, incrErr := h.base.redis.Incr(ctx, reversalKey).Result()
			if incrErr == nil {
				h.base.redis.Expire(ctx, reversalKey, 10*time.Minute)
			}
			h.base.logger.Warn("检测到实名逆转",
				zap.Uint("card_id", cardID),
				zap.Int64("reversal_count", count),
				zap.Int("threshold", constants.PollingRealnameReversalThreshold))
			if count >= int64(constants.PollingRealnameReversalThreshold) {
				h.base.redis.Del(ctx, reversalKey)
				h.base.logger.Warn("实名逆转达到阈值，触发停机评估",
					zap.Uint("card_id", cardID))
				if h.stopResumeSvc != nil {
					freshCard, loadErr := h.iotCardStore.GetByID(ctx, cardID)
					if loadErr == nil {
						if evalErr := h.stopResumeSvc.EvaluateAndAct(ctx, freshCard); evalErr != nil {
							h.base.logger.Warn("实名逆转后触发停机评估失败",
								zap.Uint("card_id", cardID), zap.Error(evalErr))
						}
					}
				}
			}
		}
	}

	h.base.updateStats(ctx, constants.TaskTypePollingRealname, true, time.Since(startTime))
	return h.base.requeueCard(ctx, cardID, constants.TaskTypePollingRealname)
}

// triggerFirstRealnameActivation 首次实名后触发套餐激活任务
func (h *PollingRealnameHandler) triggerFirstRealnameActivation(ctx context.Context, cardID uint) {
	if h.asynqClient == nil {
		return
	}
	payload := map[string]any{
		"carrier_type":    "iot_card",
		"carrier_id":      cardID,
		"activation_type": "realname",
		"timestamp":       time.Now().Unix(),
	}
	payloadBytes, err := sonic.Marshal(payload)
	if err != nil {
		h.base.logger.Warn("序列化首次实名激活任务载荷失败", zap.Uint("card_id", cardID), zap.Error(err))
		return
	}
	task := asynq.NewTask(constants.TaskTypePackageFirstActivation, payloadBytes,
		asynq.MaxRetry(3),
		asynq.Timeout(60*time.Second),
		asynq.Queue(constants.QueueForTaskType(constants.TaskTypePackageFirstActivation)),
	)
	if _, err := h.asynqClient.EnqueueContext(ctx, task); err != nil {
		h.base.logger.Warn("提交首次实名激活任务失败", zap.Uint("card_id", cardID), zap.Error(err))
	}
}

// triggerDeviceRealnameActivation 卡首次实名后，触发其所属设备的设备级套餐激活任务
// 若卡不属于任何设备（独立卡），静默跳过
func (h *PollingRealnameHandler) triggerDeviceRealnameActivation(ctx context.Context, cardID uint) {
	if h.asynqClient == nil || h.deviceSimBindingStore == nil {
		return
	}
	binding, err := h.deviceSimBindingStore.GetActiveBindingByCardID(ctx, cardID)
	if err != nil {
		if isNotFound(err) {
			return
		}
		h.base.logger.Warn("查询卡绑定设备失败，跳过设备级套餐激活",
			zap.Uint("card_id", cardID), zap.Error(err))
		return
	}
	deviceID := binding.DeviceID
	payload := map[string]any{
		"carrier_type":    "device",
		"carrier_id":      deviceID,
		"activation_type": "realname",
		"timestamp":       time.Now().Unix(),
	}
	payloadBytes, err := sonic.Marshal(payload)
	if err != nil {
		h.base.logger.Warn("序列化设备实名激活任务载荷失败",
			zap.Uint("card_id", cardID), zap.Uint("device_id", deviceID), zap.Error(err))
		return
	}
	task := asynq.NewTask(constants.TaskTypePackageFirstActivation, payloadBytes,
		asynq.MaxRetry(3),
		asynq.Timeout(60*time.Second),
		asynq.Queue(constants.QueueForTaskType(constants.TaskTypePackageFirstActivation)),
	)
	if _, err := h.asynqClient.EnqueueContext(ctx, task); err != nil {
		h.base.logger.Warn("提交设备实名激活任务失败",
			zap.Uint("card_id", cardID), zap.Uint("device_id", deviceID), zap.Error(err))
	}
}
