package com.zhongshu.card.server.core.service.devices;

import com.beust.jcommander.internal.Lists;
import com.github.microservice.components.data.base.util.PageEntityUtil;
import com.github.microservice.models.device.DeviceInfoSyncParam;
import com.github.microservice.net.ResultContent;
import com.github.microservice.net.ResultMessage;
import com.zhongshu.card.client.model.devices.*;
import com.zhongshu.card.client.model.org.OrganizationMiniModel;
import com.zhongshu.card.client.model.org.UserJoinBusOrgModel;
import com.zhongshu.card.client.model.school.AreaSimpleModel;
import com.zhongshu.card.client.service.school.DeviceInfoService;
import com.zhongshu.card.client.type.OnLineState;
import com.zhongshu.card.server.core.dao.devices.DeviceInfoDao;
import com.zhongshu.card.server.core.dao.org.OrganizationDao;
import com.zhongshu.card.server.core.dao.school.AreaDao;
import com.zhongshu.card.server.core.dataConfig.DeviceConfig;
import com.zhongshu.card.server.core.domain.devices.DeviceInfo;
import com.zhongshu.card.server.core.domain.devices.permiss.DevicePermiss;
import com.zhongshu.card.server.core.domain.org.Organization;
import com.zhongshu.card.server.core.domain.school.Area;
import com.zhongshu.card.server.core.service.base.CommonService;
import com.zhongshu.card.server.core.service.base.SuperService;
import com.zhongshu.card.server.core.service.devices.permiss.DevicePermissEventService;
import com.zhongshu.card.server.core.service.org.OrganizationServiceImpl;
import com.zhongshu.card.server.core.service.orgManager.OrganizationManagerServiceImpl;
import com.zhongshu.card.server.core.service.paySetting.OrgPaySettingJudgmentService;
import com.zhongshu.card.server.core.service.school.AreaServiceImpl;
import com.zhongshu.card.server.core.util.BeanUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.data.domain.Page;
import org.springframework.data.domain.Pageable;
import org.springframework.stereotype.Service;
import org.springframework.util.Assert;

import java.util.ArrayList;
import java.util.Collections;
import java.util.HashMap;
import java.util.List;
import java.util.stream.Collectors;

/**
 * @author TRX
 * @date 2024/6/14
 */
@Slf4j
@Service
public class DeviceInfoServiceImpl extends SuperService implements DeviceInfoService {

    @Autowired
    private DeviceInfoDao deviceInfoDao;

    @Autowired
    private AreaServiceImpl areaService;

    @Autowired
    private AreaDao areaDao;

    @Autowired
    private OrganizationServiceImpl organizationServiceImpl;

    @Autowired
    private OrganizationDao organizationDao;

    @Autowired
    private OrganizationManagerServiceImpl organizationManagerService;

    @Autowired
    private CommonService commonService;

    @Autowired
    private OrgPaySettingJudgmentService orgPaySettingJudgmentService;

    @Autowired
    private DevicePermissEventService devicePermissEventService;

    /**
     * 同步设备 （设备基础信息）
     *
     * @param param
     * @return
     */
    @Override
    public ResultContent syncDeviceInfo(DeviceInfoSyncParam param) {
        Assert.hasText(param.getDeviceId(), "deviceId不能为空");
        // 设备号
        String deviceId = param.getDeviceId();
        DeviceInfo deviceInfo = deviceInfoDao.findTopByDeviceId(deviceId);
        if (ObjectUtils.isNotEmpty(deviceInfo)) {
            // 编辑 (不能再同步名称了，可能已改了)
            BeanUtils.copyProperties(param, deviceInfo, "id", "deviceName");
        } else {
            // 新增
            deviceInfo = new DeviceInfo();
            initEntityNoCheckOid(deviceInfo);
            BeanUtils.copyProperties(param, deviceInfo, "id");
        }
        deviceInfo.setProjectInfoName(organizationServiceImpl.getOrgNameByCode(param.getProjectInfoCode()));

        if (StringUtils.isNotEmpty(param.getProjectInfoCode())) {
            Organization projectInfo = organizationDao.findTopByOrgCode(param.getProjectInfoCode());
            if (ObjectUtils.isNotEmpty(projectInfo)) {
                deviceInfo.setProjectOid(projectInfo.getOid());
                deviceInfo.setAboutOid(projectInfo.getOid());
                deviceInfo.setAboutAuthType(projectInfo.getAuthType());
            }
        }
        deviceInfoDao.save(deviceInfo);

        // 修改其他的关联设备信息
        HashMap<String, Object> where = new HashMap<>();
        where.put("deviceId", param.getDeviceId());

        HashMap<String, Object> bindMap = new HashMap<>();
        bindMap.put("gateWayId", deviceInfo.getGateWayId());
        commonService.updateData(where, bindMap, DevicePermiss.class.getSimpleName());
        return ResultContent.buildSuccess();
    }

