package com.bocloud.ims.service.resource.azure.prices;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.params.azure.AzureListPriceParams;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.ims.entity.resource.Flavor;
import com.bocloud.ims.interfaces.resource.azure.prices.AzurePriceService;
import com.bocloud.ims.repository.resource.FlavorRepository;
import com.bocloud.ims.service.resource.azure.utils.AzurePriceProviderUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Service;
import org.springframework.util.ObjectUtils;
import org.springframework.util.StringUtils;

import java.util.*;
import java.util.regex.Matcher;
import java.util.regex.Pattern;
import java.util.stream.Collectors;

/**
 * @Company: 博云 www.bocloud.com
 * @ClassName: AzurePriceServiceImpl
 * @Description:
 * @author: zhenpingLi/李振平
 * @date: 2021/1/6 15:14
 */
@Service("azurePriceService")
public class AzurePriceServiceImpl implements AzurePriceService {

    private static final Logger logger = LoggerFactory.getLogger(AzurePriceServiceImpl.class);
    @Autowired
    private AzurePriceProviderUtils priceProvider;
    @Autowired
    private FlavorRepository flavorRepository;

    @Override
    public BocloudResult mysqlStorage(AzureListPriceParams params) {
        try {
            String dbFlavorUuid = params.getUuid();
            String regionId = params.getRegionId();
            String skuName;
            switch (dbFlavorUuid) {
                case "Basic":
                    skuName = "Basic";
                    break;
                case "GeneralPurpose":
                    skuName = "General Purpose";
                    break;
                case "MemoryOptimized":
                    skuName = "General Purpose";
                    break;
                default:
                    skuName = "General Purpose";
                    break;

            }

            String productName;
            switch (dbFlavorUuid) {
                case "Basic":
                    productName = "Azure Database for MySQL Single Server Basic - Storage";
                    break;
                case "GeneralPurpose":
                    productName = "Azure Database for MySQL Single Server General Purpose - Storage";
                    break;
                case "MemoryOptimized":
                    productName = "Azure Database for MySQL Single Server General Purpose - Storage";
                    break;
                default:
                    productName = "Azure Database for MySQL Single Server Basic - Storage";
                    break;

            }
            String api = "/api/retail/prices";
            String queryParams = new StringBuffer()
                    .append("serviceName eq 'Azure Database for MySQL'")
                    .append(" and priceType eq 'Consumption'")
                    .append(" and armRegionName eq ")
                    .append("'")
                    .append(regionId)
                    .append("'")
                    .append(" and skuName eq ")
                    .append("'")
                    .append(skuName)
                    .append("'")
                    .append(" and productName eq ")
                    .append("'")
                    .append(productName)
                    .append("'")
                    .append("  and unitOfMeasure eq '1 GB/Month' ")
                    .toString();
            JSONObject paramsJson = new JSONObject();
            paramsJson.put("$filter", queryParams);
            String response = priceProvider.request(AzurePriceProviderUtils.RequestStatus.GET, api, paramsJson.toJSONString());
            List<JSONObject> objects = Optional.ofNullable(JSONObject.parseObject(response))
                    .map(responseJson -> Optional.ofNullable(responseJson.getJSONArray("Items")).map(items -> items.stream()
                            .map(JSONArray::toJSONString)
                            .map(JSONObject::parseObject)
                            .collect(Collectors.toList())).orElse(new ArrayList<>())
                    ).orElse(new ArrayList<>());
            return new BocloudResult(true, objects, "查询成功");
        } catch (Exception e) {
            logger.error("Query error:", e);
            return new BocloudResult(false, "查询失败");
        }
    }

