package device

import (
	"context"
	"strconv"

	"github.com/break/junhong_cmp_fiber/internal/gateway"
	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"gorm.io/gorm"
)

// getGatewayDevice 通过标识符获取设备并验证 IMEI 存在
// 提供统一的设备查找 + IMEI 校验逻辑，供所有 Gateway 代理方法复用
func (s *Service) getGatewayDevice(ctx context.Context, identifier string) (*model.Device, string, error) {
	device, err := s.deviceStore.GetByIdentifier(ctx, identifier)
	if err != nil {
		return nil, "", errors.New(errors.CodeNotFound, "设备不存在或无权限访问")
	}
	if device.IMEI == "" {
		return nil, "", errors.New(errors.CodeInvalidParam, "该设备未配置 IMEI，无法调用网关接口")
	}
	return device, device.IMEI, nil
}

// GatewayGetDeviceInfo 通过标识符查询设备网关信息
func (s *Service) GatewayGetDeviceInfo(ctx context.Context, identifier string) (*gateway.DeviceInfoResp, error) {
	_, imei, err := s.getGatewayDevice(ctx, identifier)
	if err != nil {
		return nil, err
	}
	return s.gatewayClient.GetDeviceInfo(ctx, &gateway.DeviceInfoReq{
		DeviceID: imei,
	})
}

// GatewayGetSlotInfo 通过标识符查询设备卡槽信息
func (s *Service) GatewayGetSlotInfo(ctx context.Context, identifier string) (*gateway.SlotInfoResp, error) {
	_, imei, err := s.getGatewayDevice(ctx, identifier)
	if err != nil {
		return nil, err
	}
	return s.gatewayClient.GetSlotInfo(ctx, &gateway.DeviceInfoReq{
		DeviceID: imei,
	})
}

// GatewaySetWiFi 通过标识符设置设备 WiFi
func (s *Service) GatewaySetWiFi(ctx context.Context, identifier string, req *dto.SetWiFiRequest) error {
	device, imei, err := s.getGatewayDevice(ctx, identifier)
	if err != nil {
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceSetWiFi,
			"设备设置WiFi失败",
			constants.AssetAuditResultFailed,
			nil,
			nil,
			map[string]any{
				"identifier": identifier,
				"ssid":       req.SSID,
				"enabled":    req.Enabled,
				"password":   req.Password,
			},
			0,
			0,
			0,
			err,
		)
		return err
	}
	observation := s.captureDeviceControlObservation(ctx, device.ID, 0, "")
	if err = s.gatewayClient.SetWiFi(ctx, &gateway.WiFiReq{
		CardNo: imei,
		Params: gateway.WiFiParams{
			SSIDName:     req.SSID,
			SSIDPassword: req.Password,
		},
	}); err != nil {
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceSetWiFi,
			"设备设置WiFi失败",
			constants.AssetAuditResultFailed,
			device,
			map[string]any{"device": deviceSnapshot(device)},
			map[string]any{
				"imei":     imei,
				"ssid":     req.SSID,
				"enabled":  req.Enabled,
				"password": req.Password,
			},
			0,
			0,
			0,
			err,
		)
		return err
	}

	s.logDeviceOperation(
		ctx,
		constants.AssetAuditOpDeviceSetWiFi,
		"设备设置WiFi",
		constants.AssetAuditResultSuccess,
		device,
		map[string]any{"device": deviceSnapshot(device)},
		map[string]any{
			"imei":     imei,
			"ssid":     req.SSID,
			"enabled":  req.Enabled,
			"password": req.Password,
		},
		0,
		0,
		0,
		nil,
	)
	s.dispatchDeviceControlObservation(ctx, device.ID, constants.CardObservationSceneDeviceSetWiFi, observation, false)
	return nil
}

// GatewaySwitchCard 通过标识符切换设备使用的卡
func (s *Service) GatewaySwitchCard(ctx context.Context, identifier string, req *dto.SwitchCardRequest) error {
	device, imei, err := s.getGatewayDevice(ctx, identifier)
	if err != nil {
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceSwitchCard,
			"设备切卡失败",
			constants.AssetAuditResultFailed,
			nil,
			nil,
			map[string]any{
				"identifier":   identifier,
				"target_iccid": req.TargetICCID,
			},
			0,
			0,
			0,
			err,
		)
		return err
	}
	observation := s.captureDeviceControlObservation(ctx, device.ID, 0, req.TargetICCID)
	if err = s.gatewayClient.SwitchCard(ctx, &gateway.SwitchCardReq{
		CardNo: imei,
		ICCID:  req.TargetICCID,
	}); err != nil {
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceSwitchCard,
			"设备切卡失败",
			constants.AssetAuditResultFailed,
			device,
			map[string]any{"device": deviceSnapshot(device)},
			map[string]any{"target_iccid": req.TargetICCID},
			0,
			0,
			0,
			err,
		)
		return err
	}

	s.logDeviceOperation(
		ctx,
		constants.AssetAuditOpDeviceSwitchCard,
		"设备切卡",
		constants.AssetAuditResultSuccess,
		device,
		map[string]any{"device": deviceSnapshot(device)},
		map[string]any{"target_iccid": req.TargetICCID},
		0,
		0,
		0,
		nil,
	)
	s.dispatchDeviceControlObservation(ctx, device.ID, constants.CardObservationSceneDeviceSwitchCard, observation, true)
	return nil
}

