package com.bocloud.ims.service.resource.f5;

import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.f5.F5DeviceManagementDriver;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.interfaces.resource.f5.F5DeviceOverviewService;
import com.bocloud.ims.repository.resource.CloudVendorRepository;
import com.google.common.collect.Lists;
import com.google.common.collect.Maps;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;

import java.text.SimpleDateFormat;
import java.util.*;

/**
 * f5主备overview数据展示
 * Created by liuyuanyuan on 2019/5/6 15:29
 */
@Service("f5DeviceOverviewService")
public class F5DeviceOverviewServiceImpl implements F5DeviceOverviewService {
    private static final Logger logger = LoggerFactory.getLogger(F5DeviceOverviewServiceImpl.class);
    @Autowired
    private F5DeviceManagementDriver f5DeviceManagementDriver;
    @Autowired
    private CloudVendorRepository cloudVendorRepository;

    @Override
    public BocloudResult list(Long vendorId) {
        CloudVendor vendor;
        try {
            vendor = cloudVendorRepository.query(vendorId);
            BocloudResult result = f5DeviceManagementDriver.syncStats(vendor.getUuid(), "");
            if (result.isSuccess()) {
                List<Object> resultData = Lists.newArrayList();
                // 获取device group操作状态
                JSONObject entries = JSONObject.parseObject(result.getMessage()).getJSONObject("entries")
                        .getJSONObject("https://localhost/mgmt/tm/cm/sync-status/0").getJSONObject("nestedStats")
                        .getJSONObject("entries");
                String summary = entries.getJSONObject("summary").getString("description");
                String syncStatus = entries.getJSONObject("status").getString("description");
                String mode = entries.getJSONObject("mode").getString("description");
                String color = entries.getJSONObject("color").getString("description");
                String syncData01 = null;
                String syncData02 = null;
                String syncData03 = null;
                String syncData04 = null;
                if (!"blue".equals(color)) {
                    // 获取同步的数据提示
                    syncData01 = getSyncData(entries, 0);
                    syncData02 = getSyncData(entries, 1);
                    syncData03 = getSyncData(entries, 2);
                    syncData04 = getSyncData(entries, 3);
                } else {
                    syncData01 = getSyncData(entries, 0);
                }
                String syncStats = null;
                String status = null;
                String summaryData = null;
                String syncStatusData = null;
                if (!"standalone".equals(mode)) {
                    // 同步状态
                    switch (color) {
                        case "green":
                            syncStats = "In Sync";
                            status = "In Sync";
                            summaryData = summary + "There are no changes pending.";
                            syncStatusData = syncStatus;
                            break;
                        case "yellow":
                        case "red":
                            syncStats = "Sync Issues";
                            status = "Changes Pending";
                            syncStatusData = syncStatus;
                            break;
                        case "blue":
                            if ("Disconnected".equals(syncStatus)) {
                                syncStats = "In Sync";
                                status = "In Sync";
                                syncStatusData = syncStatus;
                            }
                            break;
                        default:
                            return new BocloudResult(false, "纳管设备中存在未兼容的同步状态！");
                    }
                }
                // 获取主备状态
                BocloudResult deviceResult = f5DeviceManagementDriver.device(vendor.getUuid(), "");
                if (deviceResult.isFailed()) {
                    logger.error(deviceResult.getMessage());
                    return new BocloudResult(false, "查询device失败！");
                }
                List<JSONObject> devicesData = JSONObject.parseObject(deviceResult.getMessage()).getJSONArray("items")
                        .toJavaList(JSONObject.class);
                String masterName = null;
                String currentDevice = null;
                for (JSONObject device : devicesData) {
                    if ("192.168.1.245".equals(device.getString("managementIp"))
                            || "192.168.245.245".equals(device.getString("managementIp"))) {
                        return new BocloudResult(false, "暂不支持未初始化出厂管理IP{"
                                + device.get("managementIp") + "}的设备");
                    }
                    String managementIp = "https://" + device.getString("managementIp");
                    JSONObject authentication = JSONObject.parseObject(vendor.getAuthentication());
                    String address = authentication.getString("address");
                    if (address.contains("443")) {
                        managementIp += ":443";
                    }
                    if ("active".equals(device.getString("failoverState"))) {
                        masterName = device.getString("name");
                    }
                    if (managementIp.equals(address)) {
                        currentDevice = device.getString("name");
                    }
                }
                if (null == masterName) {
                    return new BocloudResult(false, "获取主设备失败,请检查主备设备配置是否正常!");
                }
                // 获取关联的主备device
                BocloudResult deviceGroupResult = f5DeviceManagementDriver.deviceGroup(vendor.getUuid(), "");
                if (deviceGroupResult.isFailed()) {
                    logger.error(deviceGroupResult.getMessage());
                    return new BocloudResult(false, "查询device group失败！");
                }
                List<JSONObject> deviceGroups = JSONObject.parseObject(deviceGroupResult.getMessage())
                        .getJSONArray("items").toJavaList(JSONObject.class);
                for (JSONObject deviceGroup : deviceGroups) {
                    Map<String, Object> groupMap = Maps.newHashMap();
                    String name = deviceGroup.getString("name");
                    if (!"gtm".equals(name)) {
                        groupMap.put("name", name);
                        // device group状态
                        switch (name) {
                            // 内置默认group
                            case "device_trust_group":
                                if ("standalone".equals(mode)) {
                                    groupMap.put("syncStats", "In Sync");
                                    groupMap.put("status", syncStatus);
                                    groupMap.put("color", color);
                                    groupMap.put("syncStatusData", syncStatus);
                                } else {
                                    groupMap.put("syncStats", "In Sync");
                                    groupMap.put("status", "In Sync");
                                    groupMap.put("color", "green");
                                    groupMap.put("summaryData", "All devices are in sync. There are no changes pending.");
                                    groupMap.put("syncStatusData", "In Sync");
                                }
                                break;
                            default:
                                if ("blue".equals(color)) {
                                    groupMap.put("syncStats", syncStats);
                                    groupMap.put("status", status);
                                    groupMap.put("color", color);
                                    groupMap.put("syncStatusData", syncStatusData);
                                    groupMap.put("summaryData", summaryData);
                                } else {
                                    if (null != syncData02) {
                                        if (name.equals(StringUtils.substringBefore(syncData02, "(").trim())) {
                                            groupMap.put("syncStats", syncStats);
                                            groupMap.put("status", status);
                                            groupMap.put("color", color);
                                            switch (color) {
                                                case "green":
                                                    groupMap.put("summaryData", summaryData);
                                                    break;
                                                case "red":
                                                    groupMap.put("warning", summary);
                                                    groupMap.put("summaryData", syncData03);
                                                    break;
                                                case "yellow":
                                                    if (null != syncData04) {
                                                        syncData03 += syncData04;
                                                    }
                                                    groupMap.put("summaryData", syncData03);
                                                    break;
                                                default:
                                                    break;
                                            }
                                            groupMap.put("syncStatusData", syncStatusData);
                                        } else {
                                            groupMap.put("syncStats", "In Sync");
                                            groupMap.put("status", "In Sync");
                                            groupMap.put("color", "green");
                                            groupMap.put("summaryData",
                                                    "All devices are in sync. There are no changes pending.");
                                            groupMap.put("syncStatusData", "In Sync");
                                        }
                                        if (name.equals(StringUtils.substringBefore(syncData02, "(").trim())) {
                                            groupMap.put("syncStats", syncStats);
                                            groupMap.put("status", status);
                                            groupMap.put("color", color);
                                            switch (color) {
                                                case "green":
                                                    groupMap.put("summaryData", summaryData);
                                                    break;
                                                case "red":
                                                    groupMap.put("warning", summary);
                                                    groupMap.put("summaryData", syncData03);
                                                    break;
                                                case "yellow":
                                                    if (null != syncData04) {
                                                        syncData03 += syncData04;
                                                    }
                                                    groupMap.put("summaryData", syncData03);
                                                    break;
                                                default:
                                                    break;
                                            }
                                            groupMap.put("syncStatusData", syncStatusData);
                                        } else {
                                            groupMap.put("syncStats", "In Sync");
                                            groupMap.put("status", "In Sync");
                                            groupMap.put("color", "green");
                                            groupMap.put("summaryData",
                                                    "All devices are in sync. There are no changes pending.");
                                            groupMap.put("syncStatusData", "In Sync");
                                        }
                                    }
                                }
                                break;
                        }
                        // 解析group类型
                        switch (deviceGroup.getString("type")) {
                            case "sync-failover":
                                groupMap.put("type", "Sync-Failover Group");
                                break;
                            case "sync-only":
                                groupMap.put("type", "Sync-Only Group");
                                break;
                            default:
                                return new BocloudResult(false, "纳管设备中存在未兼容的device group类型！");
                        }
                        // 同步类型
                        Boolean autoSync = Boolean.parseBoolean(deviceGroup.getString("autoSync")
                                .replaceAll("enabled", "true").replaceAll("disabled", "false"));
                        if (autoSync) {
                            groupMap.put("autoSync", "Auto Sync");
                        } else {
                            groupMap.put("autoSync", "Manual Sync");
                        }
                        // group下device的数量
                        BocloudResult devicesResult = f5DeviceManagementDriver.deviceGroup(vendor.getUuid(),
                                name + "/devices");
                        if (devicesResult.isFailed()) {
                            logger.error(devicesResult.getMessage());
                            return new BocloudResult(false, "查询devices group devices失败！");
                        }
                        List<JSONObject> devices = JSONObject.parseObject(devicesResult.getMessage())
                                .getJSONArray("items").toJavaList(JSONObject.class);
                        if (0 == devices.size()) {
                            continue;
                        }
                        groupMap.put("deviceCount", devices.size() + "Devices");
                        // 上次同步时间
                        BocloudResult syncResult = f5DeviceManagementDriver.deviceGroup(vendor.getUuid(),
                                name + "/stats");
                        if (syncResult.isFailed()) {
                            logger.error(syncResult.getMessage());
                            return new BocloudResult(false, "查询devices group syncData失败！");
                        }
                        JSONObject entriesData = JSONObject.parseObject(syncResult.getMessage())
                                .getJSONObject("entries");
                        String deviceName = devices.get(0).getString("name");
                        JSONObject nestedStats = entriesData.getJSONObject("https://localhost/mgmt/tm/cm/device-group/"
                                + name + "/~Common~" + name + ":~Common~" + deviceName + "/stats")
                                .getJSONObject("nestedStats");
                        String lssTime = nestedStats.getJSONObject("entries").getJSONObject("lssTime")
                                .getString("description");
                        // 格式化为国内时间
                        if (!"standalone".equals(mode)) {
                            String date = lssTime.equals("-") ? "-" : formatting(lssTime);
                            groupMap.put("lssTime", "In sync on " + date);
                        } else {
                            groupMap.put("lssTime", "The device is in the Standalone state");
                        }
                        // 获取数据变更的device
                        List<String> deviceNames = Lists.newArrayList();
                        Boolean isDisconnected = false;
                        String disconnectedName = null;
                        if (!"blue".equals(color)) {
                            if (null != syncData02) {
                                if (name.equals(StringUtils.substringBefore(syncData02, "(").trim())) {
                                    if ("Changes Pending".equals(syncStatus)) {
                                        String changesDeviceName = StringUtils.substringBefore(StringUtils
                                                .substringAfter(syncData03, " - Recommended action: Synchronize"), "to")
                                                .trim();
                                        deviceNames.add(changesDeviceName);
                                    }
                                    if (-1 != summary.indexOf("There is a possible change conflict between")) {
                                        String[] names = StringUtils
                                                .substringBefore(StringUtils.substringAfter(summary,
                                                        "There is a possible change conflict between"), ".")
                                                .replaceAll(" ", "").split("and");
                                        for (String string : names) {
                                            deviceNames.add(string);
                                        }
                                    }
                                }
                            }
                        } else {
                            disconnectedName = StringUtils.substringBefore(syncData01, ":").trim();
                            isDisconnected = true;
                        }
                        // 构建group中device的数据
                        List<Object> deviceList = Lists.newArrayList();
                        for (JSONObject device : devices) {
                            Boolean isChanges = false;
                            Map<String, Object> deviceStatsMap = Maps.newHashMap();
                            JSONObject deviceStats = entriesData
                                    .getJSONObject("https://localhost/mgmt/tm/cm/device-group/" + name + "/~Common~"
                                            + name + ":~Common~" + device.getString("name") + "/stats")
                                    .getJSONObject("nestedStats").getJSONObject("entries");
                            // 标记当前设备
                            if (currentDevice.equals(device.getString("name"))) {
                                deviceStatsMap.put("name", device.getString("name") + "(Self)");
                            } else {
                                deviceStatsMap.put("name", device.getString("name"));
                            }
                            if (masterName.equals(device.getString("name"))) {
                                deviceStatsMap.put("HA_status", "active");
                            } else {
                                deviceStatsMap.put("HA_status", "standby");
                            }
                            if (isDisconnected) {
                                if (device.getString("name").equals(disconnectedName)) {
                                    deviceStatsMap.put("syncStatus", "Disconnected");
                                } else {
                                    deviceStatsMap.put("syncStatus", "In Sync");
                                }
                            } else {
                                if (!deviceNames.isEmpty()) {
                                    for (String string : deviceNames) {
                                        if (string.equals(device.getString("name"))) {
                                            deviceStatsMap.put("syncStatus", "Changes Pending");
                                            isChanges = true;
                                        }
                                    }
                                    if (!isChanges) {
                                        deviceStatsMap.put("syncStatus", "In Sync");
                                    }
                                } else {
                                    deviceStatsMap.put("syncStatus", "In Sync");
                                }
                            }
                            if (!"device_trust_group".equals(name) && null != syncData03) {
                                // 检测提示语是否为初始化同步
                                String changeName = StringUtils.substringBefore(syncData01, ":").trim();
                                if (changeName.equals(device.getString("name"))) {
                                    if (" - 1 devices with older configuration - Recommended action: Synchronize this device to group sync_failover_group"
                                            .equals(syncData03)) {
                                        deviceStatsMap.put("syncStatus", "Does not have the last synced configuration");
                                    }
                                }
                            }
                            if ("-".equals(deviceStats.getJSONObject("commitIdTime").getString("description"))) {
                                deviceStatsMap.put("currentCommitTime", "-");
                            } else {
                                deviceStatsMap.put("currentCommitTime",
                                        formatting(deviceStats.getJSONObject("commitIdTime").getString("description")));
                            }
                            if ("-".equals(deviceStats.getJSONObject("commitIdOriginator").getString("description"))) {
                                deviceStatsMap.put("currentCommitOriginator", "-");
                            } else {
                                deviceStatsMap
                                        .put("currentCommitOriginator",
                                                StringUtils.substringAfter(deviceStats
                                                                .getJSONObject("commitIdOriginator").getString("description"),
                                                        "/Common/"));
                            }
                            if ("-".equals(deviceStats.getJSONObject("lssTime").getString("description"))) {
                                deviceStatsMap.put("previousCommitTime", "-");
                            } else {
                                deviceStatsMap.put("previousCommitTime",
                                        formatting(deviceStats.getJSONObject("lssTime").getString("description")));
                            }
                            if ("-".equals(deviceStats.getJSONObject("lssOriginator").getString("description"))) {
                                deviceStatsMap.put("previousCommitOriginator", "-");
                            } else {
                                deviceStatsMap.put("previousCommitOriginator",
                                        StringUtils.substringAfter(
                                                deviceStats.getJSONObject("lssOriginator").getString("description"),
                                                "/Common/"));
                            }
                            if ("-".equals(deviceStats.getJSONObject("timeSinceLastSync").getString("description"))) {
                                deviceStatsMap.put("deviceLastSyncTime", "no value set");
                            } else {
                                long timeSinceLastSync = Long.valueOf(
                                        deviceStats.getJSONObject("timeSinceLastSync").getString("description")) * 1000;
                                deviceStatsMap.put("deviceLastSyncTime", duration(timeSinceLastSync));
                            }
                            String lastSyncType = deviceStats.getJSONObject("lastSyncType").getString("description");
                            switch (lastSyncType) {
                                case "full-load-manual-sync":
                                    lastSyncType = "Manual Full Load";
                                    break;
                                case "incremental-manual-sync":
                                    lastSyncType = "Manual Incremental";
                                    break;
                                case "incremental-auto-sync":
                                    lastSyncType = "Auto Incremental";
                                    break;
                                case "full-load-auto-sync":
                                    lastSyncType = "Auto Full Load";
                                    break;
                                case "none":
                                    lastSyncType = "None";
                                    break;
                                default:
                                    return new BocloudResult(false, "纳管设备中存在未兼容的Device Last Sync Type！");
                            }
                            deviceStatsMap.put("deviceLastSyncType", lastSyncType);
                            deviceList.add(deviceStatsMap);
                        }
                        groupMap.put("devices", deviceList);
                        resultData.add(groupMap);
                    }
                }
                return new BocloudResult(true, resultData, "查询成功");
            } else {
                logger.error(result.getMessage());
                return new BocloudResult(false, "获取f5主备同步信息失败！");
            }
        } catch (Exception e) {
            logger.error("Overview data fail:", e);
            return new BocloudResult(false, "查询失败");
        }
    }

