package admin

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

	cardObservationApp "github.com/break/junhong_cmp_fiber/internal/application/cardobservation"
	"github.com/gofiber/fiber/v2"

	dto "github.com/break/junhong_cmp_fiber/internal/model/dto"
	packageExpiryQuery "github.com/break/junhong_cmp_fiber/internal/query/packageexpiry"
	assetService "github.com/break/junhong_cmp_fiber/internal/service/asset"
	assetAuditSvc "github.com/break/junhong_cmp_fiber/internal/service/asset_audit"
	deviceService "github.com/break/junhong_cmp_fiber/internal/service/device"
	iotCardService "github.com/break/junhong_cmp_fiber/internal/service/iot_card"
	pollingSvc "github.com/break/junhong_cmp_fiber/internal/service/polling"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/pkg/logger"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"github.com/break/junhong_cmp_fiber/pkg/response"
	"go.uber.org/zap"
)

// AssetHandler 资产管理处理器
// 提供统一的资产解析、实时状态、套餐查询、停复机、停用、轮询管控等接口
type AssetHandler struct {
	assetService          *assetService.Service
	assetAuditService     *assetAuditSvc.Service
	deviceService         *deviceService.Service
	iotCardService        *iotCardService.Service
	iotCardStopResume     *iotCardService.StopResumeService
	assetPolling          *pollingSvc.AssetPollingService
	assetLifecycleService AssetLifecycleService
	exchangeTraceQuery    AssetExchangeTraceResolver
	observationSeries     cardObservationApp.BestEffortSeriesDispatcher
	packageExpiryQuery    *packageExpiryQuery.Query
}

// SetObservationSeriesDispatcher 注入后台实时状态的观测序列端口。
func (h *AssetHandler) SetObservationSeriesDispatcher(dispatcher cardObservationApp.BestEffortSeriesDispatcher) {
	h.observationSeries = dispatcher
}

// SetPackageExpiryQuery 注入临期资产分页查询。
func (h *AssetHandler) SetPackageExpiryQuery(query *packageExpiryQuery.Query) {
	h.packageExpiryQuery = query
}

// AssetExchangeTraceResolver 定义资产详情换货链路读取用例。
type AssetExchangeTraceResolver interface {
	Resolve(ctx context.Context, assetType string, assetID uint) (*dto.AssetExchangeTrace, error)
}

// NewAssetHandler 创建资产管理处理器
func NewAssetHandler(
	assetSvc *assetService.Service,
	assetAuditService *assetAuditSvc.Service,
	deviceSvc *deviceService.Service,
	iotCardSvc *iotCardService.Service,
	iotCardStopResume *iotCardService.StopResumeService,
	assetPolling *pollingSvc.AssetPollingService,
	exchangeTraceQuery AssetExchangeTraceResolver,
) *AssetHandler {
	return &AssetHandler{
		assetService:       assetSvc,
		assetAuditService:  assetAuditService,
		deviceService:      deviceSvc,
		iotCardService:     iotCardSvc,
		iotCardStopResume:  iotCardStopResume,
		assetPolling:       assetPolling,
		exchangeTraceQuery: exchangeTraceQuery,
	}
}

// SetLifecycleService 注入生命周期服务（用于 Deactivate 接口）
func (h *AssetHandler) SetLifecycleService(svc AssetLifecycleService) {
	h.assetLifecycleService = svc
}

// resolveByIdentifier 通过标识符解析资产，用于各处理器的公共逻辑
// 不传递 include_usage_summary，始终为 false，不影响其他 Handler 性能
func (h *AssetHandler) resolveByIdentifier(c *fiber.Ctx) (*dto.AssetResolveResponse, error) {
	identifier := c.Params("identifier")
	if identifier == "" {
		return nil, errors.New(errors.CodeInvalidParam, "标识符不能为空")
	}
	return h.assetService.Resolve(c.UserContext(), identifier, false)
}

