package enterprise_device

import (
	"context"
	"time"

	"github.com/break/junhong_cmp_fiber/internal/model"
	"github.com/break/junhong_cmp_fiber/internal/model/dto"
	"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"
	pkggorm "github.com/break/junhong_cmp_fiber/pkg/gorm"
	"github.com/break/junhong_cmp_fiber/pkg/middleware"
	"go.uber.org/zap"
	"gorm.io/gorm"
)

type Service struct {
	db                        *gorm.DB
	enterpriseStore           *postgres.EnterpriseStore
	deviceStore               *postgres.DeviceStore
	deviceSimBindingStore     *postgres.DeviceSimBindingStore
	enterpriseDeviceAuthStore *postgres.EnterpriseDeviceAuthorizationStore
	enterpriseCardAuthStore   *postgres.EnterpriseCardAuthorizationStore
	logger                    *zap.Logger
}

func New(
	db *gorm.DB,
	enterpriseStore *postgres.EnterpriseStore,
	deviceStore *postgres.DeviceStore,
	deviceSimBindingStore *postgres.DeviceSimBindingStore,
	enterpriseDeviceAuthStore *postgres.EnterpriseDeviceAuthorizationStore,
	enterpriseCardAuthStore *postgres.EnterpriseCardAuthorizationStore,
	logger *zap.Logger,
) *Service {
	return &Service{
		db:                        db,
		enterpriseStore:           enterpriseStore,
		deviceStore:               deviceStore,
		deviceSimBindingStore:     deviceSimBindingStore,
		enterpriseDeviceAuthStore: enterpriseDeviceAuthStore,
		enterpriseCardAuthStore:   enterpriseCardAuthStore,
		logger:                    logger,
	}
}