    private String duration(long different) {
        long secondsInMilli = 1000;
        long minutesInMilli = secondsInMilli * 60;
        long hoursInMilli = minutesInMilli * 60;
        long daysInMilli = hoursInMilli * 24;
        long elapsedDays = different / daysInMilli;
        different = different % daysInMilli;
        long elapsedHours = different / hoursInMilli;
        different = different % hoursInMilli;
        long elapsedMinutes = different / minutesInMilli;
        different = different % minutesInMilli;
        long elapsedSeconds = different / secondsInMilli;
        String str = String.format("%d天%d小时%d分钟%d秒", elapsedDays, elapsedHours, elapsedMinutes, elapsedSeconds);
        str = str.replace("0天0小时0分钟", "");
        str = str.replace("0天0小时", "");
        str = str.replace("0天", "");
        return str;
    }

    /**
     * 获取同步结果数据
     *
     * @param entries
     * @param number
     * @return
     */
    public String getSyncData(JSONObject entries, int number) {
        JSONObject jsonObject = entries.getJSONObject("https://localhost/mgmt/tm/cm/syncStatus/0/details")
                .getJSONObject("nestedStats").getJSONObject("entries")
                .getJSONObject("https://localhost/mgmt/tm/cm/syncStatus/0/details/" + number);
        if (null != jsonObject) {
            return entries.getJSONObject("https://localhost/mgmt/tm/cm/syncStatus/0/details")
                    .getJSONObject("nestedStats").getJSONObject("entries")
                    .getJSONObject("https://localhost/mgmt/tm/cm/syncStatus/0/details/" + number)
                    .getJSONObject("nestedStats").getJSONObject("entries").getJSONObject("details")
                    .getString("description");
        } else {
            return null;
        }
    }