    @Override
    public BocloudResult mysqlVcore(AzureListPriceParams params) {
        try {
            String dbFlavorUuid = params.getUuid();
            String regionId = params.getRegionId();

            String productName;
            switch (dbFlavorUuid) {
                case "Basic":
                    productName = " and productName eq  'Azure Database for MySQL Single Server Basic - Compute Gen5'";
                    break;
                case "GeneralPurpose":
                    productName = " and productName eq 'Azure Database for MySQL Single Server General Purpose - Compute Gen5'";
                    break;
                case "MemoryOptimized":
                    productName = " and productName eq 'Azure Database for MySQL Single Server Memory Optimized - Compute Gen5'";
                    break;
                default:
                    productName = " and productName eq  'Azure Database for MySQL Single Server Basic - Compute Gen5'";
                    break;

            }
            String api = "/api/retail/prices";
            String queryParams = new StringBuffer()
                    .append("serviceName eq 'Azure Database for MySQL'")
                    .append(" and priceType eq 'Consumption'")
                    .append(" and armRegionName eq ")
                    .append("'")
                    .append(regionId)
                    .append("'")
                    .append(" and meterName eq 'vCore'")
                    .append(productName)
                    .toString();
            JSONObject paramsJson = new JSONObject();
            paramsJson.put("$filter", queryParams);
            String response = priceProvider.request(AzurePriceProviderUtils.RequestStatus.GET, api, paramsJson.toJSONString());
            List<JSONObject> objects = Optional.ofNullable(JSONObject.parseObject(response))
                    .map(responseJson -> Optional.ofNullable(responseJson.getJSONArray("Items")).map(items -> items.stream()
                            .map(JSONArray::toJSONString)
                            .map(JSONObject::parseObject)
                            .collect(Collectors.toList())).orElse(new ArrayList<>())
                    ).orElse(new ArrayList<>());
            return new BocloudResult(true, objects, "查询成功");
        } catch (Exception e) {
            logger.error("Query error:", e);
            return new BocloudResult(false, "查询失败");
        }
    }

    @Override
    public BocloudResult flavors(AzureListPriceParams params) {
        try {
            Long flavorId = params.getFlavorId();
            Flavor flavor = flavorRepository.query(flavorId);
            String osCategory = params.getOsCategory();
            if (ObjectUtils.isEmpty(flavor)) {
                return new BocloudResult(false, "规格找不到");
            }
            String armRegionName = flavor.getRegionId();
            String armSkuName = flavor.getName();

            String api = "/api/retail/prices";
            //eg:serviceName eq 'Virtual Machines' and armRegionName eq 'eastus2' and armSkuName eq 'Standard_B2s' and priceType eq 'Consumption' and skuName eq 'B2s'
            String queryParams = new StringBuffer()
                    .append("serviceName eq 'Virtual Machines'")
                    .append(" and priceType eq 'Consumption'")
                    .append(" and armRegionName eq ")
                    .append("'")
                    .append(armRegionName)
                    .append("'")
                    .append(" and armSkuName eq ")
                    .append("'")
                    .append(armSkuName)
                    .append("'")
                    .toString();
            JSONObject paramsJson = new JSONObject();
            paramsJson.put("$filter", queryParams);
            String response = priceProvider.request(AzurePriceProviderUtils.RequestStatus.GET, api, paramsJson.toJSONString());
            List<JSONObject> objects = Optional.ofNullable(JSONObject.parseObject(response))
                    .map(responseJson -> Optional.ofNullable(responseJson.getJSONArray("Items")).map(items -> items.stream()
                            .map(JSONArray::toJSONString)
                            .map(JSONObject::parseObject)
                            .collect(Collectors.toList())).orElse(new ArrayList<>())
                    ).orElse(new ArrayList<>());

            //数据二次处理
            List<JSONObject> newObject = new ArrayList<>();
            for (JSONObject jsonObject : objects) {
                if (jsonObject.getString("skuName").contains("Low") || jsonObject.getString("skuName").contains("Spot")) {
                    continue;
                }
                if (osCategory.equalsIgnoreCase("WINDOWS")) {
                    if (jsonObject.getString("productName").contains("Windows")) {
                        newObject.add(jsonObject);
                    }
                } else {
                    if (!jsonObject.getString("productName").contains("Windows")) {
                        newObject.add(jsonObject);
                    }
                }
            }
            return new BocloudResult(true, newObject, "查询成功");
        } catch (Exception e) {
            logger.error("Query error:", e);
            return new BocloudResult(false, "查询失败");
        }
    }

