package iot_card

import (
	"context"
	stderrors "errors"
	"strconv"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/gateway"
	"github.com/break/junhong_cmp_fiber/internal/infrastructure/integrationlog"
	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	assetAuditSvc "github.com/break/junhong_cmp_fiber/internal/service/asset_audit"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	pkgerrors "github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"go.uber.org/zap"
)

type speedTierIntegrationLog interface {
	Start(ctx context.Context, input integrationlog.Attempt) (*model.IntegrationLog, error)
	Complete(ctx context.Context, integrationID string, completion integrationlog.Completion) (*model.IntegrationLog, error)
}

// SetSpeedTier 为有权限的 IoT 卡设置或恢复固定限速档位。
func (s *Service) SetSpeedTier(ctx context.Context, iccid string, code *int) (*dto.SetIotCardSpeedTierResponse, error) {
	if !canManageCardSpeedTier(ctx) {
		return nil, pkgerrors.New(pkgerrors.CodeForbidden, "仅平台和代理后台账号可设置卡限速档位")
	}
	if code == nil || !constants.IsGatewaySpeedTier(*code) {
		return nil, pkgerrors.New(pkgerrors.CodeInvalidParam, "固定限速档位不合法")
	}
	if s == nil || s.iotCardStore == nil || s.gatewayClient == nil || s.speedTierIntegration == nil {
		return nil, pkgerrors.New(pkgerrors.CodeServiceUnavailable, "卡限速服务未完整配置")
	}

	card, err := s.iotCardStore.GetByICCID(ctx, iccid)
	if err != nil || card == nil || card.ICCID == "" {
		return nil, pkgerrors.New(pkgerrors.CodeForbidden, "无权限操作该资源或资源不存在")
	}

	tierName := constants.GetGatewaySpeedTierName(*code)
	resourceID := strconv.FormatUint(uint64(card.ID), 10)
	requestID := middleware.GetRequestIDFromContext(ctx)
	attempt, err := s.speedTierIntegration.Start(ctx, integrationlog.Attempt{
		Provider:      constants.IntegrationProviderGateway,
		Direction:     constants.IntegrationDirectionOutbound,
		Operation:     constants.IntegrationOperationGatewaySpeedTier,
		ExternalID:    &card.ICCID,
		ResourceType:  constants.AssetTypeIotCard,
		ResourceID:    &resourceID,
		ResourceKey:   &card.ICCID,
		RequestID:     requestID,
		CorrelationID: requestID,
		RequestSummary: map[string]any{
			"iot_card_id": card.ID,
			"iccid":       card.ICCID,
			"tier_code":   *code,
			"tier_name":   tierName,
			"operator_id": middleware.GetUserIDFromContext(ctx),
		},
	})
	if err != nil {
		s.logSpeedTierAudit(ctx, card, *code, "", constants.AssetAuditResultFailed, err)
		return nil, err
	}

	startedAt := time.Now()
	gatewayErr := s.gatewayClient.SetCardSpeedTier(ctx, &gateway.CardSpeedTierReq{
		CardNo: card.ICCID,
		Code:   strconv.Itoa(*code),
	})
	completion := speedTierCompletion(gatewayErr, time.Since(startedAt))
	if _, completeErr := s.speedTierIntegration.Complete(ctx, attempt.IntegrationID, completion); completeErr != nil {
		if s.logger != nil {
			s.logger.Error("终结卡限速 Integration Log 失败",
				zap.Uint("iot_card_id", card.ID),
				zap.String("integration_id", attempt.IntegrationID),
				zap.Error(completeErr),
			)
		}
		s.logSpeedTierAudit(ctx, card, *code, attempt.IntegrationID, constants.AssetAuditResultFailed, completeErr)
		return nil, pkgerrors.Wrap(pkgerrors.CodeDatabaseError, completeErr, "终结卡限速外部交互记录失败")
	}
	if gatewayErr != nil {
		s.logSpeedTierAudit(ctx, card, *code, attempt.IntegrationID, constants.AssetAuditResultFailed, gatewayErr)
		if isGatewayTimeout(gatewayErr) {
			return nil, pkgerrors.New(pkgerrors.CodeGatewayTimeout, "Gateway 卡限速请求结果未知，请核对实际档位后再操作")
		}
		return nil, gatewayErr
	}

	s.logSpeedTierAudit(ctx, card, *code, attempt.IntegrationID, constants.AssetAuditResultSuccess, nil)
	return &dto.SetIotCardSpeedTierResponse{
		IotCardID: card.ID, ICCID: card.ICCID, Code: *code,
		SpeedTierName: tierName, IntegrationID: attempt.IntegrationID,
	}, nil
}

func canManageCardSpeedTier(ctx context.Context) bool {
	switch middleware.GetUserTypeFromContext(ctx) {
	case constants.UserTypeSuperAdmin, constants.UserTypePlatform, constants.UserTypeAgent:
		return middleware.GetUserIDFromContext(ctx) > 0
	default:
		return false
	}
}

func speedTierCompletion(err error, duration time.Duration) integrationlog.Completion {
	completion := integrationlog.Completion{
		Result:       constants.IntegrationResultSuccess,
		DurationMS:   duration.Milliseconds(),
		StateChanged: true,
		ResponseSummary: map[string]any{
			"result": "success",
		},
	}
	if err == nil {
		return completion
	}
	completion.Result = constants.IntegrationResultFailed
	completion.StateChanged = false
	completion.ProviderMessage = err.Error()
	completion.ResponseSummary = map[string]any{"result": "failed"}
	if isGatewayTimeout(err) {
		completion.Result = constants.IntegrationResultUnknown
		completion.ResponseSummary = map[string]any{"result": "unknown"}
		completion.RecoveryStrategy = constants.GatewaySpeedTierUnknownRecoveryStrategy
	}
	return completion
}

func isGatewayTimeout(err error) bool {
	var appErr *pkgerrors.AppError
	return stderrors.As(err, &appErr) && appErr != nil && appErr.Code == pkgerrors.CodeGatewayTimeout
}

func (s *Service) logSpeedTierAudit(ctx context.Context, card *model.IotCard, code int, integrationID, result string, err error) {
	errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(err)
	s.logCardAudit(ctx, assetAuditSvc.BuildLogParams{
		AssetType:       constants.AssetTypeIotCard,
		AssetID:         card.ID,
		AssetIdentifier: card.ICCID,
		OperationType:   constants.AssetAuditOpCardSpeedTier,
		OperationDesc:   "设置 IoT 卡固定限速档位",
		BeforeData:      map[string]any{"card": cardSnapshot(card)},
		AfterData: map[string]any{
			"tier_code":      code,
			"tier_name":      constants.GetGatewaySpeedTierName(code),
			"integration_id": integrationID,
		},
		ResultStatus: result,
		ErrorCode:    errorCode,
		ErrorMsg:     errorMsg,
	})
}

var _ speedTierIntegrationLog = (*integrationlog.Repository)(nil)
