package cn.iocoder.yudao.module.system.service.biz;

import cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil;
import cn.iocoder.yudao.framework.common.pojo.PageResult;
import cn.iocoder.yudao.framework.common.util.date.DateUtils;
import cn.iocoder.yudao.framework.common.util.object.BeanUtils;
import cn.iocoder.yudao.framework.mybatis.core.query.LambdaQueryWrapperX;
import cn.iocoder.yudao.framework.security.core.util.SecurityFrameworkUtils;
import cn.iocoder.yudao.framework.tenant.core.aop.TenantIgnore;
import cn.iocoder.yudao.framework.tenant.core.context.TenantContextHolder;
import cn.iocoder.yudao.module.system.controller.admin.biz.vo.*;
import cn.iocoder.yudao.module.system.dal.dataobject.biz.*;
import cn.iocoder.yudao.module.system.dal.mysql.biz.*;
import cn.iocoder.yudao.module.system.dal.mysql.tenant.TenantMapper;
import com.alibaba.fastjson.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.conditions.update.LambdaUpdateWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.google.common.collect.Maps;
import com.mzt.logapi.context.LogRecordContext;
import com.mzt.logapi.starter.annotation.LogRecord;
import lombok.extern.slf4j.Slf4j;
import org.springframework.context.annotation.Lazy;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import javax.annotation.Resource;
import javax.validation.constraints.NotNull;

import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;

import static cn.iocoder.yudao.framework.common.exception.util.ServiceExceptionUtil.exception;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.DEVICE_PRODUCT_NOT_EXISTS;
import static cn.iocoder.yudao.module.system.enums.ErrorCodeConstants.DEVICE_SHUIXIAOBAO_BIND_FAIL;
import static cn.iocoder.yudao.module.system.enums.LogRecordConstants.*;

/**
 * @Author: jinyd
 * @CreateTime: 2024/10/28  10:50
 * @Description:
 * @Version: 4.0
 */

@Slf4j
@Service
@Validated
public class DeviceProductServiceImpl implements DeviceProductService {

    @Resource
    private DeviceProductMapper productMapper;
    @Resource
    private TenantMapper tenantMapper;
    @Resource
    private DeviceModelMapper deviceModelMapper;
    @Resource
    private DeviceCategoryMapper categoryMapper;
    @Resource
    private ElderlyInfoMapper elderlyInfoMapper;
    @Resource
    @Lazy
    private SleepthingService sleepthingService;

    @Resource
    private DeviceWarnUserMapper deviceWarnUserMapper;

    @Override
    @LogRecord(type = DEVICE_PRODUCT_TYPE, subType = DEVICE_PRODUCT_CREATE_SUB_TYPE, bizNo = "{{#id}}",
            success = DEVICE_PRODUCT_CREATE_SUCCESS)
    public Long createProduct(DeviceProductSaveReqVO createReqVO) {
        Long modelId = createReqVO.getModelId();
        if (null != modelId) {
            DeviceModelDO deviceModelDO = deviceModelMapper.selectById(modelId);
            createReqVO.setDeviceManufacturerId(deviceModelDO.getDeviceManufacturerId());
            createReqVO.setDeviceManufacturerName(deviceModelDO.getDeviceManufacturerName());
            createReqVO.setDeviceType(deviceModelDO.getType());
            createReqVO.setDeviceModelName(deviceModelDO.getDeviceName());
            createReqVO.setModelName(deviceModelDO.getModelName());
            DeviceCategoryDO deviceCategoryDO = categoryMapper.selectById(deviceModelDO.getDeviceCategoryId());
            if(null != deviceCategoryDO) {
                createReqVO.setDeviceTypeName(deviceCategoryDO.getName());
            }
        }
        // 插入
        DeviceProductDO product = BeanUtils.toBean(createReqVO, DeviceProductDO.class);
        productMapper.insert(product);
        LogRecordContext.putVariable("id", product.getId());
        // 返回
        return product.getId();
    }

