/*
 * 文 件 名:  WeatherColAmapServiceImpl
 * 版    权:
 * 描    述:  <描述>
 * 修 改 人:  learshaw
 * 修改时间:  2021/9/22
 * 跟踪单号:  <跟踪单号>
 * 修改单号:  <修改单号>
 * 修改内容:  <修改内容>
 */
package com.huashe.common.data.service.impl;

import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.huashe.common.data.service.RegionService;
import com.huashe.common.domain.model.Region;
import com.huashe.common.domain.model.WeatherForecast;
import com.huashe.common.domain.model.WeatherRt;
import com.huashe.common.exception.Assert;
import com.huashe.common.data.config.AmapWeatherConfig;
import com.huashe.common.data.mapper.AdmWeatherForecastMapper;
import com.huashe.common.data.mapper.AdmWeatherRtMapper;
import com.huashe.common.data.service.WeatherColService;
import com.huashe.common.utils.HttpUtils;
import com.huashe.common.utils.ThreadUtils;
import org.apache.commons.collections4.CollectionUtils;
import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.boot.autoconfigure.condition.ConditionalOnProperty;
import org.springframework.stereotype.Service;

import javax.annotation.Resource;
import java.util.ArrayList;
import java.util.Date;
import java.util.List;

/**
 * 天气实时采集-高德
 * <功能详细描述>
 *
 * @author learshaw
 * @version [版本号, 2021/9/22]
 * @see [相关类/方法]
 * @since [产品/模块版本]
 */
@Service("weatherColAmapService")
@ConditionalOnProperty(prefix = "weather", name = "service-provider", havingValue = "amap", matchIfMissing = false)
public class WeatherColAmapServiceImpl implements WeatherColService {
    private static final Logger log = LoggerFactory.getLogger(WeatherColAmapServiceImpl.class);

    /**
     * 系统配置
     */
    @Resource
    private AmapWeatherConfig config;

    @Resource
    private AdmWeatherRtMapper weatherRtMapper;

    @Resource
    private AdmWeatherForecastMapper weatherForecastMapper;

    @Value("${weather.region.conf-adcodes}")
    private String weatherAdcodes;

    /**
     * 区域映射装配
     */
    @Resource
    private RegionService regionService;

    /**
     * 天气采集
     */
    @Override
    public void collect() {
        try {
            List<String> adcodes= getAreaCodes();

            for (String adcode : adcodes) {
                // 实况采集
                collectRt(adcode);
                ThreadUtils.sleep(1000);
                // 预报采集
                collectForecast(adcode);
                ThreadUtils.sleep(1000);
            }
        }
        catch (Exception e) {
            log.error("collect weather fail!", e);
        }
    }

    public void collectRt(String adcode) {
        try {
            String dfUrl = StringUtils.replace(config.getUrl(), "#{adcode}", adcode);
            dfUrl = StringUtils.replace(dfUrl, "#{extensions}", "base");

            log.debug("get url:\r\n{}", dfUrl);
            String res = HttpUtils.doGet(dfUrl);
            log.debug("get res:\r\n{}", res);
            JSONObject jsonObject = JSON.parseObject(res);

            String status = jsonObject.getString("status");
            Assert.isTrue(StringUtils.equals(status, "1"), -1, jsonObject.getString("info"));

            JSONArray jsonArray = jsonObject.getJSONArray("lives");
            Assert.notNull(jsonArray, -1, "weather list is null.");

            if (!jsonArray.isEmpty()) {
                WeatherRt weatherRt = convertRt((JSONObject) jsonArray.get(0));
                weatherRtMapper.merge(weatherRt);
            }
        }
        catch (Exception e) {
            log.error("collectRt fail!", e);
        }
    }

