package com.bocloud.ims.service.scheduler.cloudbill.azure;

import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.bocloud.cmp.driver.common.BillingDriver;
import com.bocloud.cmp.model.PublicCloudBillModel;
import com.bocloud.cmp.model.azure.bill.AzureCloudBillModel;
import com.bocloud.cmp.model.azure.bill.BillPeriodModel;
import com.bocloud.common.model.BocloudResult;
import com.bocloud.ims.entity.resource.CloudBill;
import com.bocloud.ims.entity.resource.CloudVendor;
import com.bocloud.ims.repository.resource.CloudBillRepository;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.scheduling.concurrent.ThreadPoolTaskExecutor;
import org.springframework.stereotype.Component;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.CollectionUtils;
import org.springframework.util.StringUtils;

import java.text.SimpleDateFormat;
import java.util.Calendar;
import java.util.Date;
import java.util.List;
import java.util.Map;
import java.util.stream.Collectors;

/**
 * @Company: 博云 www.bocloud.com
 * @ClassName: AzureBillUtils
 * @Description:
 * @author: zhenpingLi/李振平
 * @date: 2021/9/14 15:25
 */
@Component
@Slf4j
public class AzureBillUtils {

    @Autowired
    private BillingDriver billingDriver;
    @Autowired
    private CloudBillRepository cloudBillRepository;
    @Autowired
    private ThreadPoolTaskExecutor taskExecutor;

    private String month;

    public AzureBillUtils() {
        SimpleDateFormat format = new SimpleDateFormat("yyyy-MM");
        Date date = new Date();
        Calendar calendar = Calendar.getInstance();
        calendar.setTime(date); // 设置为当前时间
        calendar.set(Calendar.MONTH, calendar.get(Calendar.MONTH) - 1); // 设置为上一个月
        date = calendar.getTime();
        this.month = format.format(date);
    }

    @Transactional(rollbackFor = Throwable.class)
    public void azureMonthBill(List<CloudVendor> vendors) {
        taskExecutor.execute(() -> {
            try {
                for (CloudVendor vendor : vendors) {
                    this.syncTenantMonthBill(vendor, this.month);
                }
            } catch (Exception e) {
                log.error("账单同步失败", e);
            }

        });
    }

    @Transactional(rollbackFor = Throwable.class)
    public void syncTenantMonthBill(CloudVendor vendor, String month) throws Exception {
        log.info("执行平台:{}->月份:{}->获取计费周期开始", vendor.getName(), month);
        BocloudResult billPeriodsResult = billingDriver.billPeriods(vendor.getUuid());
        if (billPeriodsResult.isFailed()) {
            log.info("获取计费周期失败，失败信息:" + billPeriodsResult.getMessage());
            throw new RuntimeException("获取计费周期失败，失败信息:" + billPeriodsResult.getMessage());
        }
        List<BillPeriodModel> billPeriodModels = JSONArray.parseArray(JSONObject.toJSONString(billPeriodsResult.getData()), BillPeriodModel.class);
        log.info("执行平台:{}->月份:{}->获取计费周期结束!->数据量:{}", vendor.getName(), month, billPeriodModels.size());
        Map<String, BillPeriodModel> periodModelMap = billPeriodModels.stream().collect(Collectors.toMap(periodModel -> periodModel.getName(), periodModel -> periodModel));
        String periodMonth = month.replaceAll("-", "");
        if (!periodModelMap.containsKey(periodMonth)) {
            log.info("不包含该月份的计费周期");
            throw new RuntimeException("不包含该月份的计费周期");
        }
        log.info("执行平台:{}->月份:{}->首次获取账单开始", vendor.getName(), month);
        BocloudResult periodPricesResult = billingDriver.periodPrices(vendor.getUuid(), periodModelMap.get(periodMonth).getUuid());
        if (periodPricesResult.isFailed()) {
            log.info("首次获取账单失败，失败信息:" + periodPricesResult.getMessage());
            throw new RuntimeException("首次获取账单失败，失败信息:" + periodPricesResult.getMessage());
        }
        AzureCloudBillModel azureCloudBillModel = JSONObject.parseObject(JSONObject.toJSONString(periodPricesResult.getData()), AzureCloudBillModel.class);
        log.info("执行平台:{}->月份:{}->首次获取账单结束！数据量:{}", vendor.getName(), month, azureCloudBillModel.getModels().size());

        log.info("执行平台:{}->月份:{}->删除本地数据开始", vendor.getName(), month);
        cloudBillRepository.removeByVid(vendor.getId(), month);
        log.info("执行平台:{}->月份:{}->删除本地数据结束", vendor.getName(), month);

        log.info("执行平台:{}->月份:{}->首次数据入库开始", vendor.getName(), month);
        this.syncBills(azureCloudBillModel.getModels(), vendor);
        log.info("执行平台:{}->月份:{}->首次数据入库结束", vendor.getName(), month);

        String nextLink = azureCloudBillModel.getNextLink();
        while (!StringUtils.isEmpty(nextLink)) {
            log.info("执行平台:{}->月份:{}->分页账单获取开始->url:{}", vendor.getName(), month, nextLink);
            BocloudResult nextLinkPricesResult = billingDriver.nextLinkPrices(vendor.getUuid(), nextLink);
            if (nextLinkPricesResult.isFailed()) {
                log.info("分页账单失败，url:{},失败信息:" + nextLinkPricesResult.getMessage(), nextLink);
                throw new RuntimeException("分页账单失败，失败信息:" + nextLinkPricesResult.getMessage());
            }
            AzureCloudBillModel nextLinkCloudBillModel = JSONObject.parseObject(JSONObject.toJSONString(nextLinkPricesResult.getData()), AzureCloudBillModel.class);
            log.info("执行平台:{}->月份:{}->分页账单获取数据量:{}", vendor.getName(), month, nextLinkCloudBillModel.getModels().size());

            log.info("执行平台:{}->月份:{}->分页数据入库开始", vendor.getName(), month);
            this.syncBills(nextLinkCloudBillModel.getModels(), vendor);
            log.info("执行平台:{}->月份:{}->分页数据入库结束", vendor.getName(), month);

            nextLink = nextLinkCloudBillModel.getNextLink();
            log.info("执行平台:{}->月份:{}->分页账单获取结束", vendor.getName(), month);
        }
        log.info("执行平台:{}->月份:{}->账单拉取成功！", vendor.getName(), month);
    }


    private void syncBills(List<PublicCloudBillModel> billModels, CloudVendor vendor) throws Exception {
        if (CollectionUtils.isEmpty(billModels)) {
            return;
        }
        for (PublicCloudBillModel model : billModels) {
            CloudBill cloudBill = new CloudBill();
            BeanUtils.copyProperties(model, cloudBill);
            cloudBill.setVendorId(vendor.getId());
            cloudBill.setMonth(month);
            cloudBill.setVendorType(vendor.getType());
            cloudBill.setOrderSn(cloudBill.getOrderSn());
            cloudBill.setStatus("paid"); // 已支付
            cloudBill.setChargeMode("PostCharge"); // 后付费
            cloudBill.setUnitPrice(model.getUnitPrice());
            cloudBillRepository.save(cloudBill);
        }
    }
}