package com.yeejoin.equipmanage.utils;


import com.yeejoin.equipmanage.common.datasync.entity.*;
import com.yeejoin.equipmanage.common.datasync.entity.publics.SyncDataMessage;
import com.yeejoin.equipmanage.common.datasync.enums.SyncDataOperationEnum;
import com.yeejoin.equipmanage.common.datasync.enums.SyncDataTextEnum;
import com.yeejoin.equipmanage.common.datasync.enums.SyncDataTypeEnum;
import com.yeejoin.equipmanage.common.entity.FormInstance;
import com.yeejoin.equipmanage.common.entity.vo.CarPropertyVo;
import com.yeejoin.equipmanage.common.entity.vo.EquipmentIndexVO;
import com.yeejoin.equipmanage.common.utils.ConverterUtil;
import com.yeejoin.equipmanage.common.utils.DateUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.BeanUtils;

import java.io.Serializable;
import java.util.*;
import java.util.stream.Collectors;

/**
 * <h1>实体转换为同步消息对象</h1>
 *
 * @Author SingleTian
 * @Date 2021-04-01 11:17
 */
public class SyncDataUtil {

    public static <T> SyncDataMessage buildSyncMessage(T data, SyncDataOperationEnum operation) {
        return buildSyncMessage(Arrays.asList(data), operation);
    }

    public static <T> SyncDataMessage buildSyncMessage(T data, SyncDataOperationEnum operation, String sign) {
        return buildSyncMessage(Arrays.asList(data), operation, sign);
    }

    public static <T> SyncDataMessage buildSyncMessage(Collection<T> list, SyncDataOperationEnum operation) {
        T t = list.stream().findFirst().orElse(null);
        SyncDataTypeEnum type = getDataType(t, "");
        List<Serializable> data = transData(list, type);
        SyncDataMessage message = new SyncDataMessage();
        message.setUid(UUID.randomUUID().toString());
        message.setTimestamp(System.currentTimeMillis());
        message.setOperation(operation);
        message.setType(type);
        message.setData(data);
        return message;
    }

    public static <T> SyncDataMessage buildSyncMessage(Collection<T> list, SyncDataOperationEnum operation, String sign) {
        T t = list.stream().findFirst().orElse(null);
        SyncDataTypeEnum type = getDataType(t, sign);
        List<Serializable> data = transData(list, type);
        SyncDataMessage message = new SyncDataMessage();
        message.setUid(UUID.randomUUID().toString());
        message.setTimestamp(System.currentTimeMillis());
        message.setOperation(operation);
        message.setType(type);
        message.setData(data);
        return message;
    }

    private static <T> SyncDataTypeEnum getDataType(T t, String sign) {
        if (t instanceof FireEquipment) {
            return SyncDataTypeEnum.AST_FIRE_EQUIP;
        } else if ("isNotIot".equalsIgnoreCase(sign) && (t instanceof EquipmentIndexVO)) {
            return SyncDataTypeEnum.AST_FIRE_EQUIP_INFO;
        } else if ("isIot".equalsIgnoreCase(sign) && (t instanceof EquipmentIndexVO)) {
            return SyncDataTypeEnum.AST_FIRE_EQUIP_MEASUREMENT;
        } else if (t instanceof FireVehicle) {
            return SyncDataTypeEnum.AST_FIRE_VEHICLE;
        } else if ("isNotIot".equalsIgnoreCase(sign) && (t instanceof CarPropertyVo)) {
            return SyncDataTypeEnum.AST_FIRE_VEHICLE_INFO;
        } else if ("isIot".equalsIgnoreCase(sign) && (t instanceof CarPropertyVo)) {
            return SyncDataTypeEnum.AST_FIRE_VEHICLE_MEASUREMENT;
        } else if ("building".equalsIgnoreCase(sign) && (t instanceof FormInstance)) {
            return SyncDataTypeEnum.AST_BUILDING;
        } else if ("floor".equalsIgnoreCase(sign) && (t instanceof FormInstance)) {
            return SyncDataTypeEnum.AST_FLOOR;
        } else if ("room".equalsIgnoreCase(sign) && (t instanceof FormInstance)) {
            return SyncDataTypeEnum.AST_ROOM;
        } else if (t instanceof FireFightingSystem) {
            return SyncDataTypeEnum.AST_FIRE_FIGHTING;
        } else if (t instanceof FireEquipmentFireAlarm) {
            return SyncDataTypeEnum.AST_FIRE_EQUIP_ALARM;
        } else if (t instanceof FireEquipmentFaultAlarm) {
            return SyncDataTypeEnum.AST_FIRE_EQUIP_FAULT_ALARM;
        } else if (t instanceof FireEquipmentDefectAlarm) {
            return SyncDataTypeEnum.AST_FIRE_EQUIP_DEFECT_ALARM;
        } else {
            throw new RuntimeException("无法识别的类型");
        }
    }