    /**
     * 预报采集
     *
     * @param adcode 行政区划代码
     */
    public void collectForecast(String adcode) {
        try {
            String dfUrl = StringUtils.replace(config.getUrl(), "#{adcode}", adcode);
            dfUrl = StringUtils.replace(dfUrl, "#{extensions}", "all");

            log.debug("get url:\r\n{}", dfUrl);
            String res = HttpUtils.doGet(dfUrl);
            log.debug("get res:\r\n{}", res);
            JSONObject jsonObject = JSON.parseObject(res);

            String status = jsonObject.getString("status");
            Assert.isTrue(StringUtils.equals(status, "1"), -1, jsonObject.getString("info"));

            JSONArray jsonArray = jsonObject.getJSONArray("forecasts");
            Assert.notNull(jsonArray, -1, "forecasts list is null.");

            List<WeatherForecast> forecastList = convertForecast((JSONObject) jsonArray.get(0));

            if (CollectionUtils.isNotEmpty(forecastList)) {
                weatherForecastMapper.deleteByAdcode(adcode);
                weatherForecastMapper.insertBatch(forecastList);
            }
            else {
                weatherForecastMapper.deleteByAdcode(adcode);
            }
        }
        catch (Exception e) {
            weatherForecastMapper.deleteByAdcode(adcode);
            log.error("collectRt fail!", e);
        }
    }

    public List<String> getAreaCodes() {
        List<String> adcodes = new ArrayList<>();

        // 直辖市
        List<Region> municipalitys = regionService.getMunicipality();
        municipalitys.forEach(region -> {
            adcodes.add(region.getAdcode());
        });

        // 省会城市
        Region param = new Region();
        param.setAreaType(2);
        List<Region> regions = regionService.getRegion(param);

        regions.forEach(region -> {
            adcodes.add(region.getAdcode());
        });

        // 自定义城市
        String[] areaArray = StringUtils.split(weatherAdcodes, ",");

        if (ArrayUtils.isNotEmpty(areaArray)) {
            for (String areacode : areaArray) {
                adcodes.add(areacode);
            }
        }

        return adcodes;
    }

    private WeatherRt convertRt(JSONObject jsObj) {
        WeatherRt po = new WeatherRt();
        po.setAdcode(jsObj.getString("adcode"));
        po.setAreaName(jsObj.getString("city"));
        po.setDate(jsObj.getDate("reporttime"));

        String weather = jsObj.getString("weather");
        po.setWeatherCn(weather);
        String weatherStr = StringUtils.contains(weather, "-") ? StringUtils.substringBefore(weather, "-") : weather;
        po.setWeatherType(config.getWeatherTypeByName(weatherStr));

        po.setTemperature(jsObj.getDouble("temperature"));
        po.setHumidity(jsObj.getInteger("humidity"));
        po.setWindPower(jsObj.getString("windpower"));
        po.setWindDirection(jsObj.getString("winddirection"));
        po.setReportTime(jsObj.getDate("reporttime"));
        return po;
    }

    private List<WeatherForecast> convertForecast(JSONObject jsObj) {
        Date reportDate = jsObj.getDate("reporttime");
        String areaName = jsObj.getString("city");
        String adcode = jsObj.getString("adcode");

        List<WeatherForecast> forecastList = new ArrayList<>();
        JSONArray jsonArray = jsObj.getJSONArray("casts");
        jsonArray.forEach(item -> {
            JSONObject entity = (JSONObject) item;
            WeatherForecast forecast = new WeatherForecast();
            forecast.setAdcode(adcode);
            forecast.setAreaName(areaName);
            forecast.setDate(entity.getDate("date"));

            String dayWeather = entity.getString("dayweather");
            forecast.setDayWeatherCn(dayWeather);
            String weatherStr = StringUtils.contains(dayWeather, "-") ?
                StringUtils.substringBefore(dayWeather, "-") :
                dayWeather;
            forecast.setDayWeatherType(config.getWeatherTypeByName(weatherStr));

            String nightWeather = entity.getString("nightweather");
            forecast.setNightWeatherCn(nightWeather);
            String weatherStr2 = StringUtils.contains(nightWeather, "-") ?
                StringUtils.substringBefore(nightWeather, "-") :
                nightWeather;
            forecast.setNightWeatherType(config.getWeatherTypeByName(weatherStr2));

            forecast.setDayTemp(entity.getDouble("daytemp"));
            forecast.setNightTemp(entity.getDouble("nighttemp"));
            forecast.setDayWindPower(entity.getString("daypower"));
            forecast.setNightWindPower(entity.getString("nightpower"));
            forecast.setDayWindDir(entity.getString("daywind"));
            forecast.setNightWindDir(entity.getString("nightwind"));
            forecast.setReportTime(reportDate);
            forecastList.add(forecast);
        });

        return forecastList;
    }
}