// AllocateDevices 授权设备给企业
func (s *Service) AllocateDevices(ctx context.Context, enterpriseID uint, req *dto.AllocateDevicesReq) (*dto.AllocateDevicesResp, error) {
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	// 验证企业存在
	_, err := s.enterpriseStore.GetByID(ctx, enterpriseID)
	if err != nil {
		return nil, errors.New(errors.CodeEnterpriseNotFound, "企业不存在")
	}

	// 查询所有设备
	var devices []model.Device
	if err := s.db.WithContext(ctx).Where("device_no IN ?", req.DeviceNos).Find(&devices).Error; err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询设备信息失败")
	}

	deviceMap := make(map[string]*model.Device)
	deviceIDs := make([]uint, 0, len(devices))
	for i := range devices {
		deviceMap[devices[i].DeviceNo] = &devices[i]
		deviceIDs = append(deviceIDs, devices[i].ID)
	}

	// 获取当前用户的店铺ID（用于验证设备所有权）
	currentShopID := middleware.GetShopIDFromContext(ctx)
	userType := middleware.GetUserTypeFromContext(ctx)

	// 检查已授权的设备
	existingAuths, err := s.enterpriseDeviceAuthStore.GetActiveAuthsByDeviceIDs(ctx, enterpriseID, deviceIDs)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询已有授权失败")
	}

	resp := &dto.AllocateDevicesResp{
		FailedItems:       make([]dto.FailedDeviceItem, 0),
		AuthorizedDevices: make([]dto.AuthorizedDeviceItem, 0),
	}

	devicesToAllocate := make([]*model.Device, 0)
	for _, deviceNo := range req.DeviceNos {
		device, exists := deviceMap[deviceNo]
		if !exists {
			resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
				DeviceNo: deviceNo,
				Reason:   "设备不存在",
			})
			continue
		}

		// 验证设备状态（必须是"已分销"状态）
		if device.Status != 2 {
			resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
				DeviceNo: deviceNo,
				Reason:   "设备状态不正确，必须是已分销状态",
			})
			continue
		}

		// 验证设备所有权（除非是超级管理员或平台用户）
		if userType == constants.UserTypeAgent {
			if device.ShopID == nil || *device.ShopID != currentShopID {
				resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
					DeviceNo: deviceNo,
					Reason:   "无权操作此设备",
				})
				continue
			}
		}

		// 检查是否已授权
		if existingAuths[device.ID] {
			resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
				DeviceNo: deviceNo,
				Reason:   "设备已授权给此企业",
			})
			continue
		}

		devicesToAllocate = append(devicesToAllocate, device)
	}

	// 在事务中处理授权
	if len(devicesToAllocate) > 0 {
		err := s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
			now := time.Now()
			authorizerType := userType

			// 1. 创建设备授权记录
			deviceAuths := make([]*model.EnterpriseDeviceAuthorization, 0, len(devicesToAllocate))
			for _, device := range devicesToAllocate {
				deviceAuths = append(deviceAuths, &model.EnterpriseDeviceAuthorization{
					EnterpriseID:   enterpriseID,
					DeviceID:       device.ID,
					AuthorizedBy:   currentUserID,
					AuthorizedAt:   now,
					AuthorizerType: authorizerType,
					Remark:         req.Remark,
				})
			}

			if err := tx.Create(deviceAuths).Error; err != nil {
				return errors.Wrap(errors.CodeInternalError, err, "创建设备授权记录失败")
			}

			// 构建设备ID到授权ID的映射
			deviceAuthIDMap := make(map[uint]uint)
			for _, auth := range deviceAuths {
				deviceAuthIDMap[auth.DeviceID] = auth.ID
			}

			// 2. 查询所有设备绑定的卡
			deviceIDsToQuery := make([]uint, 0, len(devicesToAllocate))
			for _, device := range devicesToAllocate {
				deviceIDsToQuery = append(deviceIDsToQuery, device.ID)
			}

			var bindings []model.DeviceSimBinding
			if err := tx.Where("device_id IN ? AND bind_status = 1", deviceIDsToQuery).Find(&bindings).Error; err != nil {
				return errors.Wrap(errors.CodeInternalError, err, "查询设备绑定卡失败")
			}

			// 3. 为每张绑定的卡创建授权记录
			if len(bindings) > 0 {
				cardAuths := make([]*model.EnterpriseCardAuthorization, 0, len(bindings))
				for _, binding := range bindings {
					deviceAuthID := deviceAuthIDMap[binding.DeviceID]
					cardAuths = append(cardAuths, &model.EnterpriseCardAuthorization{
						EnterpriseID:   enterpriseID,
						CardID:         binding.IotCardID,
						DeviceAuthID:   &deviceAuthID,
						AuthorizedBy:   currentUserID,
						AuthorizedAt:   now,
						AuthorizerType: authorizerType,
						Remark:         req.Remark,
					})
				}

				if err := tx.Create(cardAuths).Error; err != nil {
					return errors.Wrap(errors.CodeInternalError, err, "创建卡授权记录失败")
				}
			}

			// 4. 统计每个设备的绑定卡数量
			deviceCardCount := make(map[uint]int)
			for _, binding := range bindings {
				deviceCardCount[binding.DeviceID]++
			}

			// 5. 构建响应
			for _, device := range devicesToAllocate {
				resp.AuthorizedDevices = append(resp.AuthorizedDevices, dto.AuthorizedDeviceItem{
					DeviceID:  device.ID,
					DeviceNo:  device.DeviceNo,
					CardCount: deviceCardCount[device.ID],
				})
			}

			return nil
		})

		if err != nil {
			return nil, err
		}
	}

	resp.SuccessCount = len(devicesToAllocate)
	resp.FailCount = len(resp.FailedItems)
	return resp, nil
}