    private static List<Serializable> transData(Collection list, SyncDataTypeEnum type) {
        switch (type) {
            case AST_BUILDING: {
                return buildingData(list);
            }
            case AST_FLOOR: {
                return floorData(list);
            }
            case AST_ROOM: {
                return roomData(list);
            }
            case AST_FIRE_EQUIP: {
                return equipSpecificData(list);
            }
            case AST_FIRE_EQUIP_INFO: {
                return equipSpecificInfoData(list);
            }
            case AST_FIRE_EQUIP_MEASUREMENT: {
                return equipMeasurementData(list);
            }
            case AST_FIRE_EQUIP_ALARM: {
                return equipSpecificAlarmData(list);
            }
            case AST_FIRE_EQUIP_FAULT_ALARM: {
                return equipSpecificFaultAlarmData(list);
            }
            case AST_FIRE_EQUIP_DEFECT_ALARM: {
                return equipSpecificDefectAlarmData(list);
            }
            case AST_FIRE_VEHICLE: {
                return fireVehicleData(list);
            }
            case AST_FIRE_VEHICLE_INFO: {
                return fireVehicleInfoData(list);
            }
            case AST_FIRE_VEHICLE_MEASUREMENT: {
                return fireVehicleMeasurementData(list);
            }
            case AST_FIRE_FIGHTING: {
                return fireFightingSystemData(list);
            }
            default:
                return new ArrayList<>();
        }
    }

    private static List<Building> buildingData(Collection<FormInstance> list) {
        List<Building> buildingList = new ArrayList<>();
        Building building = new Building();
        list.stream().forEach(i -> {
            String fieldName = i.getFieldName();
            Long instanceId = i.getInstanceId();
            String groupCode = i.getGroupCode();
            building.setId(String.valueOf(instanceId));
            building.setType(groupCode);
            if (StringUtils.isNotBlank(fieldName)) {
                String fieldValue = i.getFieldValue();
                switch (fieldName) {
                    case "code":
                        building.setMRid(fieldValue);
                        break;
                    case "name":
                        building.setName(fieldValue);
                        break;
                    case "height":
                        building.setHeight(ConverterUtil.getAsBigDecimal(fieldValue));
                        break;
                    case "floorArea":
                        building.setArea(ConverterUtil.getAsBigDecimal(fieldValue));
                        break;
                    case "bottomArea":
                        building.setArea(ConverterUtil.getAsBigDecimal(fieldValue));
                        break;
                    case "designUnit":
                        building.setDesignUnit(fieldValue);
                        break;
                    case "constructionUnit":
                        building.setConstructionUnit(fieldValue);
                        break;
                    case "buildUseType":
                        building.setUsePurpose(fieldValue);
                        break;
                    case "buildDate":
                        building.setBuildDate(DateUtils.longStr2Date(fieldValue));
                        break;
                    case "upperPlies":
                        building.setAbovegroundFloors(StringUtils.isNotBlank(fieldValue) ? Integer.parseInt(fieldValue) : null);
                        break;
                    case "lowerPlies":
                        building.setUndergroundFloors(StringUtils.isNotBlank(fieldValue) ? Integer.parseInt(fieldValue) : null);
                        break;
                    case "riskPointId":
                        building.setRegionId(fieldValue);
                        break;
                    case "lowWaterHeight":
                        building.setInferiorLimit(fieldValue);
                        break;
                    default:
                }
            }
        });
        buildingList.add(building);
        return buildingList;
    }

    private static List<Floor> floorData(Collection<FormInstance> list) {
        List<Floor> floorList = new ArrayList<>();
        Floor floor = new Floor();
        list.stream().forEach(i -> {
            String fieldName = i.getFieldName();
            Long instanceId = i.getInstanceId();
            floor.setId(String.valueOf(instanceId));
            if (StringUtils.isNotBlank(fieldName)) {
                String fieldValue = i.getFieldValue();
                switch (fieldName) {
                    case "code":
                        floor.setMRid(fieldValue);
                        break;
                    case "name":
                        floor.setName(fieldValue);
                        break;
                    case "inwhichBuild":
                        floor.setBuildingId(fieldValue);
                        break;
                    default:
                }
            }
        });
        floorList.add(floor);
        return floorList;
    }