    @Override
    public BocloudResult volumes(AzureListPriceParams params) {
        try {
            Map<String, String> map = new HashMap<String, String>();
            //标准 HDD
            map.put("Standard_LRS", "Standard HDD Managed Disks");
            //标准 SSD
            map.put("StandardSSD_LRS", "Standard SSD Managed Disks");
            //高级 SSD
            map.put("Premium_LRS", "Premium SSD Managed Disks");
            
            String skuPattern = "^[PES]([0-9]|[0-9][0-9])\\sLRS";
            String meterPattern = "^[PES]([0-9]|[0-9][0-9])\\sDisks";
            Map<String, Integer> maps = new HashMap<String, Integer>();
            maps.put("1", 4);
            maps.put("2", 8);
            maps.put("3", 16);
            maps.put("4", 32);
            maps.put("6", 64);
            maps.put("10", 128);
            maps.put("15", 256);
            maps.put("20", 512);
            maps.put("30", 1024);
            maps.put("40", 2048);
            maps.put("50", 4096);
            maps.put("60", 8192);
            maps.put("70", 16384);
            maps.put("80", 32768);
            String category = params.getCategory();
            String regionId = params.getRegionId();
            String api = "/api/retail/prices";
            String queryParams = new StringBuffer()
                    .append("serviceName eq 'Storage'")
                    .append(" and priceType eq 'Consumption'")
                    .append(" and armRegionName eq ")
                    .append("'")
                    .append(regionId)
                    .append("'")
                    .append(" and productName eq ")
                    .append("'")
                    .append(map.get(category))
                    .append("'")
                    .append(" and isPrimaryMeterRegion eq true ")
                    .toString();
            JSONObject paramsJson = new JSONObject();
            paramsJson.put("$filter", queryParams);
            String response = priceProvider.request(AzurePriceProviderUtils.RequestStatus.GET, api, paramsJson.toJSONString());
            List<JSONObject> objects = Optional.ofNullable(JSONObject.parseObject(response))
                    .map(responseJson -> Optional.ofNullable(responseJson.getJSONArray("Items")).map(items -> items.stream()
                            .map(JSONArray::toJSONString)
                            .map(JSONObject::parseObject)
                            .collect(Collectors.toList())).orElse(new ArrayList<>())
                    ).orElse(new ArrayList<>());

            //数据过滤
            List<JSONObject> newObjects = new ArrayList<>();
            for (JSONObject jsonObject : objects) {
                boolean b = Pattern.matches(skuPattern, jsonObject.getString("skuName"));
                boolean m = Pattern.matches(meterPattern, jsonObject.getString("meterName"));
                if (b && m) {
                    Integer size = this.getVolumeSize(jsonObject.getString("skuName"), maps);
                    if (null != size) {
                        jsonObject.put("size", size);
                        newObjects.add(jsonObject);
                    }
                }
            }
            //数据排序
            for (int i = 0; i < newObjects.size(); i++) {
                for (int j = newObjects.size() - 1; j > i; j--) {
                    JSONObject objectI = newObjects.get(i);
                    JSONObject objectJ = newObjects.get(j);
                    Integer getI = objectI.getInteger("size");
                    Integer getJ = objectJ.getInteger("size");
                    if (getI > getJ) {
                        newObjects.set(i, objectJ);
                        newObjects.set(j, objectI);
                    }
                }
            }
            return new BocloudResult(true, newObjects, "查询成功");
        } catch (Exception e) {
            logger.error("Query error:", e);
            return new BocloudResult(false, "查询失败");
        }
    }