// Resolve 通过任意标识符解析资产（设备或卡）
// GET /api/admin/assets/resolve/:identifier
func (h *AssetHandler) Resolve(c *fiber.Ctx) error {
	identifier := c.Params("identifier")
	if identifier == "" {
		return errors.New(errors.CodeInvalidParam, "标识符不能为空")
	}

	includeUsageSummary := c.QueryBool("include_usage_summary", false)
	result, err := h.assetService.Resolve(c.UserContext(), identifier, includeUsageSummary)
	if err != nil {
		return err
	}
	result.ExchangeTrace = &dto.AssetExchangeTrace{}
	if h.exchangeTraceQuery != nil {
		result.ExchangeTrace, err = h.exchangeTraceQuery.Resolve(c.UserContext(), result.AssetType, result.AssetID)
		if err != nil {
			return err
		}
	}

	return response.Success(c, result)
}

// ListExpiring 查询当前权限范围内的临期资产列表和数量汇总。
// GET /api/admin/expiring-assets
func (h *AssetHandler) ListExpiring(c *fiber.Ctx) error {
	var request dto.ExpiringAssetListRequest
	if err := c.QueryParser(&request); err != nil {
		logger.GetAppLogger().Warn("临期资产列表参数解析失败",
			zap.String("method", c.Method()), zap.String("path", c.Path()), zap.Error(err))
		return errors.New(errors.CodeInvalidParam)
	}
	if h.packageExpiryQuery == nil {
		return errors.New(errors.CodeInternalError, "套餐临期查询未配置")
	}
	result, err := h.packageExpiryQuery.List(c.UserContext(), request)
	if err != nil {
		return err
	}
	return response.Success(c, dto.ExpiringAssetListResponse{
		Items: result.Items, Total: result.Total, Page: result.Page, Size: result.Size, Summary: result.Summary,
	})
}

// RealtimeStatus 获取资产实时状态
// GET /api/admin/assets/:identifier/realtime-status
func (h *AssetHandler) RealtimeStatus(c *fiber.Ctx) error {
	asset, err := h.resolveByIdentifier(c)
	if err != nil {
		return err
	}

	result, err := h.assetService.GetRealtimeStatus(c.UserContext(), asset.AssetType, asset.AssetID)
	if err != nil {
		return err
	}
	h.dispatchRealtimeObservations(c.UserContext(), result)

	return response.Success(c, result)
}

func (h *AssetHandler) dispatchRealtimeObservations(ctx context.Context, result *dto.AssetRealtimeStatusResponse) {
	if h.observationSeries == nil || result == nil {
		return
	}
	cardIDs := make([]uint, 0, len(result.Cards)+1)
	if result.AssetType == "card" {
		cardIDs = append(cardIDs, result.AssetID)
	} else {
		for _, card := range result.Cards {
			cardIDs = append(cardIDs, card.CardID)
		}
	}
	requestID := ""
	if value := middleware.GetRequestIDFromContext(ctx); value != nil {
		requestID = *value
	}
	for _, cardID := range cardIDs {
		resourceID := strconv.FormatUint(uint64(cardID), 10)
		for _, syncType := range []string{constants.CardObservationSyncTypeRealname, constants.CardObservationSyncTypeTraffic, constants.CardObservationSyncTypeNetwork} {
			h.observationSeries.Dispatch(ctx, cardObservationApp.SeriesRequest{
				Scene:        constants.CardObservationSceneAdminAssetRead,
				ResourceType: constants.CardObservationResourceTypeCard, ResourceID: resourceID,
				SyncType: syncType, Source: constants.CardObservationSourceBusinessEvent,
				RequestID: requestID, CorrelationID: requestID,
			})
		}
	}
}

// Refresh 刷新资产状态（调网关同步）
// POST /api/admin/assets/:identifier/refresh
func (h *AssetHandler) Refresh(c *fiber.Ctx) error {
	userType := middleware.GetUserTypeFromContext(c.UserContext())
	if userType == constants.UserTypeEnterprise {
		return errors.New(errors.CodeForbidden, "企业账号无权主动刷新资产状态")
	}

	asset, err := h.resolveByIdentifier(c)
	if err != nil {
		return err
	}

	result, err := h.assetService.Refresh(c.UserContext(), asset.AssetType, asset.AssetID)
	if err != nil {
		return err
	}

	return response.Success(c, result)
}