    @Override
    @LogRecord(type = DEVICE_PRODUCT_TYPE, subType = DEVICE_PRODUCT_UPDATE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
            success = DEVICE_PRODUCT_UPDATE_SUCCESS)
    public void updateProduct(DeviceProductSaveReqVO updateReqVO) {
        // 校验存在
        validateProductExists(updateReqVO.getId());
        DeviceProductDO deviceProductDO = productMapper.selectById(updateReqVO.getId());
        if (deviceProductDO.getModelId() != updateReqVO.getModelId()) {
            DeviceModelDO deviceModelDO = deviceModelMapper.selectById(updateReqVO.getModelId());
            updateReqVO.setDeviceManufacturerId(deviceModelDO.getDeviceManufacturerId());
            updateReqVO.setDeviceManufacturerName(deviceModelDO.getDeviceManufacturerName());
            updateReqVO.setDeviceType(deviceModelDO.getType());
            updateReqVO.setDeviceModelName(deviceModelDO.getDeviceName());
            updateReqVO.setModelName(deviceModelDO.getModelName());
            DeviceCategoryDO deviceCategoryDO = categoryMapper.selectById(deviceModelDO.getDeviceCategoryId());
            updateReqVO.setDeviceTypeName(deviceCategoryDO.getName());
        }
        // 更新
        DeviceProductDO updateObj = BeanUtils.toBean(updateReqVO, DeviceProductDO.class);
        productMapper.updateById(updateObj);
    }

    @Override
    @LogRecord(type = DEVICE_PRODUCT_TYPE, subType = DEVICE_PRODUCT_DELETE_SUB_TYPE, bizNo = "{{#id}}",
            success = DEVICE_PRODUCT_DELETE_SUCCESS)
    public void deleteProduct(Long id) {
        // 校验存在
        DeviceProductDO deviceProductDO = productMapper.selectById(id);
        if (deviceProductDO == null) {
            throw exception(DEVICE_PRODUCT_NOT_EXISTS);
        }
        // 删除
        productMapper.deleteById(id);
        LogRecordContext.putVariable("deviceName", deviceProductDO.getDeviceName());
    }

    private void validateProductExists(Long id) {
        if (productMapper.selectById(id) == null) {
            throw exception(DEVICE_PRODUCT_NOT_EXISTS);
        }
    }

    @Override
    public DeviceProductDO getProduct(Long id) {
        return productMapper.selectById(id);
    }

    @Override
    @TenantIgnore
    public PageResult<DeviceProductRespVO> getProductPage(DeviceProductPageReqVO pageReqVO) {

        Integer groupsManager = tenantMapper.checkGroupsManager(TenantContextHolder.getTenantId());
        if (null != groupsManager && 1 == groupsManager) {
            pageReqVO.setTenantId(null);
        } else {
            pageReqVO.setTenantId(TenantContextHolder.getTenantId());
        }
        Page<DeviceProductRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        List<DeviceProductRespVO> list = productMapper.getPage(page, pageReqVO);
        return new PageResult<>(list, page.getTotal());
    }

    @Override
    @TenantIgnore
    public PageResult<DeviceProductRespVO> getAllDeviceProductPage(DeviceProductPageReqVO pageReqVO) {
        Page<DeviceProductRespVO> page = new Page<>(pageReqVO.getPageNo(), pageReqVO.getPageSize());
        List<DeviceProductRespVO> list = productMapper.getAllDeviceProductPage(page, pageReqVO);
        return new PageResult<>(list, page.getTotal());
    }

    @Override
    public DeviceProductDetailVO getDetail(Long id) {
        DeviceProductDetailVO deviceProductDetailVO = productMapper.selectDetailById(id);
        return deviceProductDetailVO;
    }

    @Override
    public DeviceProductDO getByDeviceMac(String devID) {
        return productMapper.selectOne(new LambdaQueryWrapperX<DeviceProductDO>().eq(DeviceProductDO::getDeviceMac, devID));
    }

