package app

import (
	"github.com/break/junhong_cmp_fiber/internal/gateway"
	"github.com/break/junhong_cmp_fiber/internal/middleware"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	assetSvc "github.com/break/junhong_cmp_fiber/internal/service/asset"
	customerBinding "github.com/break/junhong_cmp_fiber/internal/service/customer_binding"
	deviceSvc "github.com/break/junhong_cmp_fiber/internal/service/device"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"github.com/break/junhong_cmp_fiber/pkg/logger"
	"github.com/break/junhong_cmp_fiber/pkg/response"
	"github.com/go-playground/validator/v10"
	"github.com/gofiber/fiber/v2"
	"go.uber.org/zap"
)

var clientDeviceValidator = validator.New()

// deviceAssetInfo validateDeviceAsset 解析后的设备资产信息
type deviceAssetInfo struct {
	DeviceID  uint   // 设备数据库 ID
	IMEI      string // 设备 IMEI（用于 Gateway API 调用）
	VirtualNo string // 设备虚拟号（用于所有权校验）
}

// ClientDeviceHandler C 端设备能力处理器
// 提供设备卡列表、重启、恢复出厂、WiFi 配置、切卡等操作
type ClientDeviceHandler struct {
	assetService          *assetSvc.Service
	customerBinding       *customerBinding.Service
	deviceStore           *postgres.DeviceStore
	deviceSimBindingStore *postgres.DeviceSimBindingStore
	iotCardStore          *postgres.IotCardStore
	gatewayClient         *gateway.Client
	deviceService         *deviceSvc.Service
	logger                *zap.Logger
}

// SetDeviceService 注入统一设备控制服务，确保各入口共享成功后的观测触发。
func (h *ClientDeviceHandler) SetDeviceService(service *deviceSvc.Service) {
	h.deviceService = service
}

// NewClientDeviceHandler 创建 C 端设备能力处理器
func NewClientDeviceHandler(
	assetService *assetSvc.Service,
	binding *customerBinding.Service,
	deviceStore *postgres.DeviceStore,
	deviceSimBindingStore *postgres.DeviceSimBindingStore,
	iotCardStore *postgres.IotCardStore,
	gatewayClient *gateway.Client,
	logger *zap.Logger,
) *ClientDeviceHandler {
	return &ClientDeviceHandler{
		assetService:          assetService,
		customerBinding:       binding,
		deviceStore:           deviceStore,
		deviceSimBindingStore: deviceSimBindingStore,
		iotCardStore:          iotCardStore,
		gatewayClient:         gatewayClient,
		logger:                logger,
	}
}

// validateDeviceAsset 校验设备资产的所有权和有效性
// 流程：认证 → 资产解析 → 类型校验（仅设备）→ 所有权校验 → IMEI 校验
func (h *ClientDeviceHandler) validateDeviceAsset(c *fiber.Ctx, identifier string) (*deviceAssetInfo, error) {
	// 获取当前登录的个人客户 ID
	customerID, ok := middleware.GetCustomerID(c)
	if !ok || customerID == 0 {
		return nil, errors.New(errors.CodeUnauthorized)
	}

	ctx := c.UserContext()

	// 通过标识符解析资产
	asset, err := h.assetService.Resolve(ctx, identifier, false)
	if err != nil {
		return nil, err
	}

	// 仅设备资产支持设备能力操作
	if asset.AssetType != "device" {
		return nil, errors.New(errors.CodeInvalidParam, "仅设备资产支持该操作")
	}

	// 校验个人客户对该设备的所有权
	owns, err := h.customerBinding.OwnsAsset(ctx, customerID, asset.AssetType, asset.AssetID)
	if err != nil {
		h.logger.Error("校验设备所有权失败",
			zap.Uint("customer_id", customerID),
			zap.Uint("asset_id", asset.AssetID),
			zap.Error(err))
		return nil, errors.New(errors.CodeInternalError)
	}
	if !owns {
		return nil, errors.New(errors.CodeForbidden, "无权限操作该资源或资源不存在")
	}

	// 校验设备 IMEI 是否存在（Gateway API 调用必需）
	if asset.IMEI == "" {
		return nil, errors.New(errors.CodeInvalidParam, "设备IMEI缺失")
	}

	return &deviceAssetInfo{
		DeviceID:  asset.AssetID,
		IMEI:      asset.IMEI,
		VirtualNo: asset.VirtualNo,
	}, nil
}

