package callback

import (
	"context"
	"strings"
	"time"

	"github.com/gofiber/fiber/v2"
	"go.uber.org/zap"

	cardapp "github.com/break/junhong_cmp_fiber/internal/application/cardobservation"
	carddomain "github.com/break/junhong_cmp_fiber/internal/domain/cardobservation"
	"github.com/break/junhong_cmp_fiber/internal/infrastructure/carriercallback"
	"github.com/break/junhong_cmp_fiber/internal/infrastructure/integrationlog"
	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	apperrors "github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
)

// CUCCRealnameHandler 处理中国联通实名成功回调。
type CUCCRealnameHandler struct {
	translator  *carriercallback.CUCCRealnameTranslator
	resolver    *carriercallback.CUCCCardResolver
	integration *integrationlog.Repository
	observation *cardapp.Service
	series      ResourceSeriesCompleter
	config      SystemConfigReader
	logger      *zap.Logger
}

// NewCUCCRealnameHandler 创建中国联通实名成功回调 Handler。
func NewCUCCRealnameHandler(translator *carriercallback.CUCCRealnameTranslator, resolver *carriercallback.CUCCCardResolver, integration *integrationlog.Repository, observation *cardapp.Service, series ResourceSeriesCompleter, config SystemConfigReader, logger *zap.Logger) *CUCCRealnameHandler {
	return &CUCCRealnameHandler{translator: translator, resolver: resolver, integration: integration, observation: observation, series: series, config: config, logger: logger}
}

// Realname 接收中国联通实名成功结果并返回固定成功应答。
// POST /api/callback/carriers/cucc/realname
func (h *CUCCRealnameHandler) Realname(c *fiber.Ctx) error {
	startedAt := time.Now()
	enabled, err := carrierCallbackEnabled(c.UserContext(), h.config, constants.SystemConfigCarrierCallbackCUCCRealnameEnabled)
	if err != nil {
		if h.logger != nil {
			h.logger.Error("读取联通实名回调启停配置失败，已按关闭处理并返回成功", zap.Error(err))
		}
		return sendCUCCSuccess(c, startedAt)
	}
	if !enabled {
		if err := recordDisabledCarrierCallback(c.UserContext(), h.integration, constants.IntegrationProviderCUCC, constants.IntegrationOperationCUCCRealnameCallback, "cucc-realname", c.Body(), c.Get("Content-Type")); err != nil && h.logger != nil {
			h.logger.Error("联通实名回调已关闭，但留痕失败", zap.Error(err))
		}
		return sendCUCCSuccess(c, startedAt)
	}
	if err := h.process(c.UserContext(), c.Body(), c.Get("Content-Type")); err != nil && h.logger != nil {
		h.logger.Error("处理联通实名回调失败，已按运营商约定返回成功", zap.Error(err))
	}
	return sendCUCCSuccess(c, startedAt)
}

