package asset

import (
	"context"
	stderrors "errors"

	"github.com/break/junhong_cmp_fiber/internal/model"
	assetAuditSvc "github.com/break/junhong_cmp_fiber/internal/service/asset_audit"
	"github.com/break/junhong_cmp_fiber/internal/store/postgres"
	"github.com/break/junhong_cmp_fiber/pkg/constants"
	"github.com/break/junhong_cmp_fiber/pkg/errors"
	"gorm.io/gorm"
)

var deactivatableAssetStatuses = []int{constants.AssetStatusInStock, constants.AssetStatusSold}

// LifecycleService 资产生命周期服务
type LifecycleService struct {
	db                *gorm.DB
	iotCardStore      *postgres.IotCardStore
	deviceStore       *postgres.DeviceStore
	assetAuditService assetAuditSvc.OperationLogger
}

// NewLifecycleService 创建资产生命周期服务
func NewLifecycleService(
	db *gorm.DB,
	iotCardStore *postgres.IotCardStore,
	deviceStore *postgres.DeviceStore,
	assetAuditService assetAuditSvc.OperationLogger,
) *LifecycleService {
	return &LifecycleService{
		db:                db,
		iotCardStore:      iotCardStore,
		deviceStore:       deviceStore,
		assetAuditService: assetAuditService,
	}
}

func (s *LifecycleService) logLifecycleAudit(ctx context.Context, p assetAuditSvc.BuildLogParams) {
	if s == nil || s.assetAuditService == nil {
		return
	}
	if p.Operator.Type == "" {
		p.Operator = assetAuditSvc.OperatorFromContext(ctx)
	}
	if p.OperationType == "" {
		p.OperationType = constants.AssetAuditOpAssetDeactivate
	}
	s.assetAuditService.LogOperation(ctx, assetAuditSvc.BuildLog(ctx, p))
}

// DeactivateIotCard 手动停用 IoT 卡
func (s *LifecycleService) DeactivateIotCard(ctx context.Context, id uint) error {
	card, err := s.iotCardStore.GetByID(ctx, id)
	if err != nil {
		if stderrors.Is(err, gorm.ErrRecordNotFound) {
			appErr := errors.New(errors.CodeIotCardNotFound)
			errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(appErr)
			s.logLifecycleAudit(ctx, assetAuditSvc.BuildLogParams{
				AssetType:     constants.AssetTypeIotCard,
				AssetID:       id,
				OperationDesc: "统一入口停用IoT卡失败",
				ResultStatus:  constants.AssetAuditResultFailed,
				ErrorCode:     errorCode,
				ErrorMsg:      errorMsg,
			})
			return appErr
		}
		appErr := errors.Wrap(errors.CodeDatabaseError, err, "查询IoT卡失败")
		errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(appErr)
		s.logLifecycleAudit(ctx, assetAuditSvc.BuildLogParams{
			AssetType:     constants.AssetTypeIotCard,
			AssetID:       id,
			OperationDesc: "统一入口停用IoT卡失败",
			ResultStatus:  constants.AssetAuditResultFailed,
			ErrorCode:     errorCode,
			ErrorMsg:      errorMsg,
		})
		return appErr
	}

	beforeData := map[string]any{
		"asset_status": card.AssetStatus,
		"iccid":        card.ICCID,
		"virtual_no":   card.VirtualNo,
	}

	if !canDeactivateAsset(card.AssetStatus) {
		appErr := errors.New(errors.CodeForbidden, "当前状态不允许停用")
		errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(appErr)
		s.logLifecycleAudit(ctx, assetAuditSvc.BuildLogParams{
			AssetType:       constants.AssetTypeIotCard,
			AssetID:         card.ID,
			AssetIdentifier: card.ICCID,
			OperationDesc:   "统一入口停用IoT卡被拒绝",
			ResultStatus:    constants.AssetAuditResultDenied,
			ErrorCode:       errorCode,
			ErrorMsg:        errorMsg,
			BeforeData:      beforeData,
		})
		return appErr
	}

	result := s.db.WithContext(ctx).Model(&model.IotCard{}).
		Where("id = ? AND asset_status IN ?", id, deactivatableAssetStatuses).
		Update("asset_status", constants.AssetStatusDeactivated)
	if result.Error != nil {
		appErr := errors.Wrap(errors.CodeDatabaseError, result.Error, "停用IoT卡失败")
		errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(appErr)
		s.logLifecycleAudit(ctx, assetAuditSvc.BuildLogParams{
			AssetType:       constants.AssetTypeIotCard,
			AssetID:         card.ID,
			AssetIdentifier: card.ICCID,
			OperationDesc:   "统一入口停用IoT卡失败",
			ResultStatus:    constants.AssetAuditResultFailed,
			ErrorCode:       errorCode,
			ErrorMsg:        errorMsg,
			BeforeData:      beforeData,
			AfterData: map[string]any{
				"asset_status": constants.AssetStatusDeactivated,
				"iccid":        card.ICCID,
				"virtual_no":   card.VirtualNo,
			},
		})
		return appErr
	}
	if result.RowsAffected == 0 {
		appErr := errors.New(errors.CodeConflict, "状态已变更，请刷新后重试")
		errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(appErr)
		s.logLifecycleAudit(ctx, assetAuditSvc.BuildLogParams{
			AssetType:       constants.AssetTypeIotCard,
			AssetID:         card.ID,
			AssetIdentifier: card.ICCID,
			OperationDesc:   "统一入口停用IoT卡失败",
			ResultStatus:    constants.AssetAuditResultFailed,
			ErrorCode:       errorCode,
			ErrorMsg:        errorMsg,
			BeforeData:      beforeData,
		})
		return appErr
	}

	s.logLifecycleAudit(ctx, assetAuditSvc.BuildLogParams{
		AssetType:       constants.AssetTypeIotCard,
		AssetID:         card.ID,
		AssetIdentifier: card.ICCID,
		OperationDesc:   "统一入口停用IoT卡",
		ResultStatus:    constants.AssetAuditResultSuccess,
		BeforeData:      beforeData,
		AfterData: map[string]any{
			"asset_status": constants.AssetStatusDeactivated,
			"iccid":        card.ICCID,
			"virtual_no":   card.VirtualNo,
		},
	})

	return nil
}