    @Override
    public BocloudResult eips(AzureListPriceParams params) {
        try {
            String ipCategory = params.getCategory();
            String sku = StringUtils.isEmpty(params.getSku()) ? "Standard" : params.getSku();//Basic\Standard

            Map<String, String> categoryMap;
            if (sku.equalsIgnoreCase("Basic")) {
                categoryMap = new HashMap<String, String>();
                //静态eip
                categoryMap.put("static", "Static Public IP");
                //动态eip
                categoryMap.put("dynamic", "Dynamic Public IP");
            } else {
                //标准不支持 动态EIP
                categoryMap = new HashMap<String, String>();
                //静态eip
                categoryMap.put("static", "Standard Static Public IP");
            }

            String api = "/api/retail/prices";
            String queryParams = new StringBuffer()
                    .append("serviceName eq 'Virtual Network'")
                    .append(" and priceType eq 'Consumption'")
                    .append(" and productName eq 'IP Addresses'")
                    .append(" and skuName eq ")
                    .append("'")
                    .append(sku)
                    .append("'")
                    .append(" and meterName eq ")
                    .append("'")
                    .append(categoryMap.get(ipCategory))
                    .append("'")
                    .toString();
            JSONObject paramsJson = new JSONObject();
            paramsJson.put("$filter", queryParams);
            String response = priceProvider.request(AzurePriceProviderUtils.RequestStatus.GET, api, paramsJson.toJSONString());
            List<JSONObject> objects = Optional.ofNullable(JSONObject.parseObject(response))
                    .map(responseJson -> Optional.ofNullable(responseJson.getJSONArray("Items")).map(items -> items.stream()
                            .map(JSONArray::toJSONString)
                            .map(JSONObject::parseObject)
                            .collect(Collectors.toList())).orElse(new ArrayList<>())
                    ).orElse(new ArrayList<>());
            return new BocloudResult(true, objects, "查询成功");
        } catch (Exception e) {
            logger.error("Query error:", e);
            return new BocloudResult(false, "查询失败");
        }
    }

    @Override
    public BocloudResult redis(AzureListPriceParams params) {
        try {
            String skuPattern = "^[CP]([0-9])";
            String meterPattern = "^[CP]([0-9])\\sCache";
            String regionId = params.getRegionId();
            String skuName = params.getSkuName();
            String productName = params.getProductName();
            String api = "/api/retail/prices";
            String queryParams = new StringBuffer()
                    .append("serviceName eq 'Redis Cache'")
                    .append(" and priceType eq 'Consumption'")
                    .append(" and armRegionName eq ")
                    .append("'")
                    .append(regionId)
                    .append("'")
                    .append(" and skuName eq ")
                    .append("'")
                    .append(skuName)
                    .append("'")
                    .append(" and productName eq ")
                    .append("'")
                    .append(productName)
                    .append("'")
                    .toString();
            JSONObject paramsJson = new JSONObject();
            paramsJson.put("$filter", queryParams);
            String response = priceProvider.request(AzurePriceProviderUtils.RequestStatus.GET, api, paramsJson.toJSONString());
            List<JSONObject> objects = Optional.ofNullable(JSONObject.parseObject(response))
                    .map(responseJson -> Optional.ofNullable(responseJson.getJSONArray("Items")).map(items -> items.stream()
                            .map(JSONArray::toJSONString)
                            .map(JSONObject::parseObject)
                            .collect(Collectors.toList())).orElse(new ArrayList<>())
                    ).orElse(new ArrayList<>());

            //数据过滤
            List<JSONObject> newObjects = new ArrayList<>();
            for (JSONObject jsonObject : objects) {
                boolean b = Pattern.matches(skuPattern, jsonObject.getString("skuName"));
                boolean m = Pattern.matches(meterPattern, jsonObject.getString("meterName"));
                if (b && m) {
                    newObjects.add(jsonObject);
                }
            }
            return new BocloudResult(true, newObjects, "查询成功");
        } catch (Exception e) {
            logger.error("Query error:", e);
            return new BocloudResult(false, "查询失败");
        }
    }

    private Integer getVolumeSize(String skuName, Map<String, Integer> maps) {
        String pattern = "[^0-9]";
        Pattern p = Pattern.compile(pattern);
        Matcher m = p.matcher(skuName);
        String trim = m.replaceAll("").trim();
        return maps.get(trim);
    }

}