    /**
     * 格式化时间
     *
     * @param time
     * @return
     * @throws Exception
     */
    public String formatting(String time) throws Exception {
        SimpleDateFormat simpleDateFormat = new SimpleDateFormat("yyyy-MMM-dd HH:mm:ss", Locale.ENGLISH);
        simpleDateFormat.setTimeZone(TimeZone.getTimeZone("UTC"));
        Date date = simpleDateFormat.parse(time);
        SimpleDateFormat format = new SimpleDateFormat("MM/dd/yyyy HH:mm:ss");
        String formatDate = format.format(date);
        return formatDate;
    }

    @Override
    public BocloudResult sync(Long vendorId, String deviceGroupName) {
        try {
            CloudVendor vendor = cloudVendorRepository.query(vendorId);
            BocloudResult syncStats = f5DeviceManagementDriver.syncStats(vendor.getUuid(), "");
            if (syncStats.isFailed()) {
                logger.error(syncStats.getMessage());
                return new BocloudResult(false, "同步失败");
            }
            JSONObject entries = JSONObject.parseObject(syncStats.getMessage()).getJSONObject("entries")
                    .getJSONObject("https://localhost/mgmt/tm/cm/sync-status/0").getJSONObject("nestedStats")
                    .getJSONObject("entries");
            String syncStatus = entries.getJSONObject("status").getString("description");
            if ("Disconnected".equals(syncStatus)) {
                return new BocloudResult(false,
                        "One or more devices are unreachable.Resolve any communication problems berfore attempting to sync.");
            }
            JSONObject params = new JSONObject();
            params.put("command", "run");
            String utilCmdArgs = "config-sync to-group " + deviceGroupName;
            params.put("utilCmdArgs", utilCmdArgs);
            BocloudResult bocloudResult = f5DeviceManagementDriver.sync(vendor.getUuid(), params);
            if (bocloudResult.isFailed()) {
                logger.error(bocloudResult.getMessage());
                return new BocloudResult(false, bocloudResult.getMessage());
            }
            return new BocloudResult(true, "主备同步成功");
        } catch (Exception e) {
            logger.error(e.getMessage());
            return new BocloudResult(false, "主备同步失败！");
        }
    }
}