// GatewayRebootDevice 通过标识符重启设备
func (s *Service) GatewayRebootDevice(ctx context.Context, identifier string) error {
	device, imei, err := s.getGatewayDevice(ctx, identifier)
	if err != nil {
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceReboot,
			"设备重启失败",
			constants.AssetAuditResultFailed,
			nil,
			nil,
			map[string]any{"identifier": identifier},
			0,
			0,
			0,
			err,
		)
		return err
	}
	observation := s.captureDeviceControlObservation(ctx, device.ID, 0, "")
	if err = s.gatewayClient.RebootDevice(ctx, &gateway.DeviceOperationReq{
		DeviceID: imei,
	}); err != nil {
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceReboot,
			"设备重启失败",
			constants.AssetAuditResultFailed,
			device,
			map[string]any{"device": deviceSnapshot(device)},
			nil,
			0,
			0,
			0,
			err,
		)
		return err
	}

	s.logDeviceOperation(
		ctx,
		constants.AssetAuditOpDeviceReboot,
		"设备重启",
		constants.AssetAuditResultSuccess,
		device,
		map[string]any{"device": deviceSnapshot(device)},
		nil,
		0,
		0,
		0,
		nil,
	)
	s.dispatchDeviceControlObservation(ctx, device.ID, constants.CardObservationSceneDeviceReboot, observation, false)
	return nil
}

// GatewayResetDevice 通过标识符恢复设备出厂设置
func (s *Service) GatewayResetDevice(ctx context.Context, identifier string) error {
	device, imei, err := s.getGatewayDevice(ctx, identifier)
	if err != nil {
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceReset,
			"设备恢复出厂失败",
			constants.AssetAuditResultFailed,
			nil,
			nil,
			map[string]any{"identifier": identifier},
			0,
			0,
			0,
			err,
		)
		return err
	}
	observation := s.captureDeviceControlObservation(ctx, device.ID, 0, "")
	if err = s.gatewayClient.ResetDevice(ctx, &gateway.DeviceOperationReq{
		DeviceID: imei,
	}); err != nil {
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceReset,
			"设备恢复出厂失败",
			constants.AssetAuditResultFailed,
			device,
			map[string]any{"device": deviceSnapshot(device)},
			nil,
			0,
			0,
			0,
			err,
		)
		return err
	}

	s.logDeviceOperation(
		ctx,
		constants.AssetAuditOpDeviceReset,
		"设备恢复出厂",
		constants.AssetAuditResultSuccess,
		device,
		map[string]any{"device": deviceSnapshot(device)},
		nil,
		0,
		0,
		0,
		nil,
	)
	s.dispatchDeviceControlObservation(ctx, device.ID, constants.CardObservationSceneDeviceReset, observation, false)
	return nil
}