// Packages 获取资产所有套餐列表（支持分页，默认 page=1 pageSize=50）
// GET /api/admin/assets/:identifier/packages
func (h *AssetHandler) Packages(c *fiber.Ctx) error {
	asset, err := h.resolveByIdentifier(c)
	if err != nil {
		return err
	}

	page := c.QueryInt("page", 1)
	pageSize := c.QueryInt("page_size", 50)
	statusRaw := c.Query("status")
	var status *int
	if statusRaw != "" {
		parsedStatus, parseErr := strconv.Atoi(statusRaw)
		if parseErr != nil || parsedStatus < constants.PackageUsageStatusPending || parsedStatus > constants.PackageUsageStatusInvalidated {
			return errors.New(errors.CodeInvalidParam)
		}
		status = &parsedStatus
	}

	callerAccountType := resolveCallerAccountType(c)
	result, err := h.assetService.GetPackages(c.UserContext(), asset.AssetType, asset.AssetID, page, pageSize, status, callerAccountType)
	if err != nil {
		return err
	}

	return response.Success(c, result)
}

// CurrentPackage 获取资产当前生效套餐
// GET /api/admin/assets/:identifier/current-package
func (h *AssetHandler) CurrentPackage(c *fiber.Ctx) error {
	asset, err := h.resolveByIdentifier(c)
	if err != nil {
		return err
	}

	callerAccountType := resolveCallerAccountType(c)
	result, err := h.assetService.GetCurrentPackage(c.UserContext(), asset.AssetType, asset.AssetID, callerAccountType)
	if err != nil {
		return err
	}

	return response.Success(c, result)
}

// UpdatePackageExpiresAt 修改资产套餐过期时间
// PATCH /api/admin/assets/:identifier/packages/:package_usage_id/expires-at
func (h *AssetHandler) UpdatePackageExpiresAt(c *fiber.Ctx) error {
	if err := ensureAssetPackageAdjuster(c); err != nil {
		return err
	}

	asset, packageUsageID, err := h.resolveAssetPackageUsagePath(c)
	if err != nil {
		return err
	}

	var req dto.UpdateAssetPackageExpiresAtRequest
	if err := c.BodyParser(&req); err != nil {
		return errors.New(errors.CodeInvalidParam)
	}
	expiresAt, err := parseAssetPackageTime(req.ExpiresAt)
	if err != nil {
		return errors.New(errors.CodeInvalidParam, "过期时间格式无效")
	}

	result, err := h.assetService.UpdatePackageExpiresAt(c.UserContext(), asset.AssetType, asset.AssetID, assetIdentifierForAudit(asset), packageUsageID, expiresAt)
	if err != nil {
		return err
	}

	return response.Success(c, result)
}

// UpdatePackageUsage 修改资产套餐已用量
// PATCH /api/admin/assets/:identifier/packages/:package_usage_id/used-data
func (h *AssetHandler) UpdatePackageUsage(c *fiber.Ctx) error {
	if err := ensureAssetPackageAdjuster(c); err != nil {
		return err
	}

	asset, packageUsageID, err := h.resolveAssetPackageUsagePath(c)
	if err != nil {
		return err
	}

	var req dto.UpdateAssetPackageUsageRequest
	if err := c.BodyParser(&req); err != nil {
		return errors.New(errors.CodeInvalidParam)
	}
	if req.DataUsageMB == nil || *req.DataUsageMB < 0 {
		return errors.New(errors.CodeInvalidParam)
	}

	result, err := h.assetService.UpdatePackageUsage(c.UserContext(), asset.AssetType, asset.AssetID, assetIdentifierForAudit(asset), packageUsageID, *req.DataUsageMB)
	if err != nil {
		return err
	}

	return response.Success(c, result)
}