// RecallDevices 撤销设备授权
func (s *Service) RecallDevices(ctx context.Context, enterpriseID uint, req *dto.RecallDevicesReq) (*dto.RecallDevicesResp, error) {
	currentUserID := middleware.GetUserIDFromContext(ctx)
	if currentUserID == 0 {
		return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	// 验证企业存在
	_, err := s.enterpriseStore.GetByID(ctx, enterpriseID)
	if err != nil {
		return nil, errors.New(errors.CodeEnterpriseNotFound, "企业不存在")
	}

	// 查询设备
	var devices []model.Device
	if err := s.db.WithContext(ctx).Where("device_no IN ?", req.DeviceNos).Find(&devices).Error; err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询设备信息失败")
	}

	deviceMap := make(map[string]*model.Device)
	deviceIDs := make([]uint, 0, len(devices))
	for i := range devices {
		deviceMap[devices[i].DeviceNo] = &devices[i]
		deviceIDs = append(deviceIDs, devices[i].ID)
	}

	// 检查授权状态
	existingAuths, err := s.enterpriseDeviceAuthStore.GetActiveAuthsByDeviceIDs(ctx, enterpriseID, deviceIDs)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询授权状态失败")
	}

	resp := &dto.RecallDevicesResp{
		FailedItems: make([]dto.FailedDeviceItem, 0),
	}

	deviceAuthsToRevoke := make([]uint, 0)
	for _, deviceNo := range req.DeviceNos {
		device, exists := deviceMap[deviceNo]
		if !exists {
			resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
				DeviceNo: deviceNo,
				Reason:   "设备不存在",
			})
			continue
		}

		if !existingAuths[device.ID] {
			resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
				DeviceNo: deviceNo,
				Reason:   "设备未授权给此企业",
			})
			continue
		}

		// 获取授权记录ID
		auth, err := s.enterpriseDeviceAuthStore.GetByDeviceID(ctx, device.ID)
		if err != nil || auth.EnterpriseID != enterpriseID {
			resp.FailedItems = append(resp.FailedItems, dto.FailedDeviceItem{
				DeviceNo: deviceNo,
				Reason:   "授权记录不存在",
			})
			continue
		}

		deviceAuthsToRevoke = append(deviceAuthsToRevoke, auth.ID)
	}

	// 在事务中处理撤销
	if len(deviceAuthsToRevoke) > 0 {
		err := s.db.WithContext(ctx).Transaction(func(tx *gorm.DB) error {
			// 1. 撤销设备授权
			if err := s.enterpriseDeviceAuthStore.RevokeByIDs(ctx, deviceAuthsToRevoke, currentUserID); err != nil {
				return errors.Wrap(errors.CodeInternalError, err, "撤销设备授权失败")
			}

			// 2. 级联撤销卡授权
			for _, authID := range deviceAuthsToRevoke {
				if err := s.enterpriseCardAuthStore.RevokeByDeviceAuthID(ctx, authID, currentUserID); err != nil {
					return errors.Wrap(errors.CodeInternalError, err, "撤销卡授权失败")
				}
			}

			return nil
		})

		if err != nil {
			return nil, err
		}
	}

	resp.SuccessCount = len(deviceAuthsToRevoke)
	resp.FailCount = len(resp.FailedItems)
	return resp, nil
}

// ListDevices 查询企业授权设备列表（后台管理）
func (s *Service) ListDevices(ctx context.Context, enterpriseID uint, req *dto.EnterpriseDeviceListReq) (*dto.EnterpriseDeviceListResp, error) {
	// 验证企业存在
	_, err := s.enterpriseStore.GetByID(ctx, enterpriseID)
	if err != nil {
		return nil, errors.New(errors.CodeEnterpriseNotFound, "企业不存在")
	}

	// 查询授权记录
	opts := postgres.DeviceAuthListOptions{
		EnterpriseID:   &enterpriseID,
		IncludeRevoked: false,
		Page:           req.Page,
		PageSize:       req.PageSize,
	}

	auths, total, err := s.enterpriseDeviceAuthStore.ListByEnterprise(ctx, opts)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询授权记录失败")
	}

	if len(auths) == 0 {
		return &dto.EnterpriseDeviceListResp{
			List:  make([]dto.EnterpriseDeviceItem, 0),
			Total: 0,
		}, nil
	}

	// 收集设备ID
	deviceIDs := make([]uint, 0, len(auths))
	authMap := make(map[uint]*model.EnterpriseDeviceAuthorization)
	for _, auth := range auths {
		deviceIDs = append(deviceIDs, auth.DeviceID)
		authMap[auth.DeviceID] = auth
	}

	// 查询设备信息
	var devices []model.Device
	query := s.db.WithContext(ctx).Where("id IN ?", deviceIDs)
	if req.DeviceNo != "" {
		query = query.Where("device_no LIKE ?", "%"+req.DeviceNo+"%")
	}
	if err := query.Find(&devices).Error; err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询设备信息失败")
	}

	// 统计每个设备的绑定卡数量
	var bindings []model.DeviceSimBinding
	if err := s.db.WithContext(ctx).
		Where("device_id IN ? AND bind_status = 1", deviceIDs).
		Find(&bindings).Error; err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询设备绑定卡失败")
	}

	cardCountMap := make(map[uint]int)
	for _, binding := range bindings {
		cardCountMap[binding.DeviceID]++
	}

	// 构建响应
	items := make([]dto.EnterpriseDeviceItem, 0, len(devices))
	for _, device := range devices {
		auth := authMap[device.ID]
		items = append(items, dto.EnterpriseDeviceItem{
			DeviceID:     device.ID,
			DeviceNo:     device.DeviceNo,
			DeviceName:   device.DeviceName,
			DeviceModel:  device.DeviceModel,
			CardCount:    cardCountMap[device.ID],
			AuthorizedAt: auth.AuthorizedAt,
		})
	}

	return &dto.EnterpriseDeviceListResp{
		List:  items,
		Total: total,
	}, nil
}