// GetDeviceCards F1 获取设备卡列表
// GET /api/c/v1/device/cards
func (h *ClientDeviceHandler) GetDeviceCards(c *fiber.Ctx) error {
	var req dto.DeviceCardListRequest
	if err := c.QueryParser(&req); err != nil {
		return errors.New(errors.CodeInvalidParam)
	}
	if err := clientDeviceValidator.Struct(&req); err != nil {
		logger.GetAppLogger().Warn("设备卡列表参数校验失败", zap.Error(err))
		return errors.New(errors.CodeInvalidParam)
	}

	info, err := h.validateDeviceAsset(c, req.Identifier)
	if err != nil {
		return err
	}

	ctx := c.UserContext()

	// 查询设备绑定的所有 SIM 卡
	bindings, err := h.deviceSimBindingStore.ListByDeviceID(ctx, info.DeviceID)
	if err != nil {
		h.logger.Error("查询设备SIM绑定失败",
			zap.Uint("device_id", info.DeviceID),
			zap.Error(err))
		return errors.New(errors.CodeInternalError)
	}

	// 无绑定卡时返回空列表
	if len(bindings) == 0 {
		return response.Success(c, &dto.DeviceCardListResponse{Cards: []dto.DeviceCardItem{}})
	}

	// 收集卡 ID，并记录插槽位置与当前在用标识
	cardIDs := make([]uint, 0, len(bindings))
	slotMap := make(map[uint]int, len(bindings))
	isCurrentMap := make(map[uint]bool, len(bindings))
	for _, b := range bindings {
		cardIDs = append(cardIDs, b.IotCardID)
		slotMap[b.IotCardID] = b.SlotPosition
		isCurrentMap[b.IotCardID] = b.IsCurrent
	}

	// 批量查询卡详情
	cards, err := h.iotCardStore.GetByIDs(ctx, cardIDs)
	if err != nil {
		h.logger.Error("批量查询IoT卡失败",
			zap.Uints("card_ids", cardIDs),
			zap.Error(err))
		return errors.New(errors.CodeInternalError)
	}

	// 组装响应，当前激活卡以绑定表 is_current 为准
	items := make([]dto.DeviceCardItem, 0, len(cards))
	for _, card := range cards {
		slot := slotMap[card.ID]
		items = append(items, dto.DeviceCardItem{
			CardID:         card.ID,
			ICCID:          card.ICCID,
			MSISDN:         card.MSISDN,
			CarrierType:    card.CarrierType,
			CarrierName:    card.CarrierName,
			NetworkStatus:  networkStatusText(card.NetworkStatus),
			GatewayExtend:  card.GatewayExtend,
			RealNameStatus: card.RealNameStatus,
			SlotPosition:   slot,
			IsActive:       isCurrentMap[card.ID],
			RealnamePolicy: card.RealnamePolicy,
		})
	}

	return response.Success(c, &dto.DeviceCardListResponse{Cards: items})
}

// RebootDevice F2 设备重启
// POST /api/c/v1/device/reboot
func (h *ClientDeviceHandler) RebootDevice(c *fiber.Ctx) error {
	var req dto.DeviceRebootRequest
	if err := c.BodyParser(&req); err != nil {
		return errors.New(errors.CodeInvalidParam)
	}
	if err := clientDeviceValidator.Struct(&req); err != nil {
		logger.GetAppLogger().Warn("设备重启参数校验失败", zap.Error(err))
		return errors.New(errors.CodeInvalidParam)
	}

	info, err := h.validateDeviceAsset(c, req.Identifier)
	if err != nil {
		return err
	}

	if h.deviceService == nil {
		return errors.New(errors.CodeInternalError, "设备控制服务未配置")
	}
	if err := h.deviceService.GatewayRebootDevice(c.UserContext(), info.IMEI); err != nil {
		h.logger.Error("Gateway重启设备失败",
			zap.String("imei", info.IMEI),
			zap.Error(err))
		return errors.Wrap(errors.CodeGatewayError, err, "设备重启失败")
	}

	return response.Success(c, &dto.DeviceOperationResponse{Accepted: true})
}