// Stop 停机（设备批量停机，单卡停机）
// POST /api/admin/assets/:identifier/stop
func (h *AssetHandler) Stop(c *fiber.Ctx) error {
	asset, err := h.resolveByIdentifier(c)
	if err != nil {
		return err
	}

	switch asset.AssetType {
	case "device":
		result, devErr := h.deviceService.StopDevice(c.UserContext(), asset.AssetID)
		if devErr != nil {
			return devErr
		}
		return response.Success(c, result)
	case "card":
		if asset.ICCID == "" {
			return errors.New(errors.CodeInternalError, "卡 ICCID 为空，无法停机")
		}
		if cardErr := h.iotCardStopResume.ManualStopCard(c.UserContext(), asset.ICCID); cardErr != nil {
			return cardErr
		}
		return response.Success(c, nil)
	default:
		return errors.New(errors.CodeInvalidParam, "不支持的资产类型")
	}
}

// Start 复机（设备批量复机，单卡复机）
// POST /api/admin/assets/:identifier/start
func (h *AssetHandler) Start(c *fiber.Ctx) error {
	asset, err := h.resolveByIdentifier(c)
	if err != nil {
		return err
	}

	switch asset.AssetType {
	case "device":
		if devErr := h.deviceService.StartDevice(c.UserContext(), asset.AssetID); devErr != nil {
			return devErr
		}
		return response.Success(c, nil)
	case "card":
		if asset.ICCID == "" {
			return errors.New(errors.CodeInternalError, "卡 ICCID 为空，无法复机")
		}
		if cardErr := h.iotCardStopResume.ManualStartCard(c.UserContext(), asset.ICCID); cardErr != nil {
			return cardErr
		}
		return response.Success(c, nil)
	default:
		return errors.New(errors.CodeInvalidParam, "不支持的资产类型")
	}
}

// Deactivate 停用资产
// PATCH /api/admin/assets/:identifier/deactivate
func (h *AssetHandler) Deactivate(c *fiber.Ctx) error {
	if h.assetLifecycleService == nil {
		return errors.New(errors.CodeInternalError, "资产生命周期服务未配置")
	}

	asset, err := h.resolveByIdentifier(c)
	if err != nil {
		return err
	}

	switch asset.AssetType {
	case "device":
		if devErr := h.assetLifecycleService.DeactivateDevice(c.UserContext(), asset.AssetID); devErr != nil {
			return devErr
		}
	case "card":
		if cardErr := h.assetLifecycleService.DeactivateIotCard(c.UserContext(), asset.AssetID); cardErr != nil {
			return cardErr
		}
	default:
		return errors.New(errors.CodeInvalidParam, "不支持的资产类型")
	}

	return response.Success(c, nil)
}

// Orders 查询资产历史订单（支持跨代追溯）
// GET /api/admin/assets/:identifier/orders
func (h *AssetHandler) Orders(c *fiber.Ctx) error {
	identifier := c.Params("identifier")
	if identifier == "" {
		return errors.New(errors.CodeInvalidParam, "标识符不能为空")
	}

	page := c.QueryInt("page", 1)
	pageSize := c.QueryInt("page_size", 20)
	includePrevious := c.QueryBool("include_previous", false)

	result, err := h.assetService.GetOrders(c.UserContext(), identifier, page, pageSize, includePrevious)
	if err != nil {
		return err
	}

	return response.Success(c, result)
}