func (h *CUCCRealnameHandler) process(ctx context.Context, body []byte, contentType string) error {
	if h == nil || h.translator == nil || h.resolver == nil || h.integration == nil || h.observation == nil {
		return apperrors.New(apperrors.CodeInternalError, "联通实名回调能力未完整配置")
	}
	translated, translateErr := h.translator.Translate(body)
	key := cuccRealnameIdempotencyKey(body, translated, translateErr == nil)
	integrationID := "cucc-realname:" + shortHash(key)
	requestID := middleware.GetRequestIDFromContext(ctx)
	log, created, err := h.integration.RecordInbound(ctx, integrationlog.InboundAttempt{
		IntegrationID: integrationID, IdempotencyKey: key,
		Provider: constants.IntegrationProviderCUCC, Operation: constants.IntegrationOperationCUCCRealnameCallback,
		ResourceType: constants.CardObservationResourceTypeCard, ResourceKey: optionalHashedResourceKey(translated.ICCID),
		RawPayload: body, ContentType: contentType, RequestID: requestID, CorrelationID: requestID,
	})
	if err != nil {
		if isAppConflict(err) {
			return h.recordConflict(ctx, body, contentType, key, translated, requestID)
		}
		return err
	}
	if !created {
		claimed, claimErr := h.claimPending(ctx, log)
		if claimErr != nil || !claimed {
			return claimErr
		}
	}
	if translateErr != nil {
		return h.complete(ctx, log.IntegrationID, constants.IntegrationResultInvalidPayload, false, "报文、嵌套 data 或字段校验失败")
	}
	cards, err := h.resolver.Resolve(ctx, translated.ICCID)
	if err != nil {
		return h.fail(ctx, log.IntegrationID, err)
	}
	if len(cards) == 0 {
		return h.complete(ctx, log.IntegrationID, constants.IntegrationResultNotFound, false, "精确列未找到卡")
	}
	if len(cards) > 1 {
		return h.complete(ctx, log.IntegrationID, constants.IntegrationResultConflict, false, "精确列匹配多张卡")
	}
	card := cards[0]
	decision, err := h.observation.ApplyCardObservation(ctx, carddomain.RealnameObservation{
		CardID: card.ID, Verified: true,
		Metadata: carddomain.ObservationMetadata{
			ObservationID: log.IntegrationID, Source: constants.CardObservationSourceCarrierCallback,
			Scene: constants.CardObservationSceneCarrierCallback, ObservedAt: time.Now().UTC(),
			RequestID: optionalStringValue(requestID), CorrelationID: optionalStringValue(requestID),
			UpstreamSummary: "联通实名成功，变更时间已留痕",
		},
	})
	if err != nil {
		return h.fail(ctx, log.IntegrationID, err)
	}
	if h.series != nil {
		if err := h.series.CompleteResourceSeries(ctx, constants.CardObservationResourceTypeCard, uintString(card.ID), constants.CardObservationSyncTypeRealname); err != nil && h.logger != nil {
			h.logger.Warn("联通实名事实已应用但提前完成观测序列失败", zap.Uint("card_id", card.ID), zap.Error(err))
		}
	}
	return h.complete(ctx, log.IntegrationID, constants.IntegrationResultSuccess, decision.StatusChanged, "实名事实已幂等应用")
}

func (h *CUCCRealnameHandler) recordConflict(ctx context.Context, body []byte, contentType, baseKey string, translated carriercallback.CUCCRealnameTranslation, requestID *string) error {
	key := baseKey + ":conflict:" + shortHashBytes(body)
	log, created, err := h.integration.RecordInbound(ctx, integrationlog.InboundAttempt{
		IntegrationID: "cucc-realname-conflict:" + shortHash(key), IdempotencyKey: key,
		Provider: constants.IntegrationProviderCUCC, Operation: constants.IntegrationOperationCUCCRealnameCallback,
		ResourceType: constants.CardObservationResourceTypeCard, ResourceKey: optionalHashedResourceKey(translated.ICCID),
		RawPayload: body, ContentType: contentType, RequestID: requestID, CorrelationID: requestID,
	})
	if err != nil {
		return err
	}
	if !created {
		claimed, claimErr := h.claimPending(ctx, log)
		if claimErr != nil || !claimed {
			return claimErr
		}
	}
	return h.complete(ctx, log.IntegrationID, constants.IntegrationResultConflict, false, "同一实名语义对应不同载荷")
}

func (h *CUCCRealnameHandler) claimPending(ctx context.Context, log *model.IntegrationLog) (bool, error) {
	if log == nil || log.Result != constants.IntegrationResultPending {
		return false, nil
	}
	return h.integration.ClaimExpiredInboundPending(ctx, log.IntegrationID, constants.IntegrationInboundProcessingLease)
}

func (h *CUCCRealnameHandler) complete(ctx context.Context, integrationID, result string, changed bool, reason string) error {
	_, err := h.integration.Complete(ctx, integrationID, integrationlog.Completion{
		Result: result, HTTPStatus: fiber.StatusOK, StateChanged: changed,
		ResponseSummary: map[string]any{"reason": reason},
	})
	return err
}

func (h *CUCCRealnameHandler) fail(ctx context.Context, integrationID string, original error) error {
	if err := h.complete(ctx, integrationID, constants.IntegrationResultFailed, false, "内部处理失败"); err != nil && h.logger != nil {
		h.logger.Error("联通实名回调失败终态写入失败", zap.String("integration_id", integrationID), zap.Error(err))
	}
	return original
}

func cuccRealnameIdempotencyKey(body []byte, translated carriercallback.CUCCRealnameTranslation, valid bool) string {
	if valid {
		semantic := strings.TrimSpace(translated.ICCID) + "\x00" + strings.TrimSpace(translated.DateChanged)
		return "cucc-realname-semantic:" + shortHash(semantic)
	}
	return "cucc-realname-body:" + shortHashBytes(body)
}