    /**
     * 添加-编辑设备
     *
     * @param param
     * @return
     */
    @Override
    public ResultContent addDeviceInfo(DeviceInfoParam param) {
        initDefaultUserAndOidNoExcept(param);
        Assert.hasText(param.getDeviceId(), "deviceId不能为空");
        String deviceId = param.getDeviceId();
        DeviceInfo deviceInfo = deviceInfoDao.findTopByDeviceId(deviceId);
        if (ObjectUtils.isNotEmpty(deviceInfo)) {
        } else {
            deviceInfo = new DeviceInfo();
        }
        BeanUtils.copyProperties(param, deviceInfo, "id");
        deviceInfo.setProjectInfoName(organizationServiceImpl.getOrgNameByCode(param.getProjectInfoCode()));
        deviceInfoDao.save(deviceInfo);

        devicePermissEventService.sendDeviceChangeEvent(deviceInfo.getDeviceId(), deviceInfo.getProjectOid(), "addDeviceInfo");
        return ResultContent.buildSuccess();
    }

    /**
     * 设备分页列表
     *
     * @param param
     * @param pageable
     * @return
     */
    @Override
    public ResultContent<Page<DeviceInfoModel>> page(DeviceInfoSearch param, Pageable pageable) {
        // 完善所属项目
        String projectOid = param.getProjectOid();
        if (StringUtils.isNotEmpty(projectOid)) {
            Organization organization = organizationDao.findTopByOid(projectOid);
            if (ObjectUtils.isEmpty(organization)) {
                return ResultContent.buildFail("projectOid不存在");
            }
            //TODO 放开查询所有的设备
            param.setProjectInfoCode(organization.getCode());
        }
        Page<DeviceInfo> page = deviceInfoDao.page(pageable, param);
        return ResultContent.buildSuccess(PageEntityUtil.concurrent2PageModel(page, this::toModel));
    }

    @Override
    public ResultContent<Page<DeviceInfoModel>> busPage(DeviceInfoSearch param, Pageable pageable) {
        // 完善所属项目
        String projectOid = param.getProjectOid();
        if (StringUtils.isEmpty(projectOid)) {
            projectOid = getCurrentProjectOid();
        }
        param.setProjectOid(projectOid);
        if (StringUtils.isEmpty(projectOid)) {
            return ResultContent.buildFail("projectOid不能为空");
        }

        List<String> shopOids = new ArrayList<String>();
        if (param.getIsAllBusinessMain() != null && param.getIsAllBusinessMain()) {
            List<UserJoinBusOrgModel> list = organizationServiceImpl.getUserAboutShopList(getCurrentUserId());
            if (ObjectUtils.isNotEmpty(list)) {
                shopOids = list.stream().map(it -> it.getBusOid()).collect(Collectors.toList());
            }
        } else {
            if (StringUtils.isNotEmpty(param.getShopOid())) {
                shopOids.add(param.getShopOid());
            }
        }
        if (ObjectUtils.isEmpty(shopOids)) {
            return ResultContent.buildFail("关联商户不存在");
        }
        param.setShopOids(shopOids);
        Page<DeviceInfo> page = deviceInfoDao.page(pageable, param);
        return ResultContent.buildSuccess(PageEntityUtil.concurrent2PageModel(page, this::toModel));
    }

    /**
     * 删除设备
     *
     * @param id
     * @return
     */
    @Override
    public ResultContent deleteDeviceInfo(String id) {
        DeviceInfo deviceInfo = deviceInfoDao.findTopById(id);
        if (ObjectUtils.isEmpty(deviceInfo)) {
            return ResultContent.buildFail(String.format(ResultMessage.DATA_NOT_EXIST, id));
        }
        deviceInfoDao.delete(deviceInfo);
        return ResultContent.buildSuccess();
    }