    private static List<Room> roomData(Collection<FormInstance> list) {
        List<Room> roomList = new ArrayList<>();
        Room room = new Room();
        list.stream().forEach(i -> {
            String fieldName = i.getFieldName();
            Long instanceId = i.getInstanceId();
            room.setId(String.valueOf(instanceId));
            if (StringUtils.isNotBlank(fieldName)) {
                String fieldValue = i.getFieldValue();
                switch (fieldName) {
                    case "code":
                        room.setMRid(fieldValue);
                        break;
                    case "name":
                        room.setName(fieldValue);
                        break;
                    case "inwhichBuild":
                        room.setBuildingId(fieldValue);
                        break;
                    case "riskPointId":
                        room.setRegionId(fieldValue);
                        break;
                    case "height":
                        room.setHeight(ConverterUtil.getAsBigDecimal(fieldValue));
                        break;
                    default:
                }
            }
        });
        roomList.add(room);
        return roomList;
    }

    private static List<Serializable> equipSpecificData(Collection<FireEquipment> list) {
        return list.stream().map(i -> {
            FireEquipment fireEquipment = new FireEquipment();
            BeanUtils.copyProperties(i, fireEquipment);
            return fireEquipment;
        }).collect(Collectors.toList());
    }

    private static List<Serializable> equipSpecificInfoData(Collection<EquipmentIndexVO> list) {
        return list.stream().map(i -> new FireEquipmentInfo()
                .setId(String.valueOf(i.getId()))
                .setCreateDate(i.getCreateDate())
                .setDataType(SyncDataTextEnum.DATA_TYPE_TEXT.getText())
                .setFieldLabel(i.getPerfQuotaName())
                .setFieldName(i.getNameKey())
                .setFireEquipmentId(i.getEquipmentId())
                .setIsMust(Boolean.FALSE)
                .setMeasureUnit(i.getUnitName())
                .setSort(i.getSortNum())
                .setUpdateDate(i.getUpdateDate())
                .setValue(i.getValue())
                .setMrid(i.getIndexId())
                .setName(i.getPerfQuotaName())
                .setAliasname(i.getPerfQuotaName())
        ).collect(Collectors.toList());
    }

    private static List<Serializable> equipMeasurementData(Collection<EquipmentIndexVO> list) {
        return list.stream().map(i -> {
                    FireEquipMeasurement fireEquipMeasurement = new FireEquipMeasurement();
                    String unitName = i.getUnitName();
                    if (StringUtils.isNotBlank(unitName)) {
                        fireEquipMeasurement.setType(SyncDataTextEnum.IOT_SWITCH.getText());
                    } else {
                        fireEquipMeasurement.setType(SyncDataTextEnum.IOT_ANALOG.getText());
                    }
                    fireEquipMeasurement.setId(String.valueOf(i.getId()));
                    fireEquipMeasurement.setCreateDate(i.getCreateDate());
                    fireEquipMeasurement.setDataType(SyncDataTextEnum.DATA_TYPE_TEXT.getText());
                    fireEquipMeasurement.setFieldLabel(i.getPerfQuotaName());
                    fireEquipMeasurement.setFieldName(i.getNameKey());
                    fireEquipMeasurement.setFireEquipmentId(i.getEquipmentId());
                    fireEquipMeasurement.setMeasureUnit(unitName);
                    fireEquipMeasurement.setSort(i.getSortNum());
                    fireEquipMeasurement.setUpdateDate(i.getUpdateDate());
                    fireEquipMeasurement.setValue(i.getValue());
                    fireEquipMeasurement.setTypeCode(i.getTypeCode());
                    fireEquipMeasurement.setTypeName(i.getTypeName());
                    fireEquipMeasurement.setMRid(i.getTypeCode());
                    return fireEquipMeasurement;
                }
        ).collect(Collectors.toList());
    }

    private static List<Serializable> equipSpecificAlarmData(Collection<FireEquipmentFireAlarm> list) {
        return list.stream().map(i -> {
                    FireEquipmentFireAlarm fireEquipmentAlarm = new FireEquipmentFireAlarm();
                    BeanUtils.copyProperties(i, fireEquipmentAlarm);
                    return fireEquipmentAlarm;
                }
        ).collect(Collectors.toList());
    }