// FactoryResetDevice F3 恢复出厂设置
// POST /api/c/v1/device/factory-reset
func (h *ClientDeviceHandler) FactoryResetDevice(c *fiber.Ctx) error {
	var req dto.DeviceFactoryResetRequest
	if err := c.BodyParser(&req); err != nil {
		return errors.New(errors.CodeInvalidParam)
	}
	if err := clientDeviceValidator.Struct(&req); err != nil {
		logger.GetAppLogger().Warn("恢复出厂设置参数校验失败", zap.Error(err))
		return errors.New(errors.CodeInvalidParam)
	}

	info, err := h.validateDeviceAsset(c, req.Identifier)
	if err != nil {
		return err
	}

	if h.deviceService == nil {
		return errors.New(errors.CodeInternalError, "设备控制服务未配置")
	}
	if err := h.deviceService.GatewayResetDevice(c.UserContext(), info.IMEI); err != nil {
		h.logger.Error("Gateway恢复出厂设置失败",
			zap.String("imei", info.IMEI),
			zap.Error(err))
		return errors.Wrap(errors.CodeGatewayError, err, "恢复出厂设置失败")
	}

	return response.Success(c, &dto.DeviceOperationResponse{Accepted: true})
}

// SetWiFi F4 设备WiFi配置
// POST /api/c/v1/device/wifi
// 注意：WiFiReq.CardNo 字段名具有误导性，实际传入的是设备 IMEI，而非卡号
func (h *ClientDeviceHandler) SetWiFi(c *fiber.Ctx) error {
	var req dto.DeviceWifiRequest
	if err := c.BodyParser(&req); err != nil {
		return errors.New(errors.CodeInvalidParam)
	}
	if err := clientDeviceValidator.Struct(&req); err != nil {
		logger.GetAppLogger().Warn("WiFi配置参数校验失败", zap.Error(err))
		return errors.New(errors.CodeInvalidParam)
	}

	info, err := h.validateDeviceAsset(c, req.Identifier)
	if err != nil {
		return err
	}

	if h.deviceService == nil {
		return errors.New(errors.CodeInternalError, "设备控制服务未配置")
	}
	if err := h.deviceService.GatewaySetWiFi(c.UserContext(), info.IMEI, &dto.SetWiFiRequest{
		SSID: req.SSID, Password: req.Password, Enabled: req.Enabled,
	}); err != nil {
		h.logger.Error("Gateway配置WiFi失败",
			zap.String("imei", info.IMEI),
			zap.String("ssid", req.SSID),
			zap.Error(err))
		return errors.Wrap(errors.CodeGatewayError, err, "WiFi配置失败")
	}

	return response.Success(c, &dto.DeviceOperationResponse{Accepted: true})
}

// SwitchCard F5 设备切卡
// POST /api/c/v1/device/switch-card
func (h *ClientDeviceHandler) SwitchCard(c *fiber.Ctx) error {
	var req dto.DeviceSwitchCardRequest
	if err := c.BodyParser(&req); err != nil {
		return errors.New(errors.CodeInvalidParam)
	}
	if err := clientDeviceValidator.Struct(&req); err != nil {
		logger.GetAppLogger().Warn("设备切卡参数校验失败", zap.Error(err))
		return errors.New(errors.CodeInvalidParam)
	}

	info, err := h.validateDeviceAsset(c, req.Identifier)
	if err != nil {
		return err
	}

	if h.deviceService == nil {
		return errors.New(errors.CodeInternalError, "设备控制服务未配置")
	}
	if err := h.deviceService.GatewaySwitchCard(c.UserContext(), info.IMEI, &dto.SwitchCardRequest{
		TargetICCID: req.TargetICCID,
	}); err != nil {
		h.logger.Error("Gateway切卡失败",
			zap.String("imei", info.IMEI),
			zap.String("target_iccid", req.TargetICCID),
			zap.Error(err))
		return errors.Wrap(errors.CodeGatewayError, err, "设备切卡失败")
	}

	return response.Success(c, &dto.DeviceSwitchCardResponse{
		Accepted:    true,
		TargetICCID: req.TargetICCID,
	})
}

// networkStatusText 将网络状态码转为文本描述
func networkStatusText(status int) string {
	switch status {
	case 0:
		return "停机"
	case 1:
		return "开机"
	default:
		return "未知"
	}
}