    /**
     * 得到设备详情
     *
     * @param id
     * @return
     */
    @Override
    public ResultContent<DeviceInfoMoreModel> getDeviceDetail(String id) {
        DeviceInfo deviceInfo = deviceInfoDao.findTopById(id);
        if (ObjectUtils.isEmpty(deviceInfo)) {
            return ResultContent.buildFail(String.format(ResultMessage.DATA_NOT_EXIST, id));
        }
        DeviceInfoMoreModel model = toMoreModel(deviceInfo);
        return ResultContent.buildSuccess(model);
    }

    @Override
    public ResultContent<DeviceInfoMoreModel> getDeviceDetailByDeviceId(String deviceId) {
        DeviceInfo deviceInfo = deviceInfoDao.findTopByDeviceId(deviceId);
        DeviceInfoMoreModel model = null;
        if (ObjectUtils.isNotEmpty(deviceInfo)) {
            model = toMoreModel(deviceInfo);
        }
        return ResultContent.buildSuccess(model);
    }

    @Override
    public ResultContent<List<DeviceInfoMoreModel>> getDeviceDetailByDeviceIdLike(String deviceId) {
        List<DeviceInfoMoreModel> models = new ArrayList<>();
        if (StringUtils.isNotEmpty(deviceId)) {
            List<DeviceInfo> list = deviceInfoDao.findTop10ByDeviceIdLike(deviceId);
            if (ObjectUtils.isNotEmpty(list)) {
                models = list.stream().map(this::toMoreModel).collect(Collectors.toList());
            }
        }
        return ResultContent.buildSuccess(models);
    }

    public DeviceInfoMoreModel toMoreModel(DeviceInfo entity) {
        DeviceInfoMoreModel model = null;
        if (ObjectUtils.isNotEmpty(entity)) {
            model = new DeviceInfoMoreModel();
            DeviceInfoModel deviceInfoModel = toModel(entity);
            BeanUtils.copyProperties(deviceInfoModel, model);
        }
        return model;
    }

    /**
     * @param param
     * @return
     */
    public ResultContent updateDevice(DeviceBindAreaParam param) {
        DeviceInfo deviceInfo = deviceInfoDao.findTopById(param.getId());
        if (ObjectUtils.isEmpty(deviceInfo)) {
            return ResultContent.buildFail(String.format(ResultMessage.DATA_NOT_EXIST, param.getId()));
        }
        Area area = null;
        List<String> strings = new ArrayList<>();
        // 修改设备 只能绑定 区域 所属机构等信息
        if (StringUtils.isNotEmpty(param.getAreaId())) {
            area = areaDao.findTopById(param.getAreaId());
            if (ObjectUtils.isEmpty(area)) {
                return ResultContent.buildFail("区域信息不存在");
            }
            strings = areaService.getAllParents(param.getAreaId());
        }
        if (ObjectUtils.isNotEmpty(area)) {
            deviceInfo.setArea(area);
            deviceInfo.setAreaId(area.getId());
        } else {
            deviceInfo.setArea(null);
            deviceInfo.setAreaId(null);
        }
        deviceInfo.setAreaPaths(String.join("/", strings));
        deviceInfo.setDeviceName(param.getDeviceName());

        // 设备所属机构
        Organization organization = null;
        if (StringUtils.isNotEmpty(param.getBeLongOid())) {
            organization = organizationDao.findTopByOid(param.getBeLongOid());
            if (ObjectUtils.isEmpty(organization)) {
                return ResultContent.buildFail("所属机构不存在");
            }
            deviceInfo.setBeLongName(organization.getName());
        }
        deviceInfo.setOrganization(organization);
        deviceInfo.setBeLongOid(param.getBeLongOid());

        if (StringUtils.isEmpty(deviceInfo.getProjectOid())) {
            Organization project = organizationDao.findTopByCode(deviceInfo.getProjectInfoCode());
            if (ObjectUtils.isNotEmpty(project)) {
                deviceInfo.setProjectOid(project.getOid());
            }
        }

        if (ObjectUtils.isNotEmpty(organization)) {
            // 检查设备关联的机构，是否可以收款
            ResultContent resultContent = orgPaySettingJudgmentService.checkOrgPaySetting(deviceInfo.getProjectOid(), deviceInfo.getBeLongOid());
            if (resultContent.isFailed()) {
                return ResultContent.buildFail(resultContent.getMsg());
            }
        }
        deviceInfo.setAboutInfo(param.getAboutInfo());

        deviceInfoDao.save(deviceInfo);

        devicePermissEventService.sendDeviceChangeEvent(deviceInfo.getDeviceId(), deviceInfo.getProjectOid(), "updateDevice");
        return ResultContent.buildSuccess();
    }