// ListDevicesForEnterprise 查询企业授权设备列表（H5企业用户）
func (s *Service) ListDevicesForEnterprise(ctx context.Context, req *dto.EnterpriseDeviceListReq) (*dto.EnterpriseDeviceListResp, error) {
	enterpriseID := middleware.GetEnterpriseIDFromContext(ctx)
	if enterpriseID == 0 {
		return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	opts := postgres.DeviceAuthListOptions{
		EnterpriseID:   &enterpriseID,
		IncludeRevoked: false,
		Page:           req.Page,
		PageSize:       req.PageSize,
	}

	auths, total, err := s.enterpriseDeviceAuthStore.ListByEnterprise(ctx, opts)
	if err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询授权记录失败")
	}

	if len(auths) == 0 {
		return &dto.EnterpriseDeviceListResp{
			List:  make([]dto.EnterpriseDeviceItem, 0),
			Total: 0,
		}, nil
	}

	deviceIDs := make([]uint, 0, len(auths))
	authMap := make(map[uint]*model.EnterpriseDeviceAuthorization)
	for _, auth := range auths {
		deviceIDs = append(deviceIDs, auth.DeviceID)
		authMap[auth.DeviceID] = auth
	}

	skipCtx := pkggorm.SkipDataPermission(ctx)

	var devices []model.Device
	query := s.db.WithContext(skipCtx).Where("id IN ?", deviceIDs)
	if req.DeviceNo != "" {
		query = query.Where("device_no LIKE ?", "%"+req.DeviceNo+"%")
	}
	if err := query.Find(&devices).Error; err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询设备信息失败")
	}

	var bindings []model.DeviceSimBinding
	if err := s.db.WithContext(skipCtx).
		Where("device_id IN ? AND bind_status = 1", deviceIDs).
		Find(&bindings).Error; err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询设备绑定卡失败")
	}

	cardCountMap := make(map[uint]int)
	for _, binding := range bindings {
		cardCountMap[binding.DeviceID]++
	}

	items := make([]dto.EnterpriseDeviceItem, 0, len(devices))
	for _, device := range devices {
		auth := authMap[device.ID]
		items = append(items, dto.EnterpriseDeviceItem{
			DeviceID:     device.ID,
			DeviceNo:     device.DeviceNo,
			DeviceName:   device.DeviceName,
			DeviceModel:  device.DeviceModel,
			CardCount:    cardCountMap[device.ID],
			AuthorizedAt: auth.AuthorizedAt,
		})
	}

	return &dto.EnterpriseDeviceListResp{
		List:  items,
		Total: total,
	}, nil
}