// OperationLogs 查询资产操作审计日志
// GET /api/admin/assets/:identifier/operation-logs
func (h *AssetHandler) OperationLogs(c *fiber.Ctx) error {
	if h.assetAuditService == nil {
		return errors.New(errors.CodeInternalError, "资产审计服务未配置")
	}

	asset, err := h.resolveByIdentifier(c)
	if err != nil {
		return err
	}

	page := c.QueryInt("page", 1)
	pageSize := c.QueryInt("page_size", 20)
	if page <= 0 || pageSize <= 0 || pageSize > 100 {
		return errors.New(errors.CodeInvalidParam, "分页参数无效")
	}

	operationType := strings.TrimSpace(c.Query("operation_type"))
	resultStatus := strings.TrimSpace(c.Query("result_status"))
	if resultStatus != "" &&
		resultStatus != constants.AssetAuditResultSuccess &&
		resultStatus != constants.AssetAuditResultFailed &&
		resultStatus != constants.AssetAuditResultDenied {
		return errors.New(errors.CodeInvalidParam, "无效的结果状态")
	}

	result, err := h.assetAuditService.ListByAsset(c.UserContext(), assetAuditSvc.ListByAssetParams{
		AssetType:     asset.AssetType,
		AssetID:       asset.AssetID,
		Page:          page,
		PageSize:      pageSize,
		OperationType: operationType,
		ResultStatus:  resultStatus,
	})
	if err != nil {
		return err
	}

	return response.Success(c, result)
}

// UpdatePollingStatus 更新资产轮询状态
// PATCH /api/admin/assets/:identifier/polling-status
func (h *AssetHandler) UpdatePollingStatus(c *fiber.Ctx) error {
	identifier := c.Params("identifier")
	if identifier == "" {
		return errors.New(errors.CodeInvalidParam)
	}

	var req dto.UpdateAssetPollingStatusRequest
	if err := c.BodyParser(&req); err != nil {
		return errors.New(errors.CodeInvalidParam)
	}

	asset, err := h.assetService.Resolve(c.UserContext(), identifier, false)
	if err != nil {
		return err
	}

	_ = middleware.GetUserIDFromContext(c.UserContext())

	if h.assetPolling == nil {
		return errors.New(errors.CodeInternalError, "轮询管控服务未配置")
	}

	pollingAssetType := asset.AssetType
	if pollingAssetType == "card" {
		pollingAssetType = "iot_card"
	}

	if err := h.assetPolling.UpdatePollingStatus(c.UserContext(), pollingAssetType, asset.AssetID, req.EnablePolling); err != nil {
		return err
	}

	return response.Success(c, &dto.UpdateAssetPollingStatusResponse{
		AssetType:     asset.AssetType,
		AssetID:       asset.AssetID,
		EnablePolling: req.EnablePolling,
	})
}

// UpdateRealnamePolicy 更新资产实名认证策略
// PATCH /api/admin/assets/:identifier/realname-mode
func (h *AssetHandler) UpdateRealnamePolicy(c *fiber.Ctx) error {
	if middleware.GetUserTypeFromContext(c.UserContext()) == constants.UserTypeEnterprise {
		return errors.New(errors.CodeForbidden, "企业账号无权修改资产实名认证策略")
	}

	identifier := c.Params("identifier")
	if identifier == "" {
		return errors.New(errors.CodeInvalidParam)
	}

	var req dto.UpdateAssetRealnamePolicyRequest
	if err := c.BodyParser(&req); err != nil {
		return errors.New(errors.CodeInvalidParam)
	}

	if req.RealnamePolicy != constants.RealnamePolicyNone &&
		req.RealnamePolicy != constants.RealnamePolicyBeforeOrder &&
		req.RealnamePolicy != constants.RealnamePolicyAfterOrder {
		return errors.New(errors.CodeInvalidParam, "无效的实名认证策略")
	}

	asset, err := h.assetService.Resolve(c.UserContext(), identifier, false)
	if err != nil {
		return err
	}

	switch asset.AssetType {
	case "card":
		if err := h.iotCardService.UpdateRealnamePolicy(c.UserContext(), asset.AssetID, req.RealnamePolicy); err != nil {
			return err
		}
	case "device":
		if err := h.deviceService.UpdateRealnamePolicy(c.UserContext(), asset.AssetID, req.RealnamePolicy); err != nil {
			return err
		}
	default:
		return errors.New(errors.CodeInvalidParam, "不支持的资产类型")
	}

	return response.Success(c, &dto.UpdateAssetRealnamePolicyResponse{
		AssetType:      asset.AssetType,
		AssetID:        asset.AssetID,
		RealnamePolicy: req.RealnamePolicy,
	})
}