    private static List<Serializable> equipSpecificFaultAlarmData(Collection<FireEquipmentFaultAlarm> list) {
        return list.stream().map(i -> {
                    FireEquipmentFaultAlarm fireEquipmentAlarm = new FireEquipmentFaultAlarm();
                    BeanUtils.copyProperties(i, fireEquipmentAlarm);
                    return fireEquipmentAlarm;
                }
        ).collect(Collectors.toList());
    }

    private static List<Serializable> equipSpecificDefectAlarmData(Collection<FireEquipmentDefectAlarm> list) {
        return list.stream().map(i -> {
                    FireEquipmentDefectAlarm fireEquipmentAlarm = new FireEquipmentDefectAlarm();
                    BeanUtils.copyProperties(i, fireEquipmentAlarm);
                    return fireEquipmentAlarm;
                }
        ).collect(Collectors.toList());
    }

    private static List<Serializable> fireVehicleData(Collection<FireVehicle> list) {
        return list.stream().map(i -> {
                    FireVehicle fireVehicle = new FireVehicle();
                    BeanUtils.copyProperties(i, fireVehicle);
                    return fireVehicle;
                }
        ).collect(Collectors.toList());
    }

    private static List<Serializable> fireVehicleInfoData(Collection<CarPropertyVo> list) {
        return list.stream().map(i -> {
                    FireVehicleInfo fireVehicleInfo = new FireVehicleInfo();
                    fireVehicleInfo.setId(String.valueOf(i.getId()));
                    fireVehicleInfo.setFireVehicleId(String.valueOf(i.getCarId()));
                    fireVehicleInfo.setCreateDate(i.getCreateDate());
                    fireVehicleInfo.setDataType(SyncDataTextEnum.DATA_TYPE_TEXT.getText());
                    fireVehicleInfo.setFieldLabel(i.getNameKey());
                    fireVehicleInfo.setFieldName(i.getName());
                    fireVehicleInfo.setIsMust(false);
                    fireVehicleInfo.setMeasureUnit(i.getUnit());
                    fireVehicleInfo.setSort(i.getSort());
                    fireVehicleInfo.setUpdateDate(new Date());
                    fireVehicleInfo.setValue(i.getValue());
                    fireVehicleInfo.setAliasname(i.getName());
                    fireVehicleInfo.setMrid(i.getMRid());
                    return fireVehicleInfo;
                }
        ).collect(Collectors.toList());
    }

    private static List<Serializable> fireVehicleMeasurementData(Collection<CarPropertyVo> list) {
        return list.stream().map(i -> {
                    FireVehicleMeasurement fireVehicleMeasurement = new FireVehicleMeasurement();
                    String unitName = i.getUnit();
                    if (StringUtils.isNotBlank(unitName)) {
                        fireVehicleMeasurement.setType(SyncDataTextEnum.IOT_SWITCH.getText());
                    } else {
                        fireVehicleMeasurement.setType(SyncDataTextEnum.IOT_ANALOG.getText());
                    }
                    fireVehicleMeasurement.setId(String.valueOf(i.getId()));
                    fireVehicleMeasurement.setFireVehicleId(String.valueOf(i.getCarId()));
                    fireVehicleMeasurement.setCreateDate(i.getCreateDate());
                    fireVehicleMeasurement.setDataType(SyncDataTextEnum.DATA_TYPE_TEXT.getText());
                    fireVehicleMeasurement.setFieldLabel(i.getNameKey());
                    fireVehicleMeasurement.setFieldName(i.getName());
                    fireVehicleMeasurement.setMeasureUnit(unitName);
                    fireVehicleMeasurement.setSort(i.getSort());
                    fireVehicleMeasurement.setUpdateDate(new Date());
                    fireVehicleMeasurement.setValue(i.getValue());
                    return fireVehicleMeasurement;
                }
        ).collect(Collectors.toList());
    }

    private static List<Serializable> fireFightingSystemData(Collection<FireFightingSystem> list) {
        return list.stream().map(i -> {
                    FireFightingSystem fireFightingSystem = new FireFightingSystem();
                    BeanUtils.copyProperties(i, fireFightingSystem);
                    return fireFightingSystem;
                }
        ).collect(Collectors.toList());
    }

}