// GetDeviceDetail 获取设备详情（H5企业用户）
func (s *Service) GetDeviceDetail(ctx context.Context, deviceID uint) (*dto.EnterpriseDeviceDetailResp, error) {
	enterpriseID := middleware.GetEnterpriseIDFromContext(ctx)
	if enterpriseID == 0 {
		return nil, errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	auth, err := s.enterpriseDeviceAuthStore.GetByDeviceID(ctx, deviceID)
	if err != nil || auth.EnterpriseID != enterpriseID || auth.RevokedAt != nil {
		return nil, errors.New(errors.CodeDeviceNotAuthorized, "设备未授权给此企业")
	}

	skipCtx := pkggorm.SkipDataPermission(ctx)

	var device model.Device
	if err := s.db.WithContext(skipCtx).Where("id = ?", deviceID).First(&device).Error; err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询设备信息失败")
	}

	var bindings []model.DeviceSimBinding
	if err := s.db.WithContext(skipCtx).
		Where("device_id = ? AND bind_status = 1", deviceID).
		Find(&bindings).Error; err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "查询设备绑定卡失败")
	}

	cardIDs := make([]uint, 0, len(bindings))
	for _, binding := range bindings {
		cardIDs = append(cardIDs, binding.IotCardID)
	}

	var cards []model.IotCard
	cardInfos := make([]dto.DeviceCardInfo, 0)
	if len(cardIDs) > 0 {
		if err := s.db.WithContext(skipCtx).Where("id IN ?", cardIDs).Find(&cards).Error; err != nil {
			return nil, errors.Wrap(errors.CodeInternalError, err, "查询卡信息失败")
		}

		carrierIDs := make([]uint, 0, len(cards))
		for _, card := range cards {
			carrierIDs = append(carrierIDs, card.CarrierID)
		}

		var carriers []model.Carrier
		carrierMap := make(map[uint]string)
		if len(carrierIDs) > 0 {
			if err := s.db.WithContext(skipCtx).Where("id IN ?", carrierIDs).Find(&carriers).Error; err == nil {
				for _, carrier := range carriers {
					carrierMap[carrier.ID] = carrier.CarrierName
				}
			}
		}

		for _, card := range cards {
			cardInfos = append(cardInfos, dto.DeviceCardInfo{
				CardID:            card.ID,
				ICCID:             card.ICCID,
				MSISDN:            card.MSISDN,
				CarrierName:       carrierMap[card.CarrierID],
				NetworkStatus:     card.NetworkStatus,
				NetworkStatusName: getNetworkStatusName(card.NetworkStatus),
			})
		}
	}

	return &dto.EnterpriseDeviceDetailResp{
		Device: dto.EnterpriseDeviceInfo{
			DeviceID:     device.ID,
			DeviceNo:     device.DeviceNo,
			DeviceName:   device.DeviceName,
			DeviceModel:  device.DeviceModel,
			DeviceType:   device.DeviceType,
			AuthorizedAt: auth.AuthorizedAt,
		},
		Cards: cardInfos,
	}, nil
}

func (s *Service) SuspendCard(ctx context.Context, deviceID, cardID uint, req *dto.DeviceCardOperationReq) (*dto.DeviceCardOperationResp, error) {
	if err := s.validateCardOperation(ctx, deviceID, cardID); err != nil {
		return nil, err
	}

	skipCtx := pkggorm.SkipDataPermission(ctx)
	if err := s.db.WithContext(skipCtx).Model(&model.IotCard{}).
		Where("id = ?", cardID).
		Update("network_status", 0).Error; err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "停机操作失败")
	}

	return &dto.DeviceCardOperationResp{
		Success: true,
		Message: "停机成功",
	}, nil
}

func (s *Service) ResumeCard(ctx context.Context, deviceID, cardID uint, req *dto.DeviceCardOperationReq) (*dto.DeviceCardOperationResp, error) {
	if err := s.validateCardOperation(ctx, deviceID, cardID); err != nil {
		return nil, err
	}

	skipCtx := pkggorm.SkipDataPermission(ctx)
	if err := s.db.WithContext(skipCtx).Model(&model.IotCard{}).
		Where("id = ?", cardID).
		Update("network_status", 1).Error; err != nil {
		return nil, errors.Wrap(errors.CodeInternalError, err, "复机操作失败")
	}

	return &dto.DeviceCardOperationResp{
		Success: true,
		Message: "复机成功",
	}, nil
}

func (s *Service) validateCardOperation(ctx context.Context, deviceID, cardID uint) error {
	enterpriseID := middleware.GetEnterpriseIDFromContext(ctx)
	if enterpriseID == 0 {
		return errors.New(errors.CodeUnauthorized, "未授权访问")
	}

	auth, err := s.enterpriseDeviceAuthStore.GetByDeviceID(ctx, deviceID)
	if err != nil || auth.EnterpriseID != enterpriseID || auth.RevokedAt != nil {
		return errors.New(errors.CodeDeviceNotAuthorized, "设备未授权给此企业")
	}

	skipCtx := pkggorm.SkipDataPermission(ctx)

	var binding model.DeviceSimBinding
	if err := s.db.WithContext(skipCtx).
		Where("device_id = ? AND iot_card_id = ? AND bind_status = 1", deviceID, cardID).
		First(&binding).Error; err != nil {
		return errors.New(errors.CodeForbidden, "卡不属于该设备")
	}

	var cardAuth model.EnterpriseCardAuthorization
	if err := s.db.WithContext(skipCtx).
		Where("enterprise_id = ? AND card_id = ? AND device_auth_id IS NOT NULL AND revoked_at IS NULL", enterpriseID, cardID).
		First(&cardAuth).Error; err != nil {
		return errors.New(errors.CodeForbidden, "无权操作此卡")
	}

	return nil
}

func getNetworkStatusName(status int) string {
	if status == 1 {
		return "开机"
	}
	return "停机"
}