// UpdateRealnameStatus 手动更新资产实名状态
// PATCH /api/admin/assets/:identifier/realname-status
func (h *AssetHandler) UpdateRealnameStatus(c *fiber.Ctx) error {
	identifier := c.Params("identifier")
	if identifier == "" {
		return errors.New(errors.CodeInvalidParam)
	}

	var req dto.UpdateAssetRealnameStatusRequest
	if err := c.BodyParser(&req); err != nil {
		return errors.New(errors.CodeInvalidParam)
	}

	if req.RealNameStatus != constants.RealNameStatusNotVerified &&
		req.RealNameStatus != constants.RealNameStatusVerified {
		return errors.New(errors.CodeInvalidParam, "无效的实名状态")
	}

	asset, err := h.assetService.Resolve(c.UserContext(), identifier, false)
	if err != nil {
		return err
	}
	if asset.AssetType != "card" {
		return errors.New(errors.CodeInvalidParam, "仅支持IoT卡资产手动修改实名状态")
	}

	card, err := h.iotCardService.ManualUpdateRealnameStatus(c.UserContext(), asset.AssetID, req.RealNameStatus)
	if err != nil {
		return err
	}

	return response.Success(c, &dto.UpdateAssetRealnameStatusResponse{
		AssetType:          asset.AssetType,
		AssetID:            asset.AssetID,
		RealNameStatus:     card.RealNameStatus,
		RealNameStatusName: constants.GetRealNameStatusName(card.RealNameStatus),
		FirstRealnameAt:    card.FirstRealnameAt,
	})
}

// resolveCallerAccountType 从 middleware 上下文中提取调用方账号类型
// 平台账号（SuperAdmin/Platform）返回 "platform"，其他返回 "agent"
func resolveCallerAccountType(c *fiber.Ctx) string {
	userType := middleware.GetUserTypeFromContext(c.UserContext())
	if userType == constants.UserTypeSuperAdmin || userType == constants.UserTypePlatform {
		return constants.OwnerTypePlatform
	}
	return "agent"
}

func (h *AssetHandler) resolveAssetPackageUsagePath(c *fiber.Ctx) (*dto.AssetResolveResponse, uint, error) {
	asset, err := h.resolveByIdentifier(c)
	if err != nil {
		return nil, 0, err
	}

	packageUsageID, parseErr := strconv.ParseUint(c.Params("package_usage_id"), 10, 64)
	if parseErr != nil || packageUsageID == 0 {
		return nil, 0, errors.New(errors.CodeInvalidParam)
	}

	return asset, uint(packageUsageID), nil
}

func ensureAssetPackageAdjuster(c *fiber.Ctx) error {
	if middleware.GetUserIDFromContext(c.UserContext()) != 41 && middleware.GetUserIDFromContext(c.UserContext()) != 127 {
		return errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
	}
	return nil
}

func parseAssetPackageTime(value string) (time.Time, error) {
	raw := strings.TrimSpace(value)
	if raw == "" {
		return time.Time{}, errors.New(errors.CodeInvalidParam)
	}

	layouts := []string{
		time.RFC3339,
		"2006-01-02 15:04:05",
		"2006-01-02T15:04:05",
		"2006-01-02",
	}
	for _, layout := range layouts {
		if t, err := time.ParseInLocation(layout, raw, time.Local); err == nil {
			return t, nil
		}
	}
	return time.Time{}, errors.New(errors.CodeInvalidParam)
}

func assetIdentifierForAudit(asset *dto.AssetResolveResponse) string {
	if asset == nil {
		return ""
	}
	if asset.AssetType == "card" && strings.TrimSpace(asset.ICCID) != "" {
		return asset.ICCID
	}
	if strings.TrimSpace(asset.VirtualNo) != "" {
		return asset.VirtualNo
	}
	return asset.Identifier
}