// DeactivateDevice 手动停用设备
func (s *LifecycleService) DeactivateDevice(ctx context.Context, id uint) error {
	device, err := s.deviceStore.GetByID(ctx, id)
	if err != nil {
		if stderrors.Is(err, gorm.ErrRecordNotFound) {
			appErr := errors.New(errors.CodeNotFound, "设备不存在")
			errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(appErr)
			s.logLifecycleAudit(ctx, assetAuditSvc.BuildLogParams{
				AssetType:     constants.AssetTypeDevice,
				AssetID:       id,
				OperationDesc: "统一入口停用设备失败",
				ResultStatus:  constants.AssetAuditResultFailed,
				ErrorCode:     errorCode,
				ErrorMsg:      errorMsg,
			})
			return appErr
		}
		appErr := errors.Wrap(errors.CodeDatabaseError, err, "查询设备失败")
		errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(appErr)
		s.logLifecycleAudit(ctx, assetAuditSvc.BuildLogParams{
			AssetType:     constants.AssetTypeDevice,
			AssetID:       id,
			OperationDesc: "统一入口停用设备失败",
			ResultStatus:  constants.AssetAuditResultFailed,
			ErrorCode:     errorCode,
			ErrorMsg:      errorMsg,
		})
		return appErr
	}

	beforeData := map[string]any{
		"asset_status": device.AssetStatus,
		"virtual_no":   device.VirtualNo,
	}

	if !canDeactivateAsset(device.AssetStatus) {
		appErr := errors.New(errors.CodeForbidden, "当前状态不允许停用")
		errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(appErr)
		s.logLifecycleAudit(ctx, assetAuditSvc.BuildLogParams{
			AssetType:       constants.AssetTypeDevice,
			AssetID:         device.ID,
			AssetIdentifier: device.VirtualNo,
			OperationDesc:   "统一入口停用设备被拒绝",
			ResultStatus:    constants.AssetAuditResultDenied,
			ErrorCode:       errorCode,
			ErrorMsg:        errorMsg,
			BeforeData:      beforeData,
		})
		return appErr
	}

	result := s.db.WithContext(ctx).Model(&model.Device{}).
		Where("id = ? AND asset_status IN ?", id, deactivatableAssetStatuses).
		Update("asset_status", constants.AssetStatusDeactivated)
	if result.Error != nil {
		appErr := errors.Wrap(errors.CodeDatabaseError, result.Error, "停用设备失败")
		errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(appErr)
		s.logLifecycleAudit(ctx, assetAuditSvc.BuildLogParams{
			AssetType:       constants.AssetTypeDevice,
			AssetID:         device.ID,
			AssetIdentifier: device.VirtualNo,
			OperationDesc:   "统一入口停用设备失败",
			ResultStatus:    constants.AssetAuditResultFailed,
			ErrorCode:       errorCode,
			ErrorMsg:        errorMsg,
			BeforeData:      beforeData,
			AfterData: map[string]any{
				"asset_status": constants.AssetStatusDeactivated,
				"virtual_no":   device.VirtualNo,
			},
		})
		return appErr
	}
	if result.RowsAffected == 0 {
		appErr := errors.New(errors.CodeConflict, "状态已变更，请刷新后重试")
		errorCode, errorMsg := assetAuditSvc.BuildErrorInfo(appErr)
		s.logLifecycleAudit(ctx, assetAuditSvc.BuildLogParams{
			AssetType:       constants.AssetTypeDevice,
			AssetID:         device.ID,
			AssetIdentifier: device.VirtualNo,
			OperationDesc:   "统一入口停用设备失败",
			ResultStatus:    constants.AssetAuditResultFailed,
			ErrorCode:       errorCode,
			ErrorMsg:        errorMsg,
			BeforeData:      beforeData,
		})
		return appErr
	}

	s.logLifecycleAudit(ctx, assetAuditSvc.BuildLogParams{
		AssetType:       constants.AssetTypeDevice,
		AssetID:         device.ID,
		AssetIdentifier: device.VirtualNo,
		OperationDesc:   "统一入口停用设备",
		ResultStatus:    constants.AssetAuditResultSuccess,
		BeforeData:      beforeData,
		AfterData: map[string]any{
			"asset_status": constants.AssetStatusDeactivated,
			"virtual_no":   device.VirtualNo,
		},
	})

	return nil
}

func canDeactivateAsset(assetStatus int) bool {
	return assetStatus == constants.AssetStatusInStock || assetStatus == constants.AssetStatusSold
}