    /**
     * 查询设备所属机构（设备绑定的那个机构）
     *
     * @param deviceId
     * @return
     */
    public Organization getDeviceBelongTo(String deviceId) {
        Organization organization = null;
        if (StringUtils.isNotEmpty(deviceId)) {
            DeviceInfo deviceInfo = deviceInfoDao.findTopById(deviceId);
            if (ObjectUtils.isNotEmpty(deviceInfo)) {
                organization = deviceInfo.getOrganization();
            }
        }
        return organization;
    }

    /**
     * 启动平台时检查设备 （有些设备没有使用了，没有改变在线状态）
     */
    public void initCheckDeviceOnLine() {
        List<DeviceInfo> list = deviceInfoDao.findAll();
        if (ObjectUtils.isNotEmpty(list)) {
            long maxTime = DeviceConfig.maxInitCheckDeviceLineStateTime;
            List<DeviceInfo> deviceInfos = new ArrayList<>();
            for (DeviceInfo deviceInfo : list) {
                if (deviceInfo.getLastOnlineTime() == null || (System.currentTimeMillis() - deviceInfo.getLastOnlineTime()) > maxTime) {
                    deviceInfo.setOnLineState(OnLineState.OffLine);
                    deviceInfos.add(deviceInfo);
                }
            }
            if (ObjectUtils.isNotEmpty(deviceInfos)) {
                deviceInfoDao.saveAll(deviceInfos);
            }
        }
    }

    /**
     * 得到、封装设备的扩展信息
     *
     * @param deviceId
     */
    public void getDeviceAboutInfo(String deviceId) {
        DeviceInfo deviceInfo = deviceInfoDao.findTopById(deviceId);
        if (ObjectUtils.isNotEmpty(deviceInfo)) {

        }
    }

    public List<DeviceInfo> getDevicesByDeviceIds(List<String> deviceIds) {
        if (ObjectUtils.isNotEmpty(deviceIds)) {
            return deviceInfoDao.findByDeviceIdIn(deviceIds);
        }
        return Lists.newArrayList();
    }

    /**
     * 设备基础信息
     *
     * @param entity
     * @return
     */
    public DeviceInfoModel toModel(DeviceInfo entity) {
        DeviceInfoModel model = null;
        if (ObjectUtils.isNotEmpty(entity)) {
            model = new DeviceInfoModel();
            // 所属机构信息
            OrganizationMiniModel miniModel = organizationManagerService.toMiniModel(entity.getOrganization());
            model.setOrganization(miniModel);

            BeanUtils.copyProperties(entity, model);
            model.setProjectInfoName(organizationServiceImpl.getOrgNameByCode(entity.getProjectInfoCode()));

            // 所属区域信息
            List<AreaSimpleModel> areaModels = areaService.getParents(entity.getArea());
            if (ObjectUtils.isNotEmpty(areaModels)) {
                model.setArea(areaModels.get(0));
                Collections.reverse(areaModels);
                List<String> areaNames = areaModels.stream().map(it -> it.getName()).collect(Collectors.toList());
                model.setAreaAllName(String.join("/", areaNames));
            }
        }
        return model;
    }

    public DeviceInfoStoreModel toStoreModel(DeviceInfo entity) {
        DeviceInfoStoreModel model = null;
        if (ObjectUtils.isNotEmpty(entity)) {
            model = new DeviceInfoStoreModel();
            BeanUtils.copyProperties(entity, model);

            model.setProjectInfoName(organizationServiceImpl.getOrgNameByCode(entity.getProjectInfoCode()));

            // 所属区域信息
            List<AreaSimpleModel> areaModels = areaService.getParents(entity.getArea());
            if (ObjectUtils.isNotEmpty(areaModels)) {
                model.setArea(areaModels.get(0));
                Collections.reverse(areaModels);
                List<String> areaNames = areaModels.stream().map(it -> it.getName()).collect(Collectors.toList());
                model.setAreaAllName(String.join("/", areaNames));
            }
        }
        return model;
    }

    /**
     * 设备信息  简单模型
     *
     * @param entity
     * @return
     */
    public DeviceInfoSimpleModel toSimpleModel(DeviceInfo entity) {
        DeviceInfoSimpleModel model = null;
        if (ObjectUtils.isNotEmpty(entity)) {
            model = new DeviceInfoSimpleModel();
            BeanUtils.copyProperties(entity, model);
        }
        return model;
    }
}