// GatewaySwitchMode 通过标识符设置设备切卡模式
func (s *Service) GatewaySwitchMode(ctx context.Context, identifier string, req *dto.SetSwitchModeRequest) error {
	switchMode := 0
	if req.SwitchMode != nil {
		switchMode = *req.SwitchMode
	}

	device, imei, err := s.getGatewayDevice(ctx, identifier)
	if err != nil {
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceSwitchMode,
			"设备切卡模式切换失败",
			constants.AssetAuditResultFailed,
			nil,
			nil,
			map[string]any{
				"identifier":  identifier,
				"switch_mode": switchMode,
				"iot_card_id": req.IotCardID,
			},
			0,
			0,
			0,
			err,
		)
		return err
	}
	if req.SwitchMode == nil {
		appErr := errors.New(errors.CodeInvalidParam, "切卡模式不能为空")
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceSwitchMode,
			"设备切卡模式切换被拒绝",
			constants.AssetAuditResultDenied,
			device,
			map[string]any{"device": deviceSnapshot(device)},
			map[string]any{"iot_card_id": req.IotCardID},
			0,
			0,
			0,
			appErr,
		)
		return appErr
	}
	if switchMode != 0 && switchMode != 1 {
		appErr := errors.New(errors.CodeInvalidParam, "切卡模式仅支持0或1")
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceSwitchMode,
			"设备切卡模式切换被拒绝",
			constants.AssetAuditResultDenied,
			device,
			map[string]any{"device": deviceSnapshot(device)},
			map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID},
			0,
			0,
			0,
			appErr,
		)
		return appErr
	}
	if req.IotCardID == 0 {
		appErr := errors.New(errors.CodeInvalidParam, "目标卡资产ID不能为空")
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceSwitchMode,
			"设备切卡模式切换被拒绝",
			constants.AssetAuditResultDenied,
			device,
			map[string]any{"device": deviceSnapshot(device)},
			map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID},
			0,
			0,
			0,
			appErr,
		)
		return appErr
	}

	targetCard, err := s.iotCardStore.GetByID(ctx, req.IotCardID)
	if err != nil {
		if err == gorm.ErrRecordNotFound {
			appErr := errors.New(errors.CodeNotFound, "目标卡资产不存在或无权限访问")
			s.logDeviceOperation(
				ctx,
				constants.AssetAuditOpDeviceSwitchMode,
				"设备切卡模式切换被拒绝",
				constants.AssetAuditResultDenied,
				device,
				map[string]any{"device": deviceSnapshot(device)},
				map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID},
				0,
				0,
				0,
				appErr,
			)
			return appErr
		}
		appErr := errors.Wrap(errors.CodeDatabaseError, err, "查询目标卡资产失败")
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceSwitchMode,
			"设备切卡模式切换失败",
			constants.AssetAuditResultFailed,
			device,
			map[string]any{"device": deviceSnapshot(device)},
			map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID},
			0,
			0,
			0,
			appErr,
		)
		return appErr
	}
	if _, err = s.deviceSimBindingStore.GetByDeviceAndCard(ctx, device.ID, targetCard.ID); err != nil {
		if err == gorm.ErrRecordNotFound {
			appErr := errors.New(errors.CodeForbidden, "目标卡未绑定到当前设备，禁止设置切卡模式")
			s.logDeviceOperation(
				ctx,
				constants.AssetAuditOpDeviceSwitchMode,
				"设备切卡模式切换被拒绝",
				constants.AssetAuditResultDenied,
				device,
				map[string]any{"device": deviceSnapshot(device)},
				map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID, "iccid": targetCard.ICCID},
				0,
				0,
				0,
				appErr,
			)
			return appErr
		}
		appErr := errors.Wrap(errors.CodeDatabaseError, err, "查询设备卡绑定关系失败")
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceSwitchMode,
			"设备切卡模式切换失败",
			constants.AssetAuditResultFailed,
			device,
			map[string]any{"device": deviceSnapshot(device)},
			map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID, "iccid": targetCard.ICCID},
			0,
			0,
			0,
			appErr,
		)
		return appErr
	}
	if targetCard.ICCID == "" {
		appErr := errors.New(errors.CodeConflict, "目标卡资产缺少ICCID，无法设置切卡模式")
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceSwitchMode,
			"设备切卡模式切换被拒绝",
			constants.AssetAuditResultDenied,
			device,
			map[string]any{"device": deviceSnapshot(device)},
			map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID},
			0,
			0,
			0,
			appErr,
		)
		return appErr
	}
	if targetCard.NetworkStatus != constants.NetworkStatusOnline {
		appErr := errors.New(errors.CodeForbidden, "目标卡状态异常，仅正常状态的卡允许设置切卡模式")
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceSwitchMode,
			"设备切卡模式切换被拒绝",
			constants.AssetAuditResultDenied,
			device,
			map[string]any{"device": deviceSnapshot(device)},
			map[string]any{
				"switch_mode":      switchMode,
				"iot_card_id":      req.IotCardID,
				"iccid":            targetCard.ICCID,
				"network_status":   targetCard.NetworkStatus,
				"real_name_status": targetCard.RealNameStatus,
			},
			0,
			0,
			0,
			appErr,
		)
		return appErr
	}
	if targetCard.RealNameStatus != constants.RealNameStatusVerified {
		appErr := errors.New(errors.CodeForbidden, "目标卡未实名，禁止设置切卡模式")
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceSwitchMode,
			"设备切卡模式切换被拒绝",
			constants.AssetAuditResultDenied,
			device,
			map[string]any{"device": deviceSnapshot(device)},
			map[string]any{
				"switch_mode":      switchMode,
				"iot_card_id":      req.IotCardID,
				"iccid":            targetCard.ICCID,
				"network_status":   targetCard.NetworkStatus,
				"real_name_status": targetCard.RealNameStatus,
			},
			0,
			0,
			0,
			appErr,
		)
		return appErr
	}
	observation := s.captureDeviceControlObservation(ctx, device.ID, targetCard.ID, targetCard.ICCID)
	if err = s.gatewayClient.SwitchMode(ctx, &gateway.SwitchModeReq{
		CardNo:     imei,
		SwitchMode: strconv.Itoa(switchMode),
		ICCID:      targetCard.ICCID,
	}); err != nil {
		s.logDeviceOperation(
			ctx,
			constants.AssetAuditOpDeviceSwitchMode,
			"设备切卡模式切换失败",
			constants.AssetAuditResultFailed,
			device,
			map[string]any{"device": deviceSnapshot(device)},
			map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID, "iccid": targetCard.ICCID},
			0,
			0,
			0,
			err,
		)
		return err
	}

	s.logDeviceOperation(
		ctx,
		constants.AssetAuditOpDeviceSwitchMode,
		"设备切卡模式切换",
		constants.AssetAuditResultSuccess,
		device,
		map[string]any{"device": deviceSnapshot(device)},
		map[string]any{"switch_mode": switchMode, "iot_card_id": req.IotCardID, "iccid": targetCard.ICCID},
		0,
		0,
		0,
		nil,
	)
	s.dispatchDeviceControlObservation(ctx, device.ID, constants.CardObservationSceneDeviceSwitchMode, observation, true)
	return nil
}