    @Override
    @LogRecord(type = DEVICE_PRODUCT_TYPE, subType = DEVICE_PRODUCT_DELETE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
            success = DEVICE_PRODUCT_DELETE_SUCCESS)
    public Integer bindDevice(BindingDeviceReqVO updateReqVO) {

        DeviceProductDO deviceProductDO = productMapper.selectById(updateReqVO.getId());

        updateReqVO.setBindingDate(LocalDateTime.now());
        updateReqVO.setBindingStatus(1);
        DeviceProductDO updateObj = BeanUtils.toBean(updateReqVO, DeviceProductDO.class);
        updateObj.setDeviceName(updateReqVO.getBindingUserName());
        //默认给睡小宝传个人信息
        if ("DEVICE_SHUIXIAOBAO".equals(deviceProductDO.getDeviceType())) {
            try {
                ElderlyInfoDO elderlyInfoDO = elderlyInfoMapper.selectById(updateReqVO.getBindingId());
                HashMap<String, Object> params = Maps.newHashMap();
                params.put("devID", deviceProductDO.getDeviceMac());
                if (elderlyInfoDO != null && elderlyInfoDO.getBirthday() != null) {
                    params.put("name",elderlyInfoDO.getElderName());
                    params.put("birthday", DateUtils.parseDateToStr("yyyy-MM-dd", elderlyInfoDO.getBirthday()));
                    params.put("gender", elderlyInfoDO.getElderSex() == 1 ? "男" : "女");
                }
                JSONObject jsonObject = null;
                if (deviceProductDO.getIsNew() != null && deviceProductDO.getIsNew() == 0) {
                    jsonObject = sleepthingService.bindUserBodyInfoOld(params);
                } else {
                    jsonObject = sleepthingService.bindUserBodyInfo(params);
                }
                String code = jsonObject.get("code") == null ? "" : jsonObject.get("code").toString();
                if (200 == Integer.valueOf(code)) {
                    log.info("设备绑定成功，设备编号："
                            + deviceProductDO.getDeviceMac() + "，绑定用户：" + updateReqVO.getBindingUserName());
                    //todo 睡小宝成功逻辑
                } else {
                    log.error("设备绑定失败，设备编号："
                            + deviceProductDO.getDeviceMac() + "，绑定用户：" + updateReqVO.getBindingUserName() + "，失败原因：" + jsonObject.get("msg"));
                    // 抛出业务异常
                    throw exception(DEVICE_SHUIXIAOBAO_BIND_FAIL);
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return productMapper.updateById(updateObj);
    }

    @Override
    @LogRecord(type = DEVICE_PRODUCT_TYPE, subType = DEVICE_PRODUCT_UNBIND_SUB_TYPE, bizNo = "{{#id}}",
            success = DEVICE_PRODUCT_UNBIND_SUCCESS)
    public Integer unbindDevice(Long id) {
        DeviceProductDO updateDevice = new DeviceProductDO();
        updateDevice.setId(id);
        updateDevice.setBindingStatus(0);

        DeviceProductDO deviceProductDO = productMapper.selectById(id);

        //默认给睡小宝传个人信息
        if ("DEVICE_SHUIXIAOBAO".equals(deviceProductDO.getDeviceType())) {
            try {
                ElderlyInfoDO elderlyInfoDO = elderlyInfoMapper.selectById(deviceProductDO.getBindingId());
                HashMap<String, Object> params = Maps.newHashMap();
                params.put("devID", deviceProductDO.getDeviceMac());
                if (elderlyInfoDO != null && elderlyInfoDO.getBirthday() != null) {
                    params.put("name",elderlyInfoDO.getElderName());
                    params.put("birthday", DateUtils.parseDateToStr("yyyy-MM-dd", elderlyInfoDO.getBirthday()));
                    params.put("gender", elderlyInfoDO.getElderSex() == 1 ? "男" : "女");
                }
                JSONObject jsonObject = null;
                if (deviceProductDO.getIsNew() != null && deviceProductDO.getIsNew() == 0) {
                    jsonObject = sleepthingService.bindUserBodyInfoOld(params);
                } else {
                    jsonObject = sleepthingService.bindUserBodyInfo(params);
                }
                String code = jsonObject.get("code") == null ? "" : jsonObject.get("code").toString();
                if (200 == Integer.valueOf(code)) {
                    log.info("设备绑定成功，设备编号："
                            + deviceProductDO.getDeviceMac() + "，绑定用户：" + deviceProductDO.getBindingUserName());

                } else {
                    log.error("设备绑定失败，设备编号："
                            + deviceProductDO.getDeviceMac() + "，绑定用户：" + deviceProductDO.getBindingUserName() + "，失败原因：" + jsonObject.get("msg"));
                }
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        productMapper.updateById(updateDevice);

        return null;
    }

    @Override
    public Boolean updateBatchBind(BindingAllDeviceReqVO updateReqVO) {
        Long[] ids = updateReqVO.getIds();
        for (int i = 0; i < ids.length; i++) {
            DeviceProductDO deviceProductDO = new DeviceProductDO();
            deviceProductDO.setId(ids[i]);
            deviceProductDO.setTenantId(0l);
            productMapper.updateById(deviceProductDO);
        }
        return Boolean.TRUE;
    }

    @Override
    @TenantIgnore
    @LogRecord(type = DEVICE_PRODUCT_TYPE, subType = DEVICE_PRODUCT_DELETE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
            success = DEVICE_PRODUCT_BATCH_BIND_SUCCESS)
    public Boolean groupBatchBind(BindingAllDeviceReqVO updateReqVO) {
        Long[] ids = updateReqVO.getIds();
        for (int i = 0; i < ids.length; i++) {
            DeviceProductDO deviceProductDO = new DeviceProductDO();
            deviceProductDO.setId(ids[i]);
            deviceProductDO.setTenantId(updateReqVO.getTenantId());
            productMapper.updateById(deviceProductDO);
        }
        return Boolean.TRUE;
    }

    @Override
    @TenantIgnore
    @LogRecord(type = DEVICE_PRODUCT_TYPE, subType = DEVICE_PRODUCT_DELETE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
            success = DEVICE_PRODUCT_BATCH_UNBIND_SUCCESS)
    public Boolean groupBatchUnbind(BindingAllDeviceReqVO updateReqVO) {
        Long[] ids = updateReqVO.getIds();
        for (int i = 0; i < ids.length; i++) {
            DeviceProductDO deviceProductDO = new DeviceProductDO();
            deviceProductDO.setId(ids[i]);
            deviceProductDO.setTenantId(0l);
            productMapper.updateById(deviceProductDO);
        }
        return Boolean.TRUE;
    }

    @Override
    @TenantIgnore
    @LogRecord(type = DEVICE_PRODUCT_TYPE, subType = DEVICE_PRODUCT_DELETE_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
            success = DEVICE_PRODUCT_BATCH_DELETE_SUCCESS)
    public Boolean groupBatchDelete(BindingAllDeviceReqVO updateReqVO) {
        Long[] ids = updateReqVO.getIds();
        for (int i = 0; i < ids.length; i++) {
            productMapper.update(new LambdaUpdateWrapper<DeviceProductDO>().set(DeviceProductDO::getDeleted, Boolean.TRUE).eq(DeviceProductDO::getId, ids[i]));
        }
        return Boolean.TRUE;
    }

    @Override
    public List<DeviceWarnUserDO> getWarnUserList(Long id) {
        return productMapper.selectWarnUser(id);
    }

    @Override
    @LogRecord(type = DEVICE_PRODUCT_TYPE, subType = DEVICE_PRODUCT_UPDATE_WARN_SUB_TYPE, bizNo = "{{#deviceWarnUserUpdateReqVO.id}}",
            success = DEVICE_PRODUCT_UPDATE_WARN_SUCCESS)
    public Boolean updateWarnUser(DeviceWarnUserUpdateReqVO deviceWarnUserUpdateReqVO) {
        Long id = deviceWarnUserUpdateReqVO.getId();
        deviceWarnUserMapper.delete(new LambdaQueryWrapperX<DeviceWarnUserDO>().eq(DeviceWarnUserDO::getDeviceProductId, id));
        Long[] userIdStr = deviceWarnUserUpdateReqVO.getUserIds();
        Long[] deptIdStr = deviceWarnUserUpdateReqVO.getDeptIds();
        if (null != userIdStr && userIdStr.length > 0) {
            for (int i = 0; i < userIdStr.length; i++) {
                DeviceWarnUserDO deviceWarnUserDO = new DeviceWarnUserDO();
                deviceWarnUserDO.setDeviceProductId(id);
                deviceWarnUserDO.setUserId(userIdStr[i]);
                deviceWarnUserDO.setType(0);
                deviceWarnUserMapper.insert(deviceWarnUserDO);
            }
        }

        if (null != deptIdStr && deptIdStr.length > 0) {
            for (int i = 0; i < deptIdStr.length; i++) {
                DeviceWarnUserDO deviceWarnUserDO = new DeviceWarnUserDO();
                deviceWarnUserDO.setDeviceProductId(id);
                deviceWarnUserDO.setDeptId(deptIdStr[i]);
                deviceWarnUserDO.setType(1);
                deviceWarnUserMapper.insert(deviceWarnUserDO);
            }
        }

        return Boolean.TRUE;
    }

    @Override
    @LogRecord(type = DEVICE_PRODUCT_TYPE, subType = DEVICE_PRODUCT_DELETE_WARN_SUB_TYPE, bizNo = "{{#updateReqVO.id}}",
            success = DEVICE_PRODUCT_DELETE_WARN_SUCCESS)
    public int delectWarnUserById(Long id) {
        return deviceWarnUserMapper.deleteById(id);
    }
}
