package com.ho.filecenter.service.impl;

import cn.hutool.http.HttpRequest;
import cn.hutool.http.HttpResponse;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.ho.common.tools.constant.RedisKeyConstant;
import com.ho.common.tools.entity.WeatherRespVo;
import com.ho.common.tools.service.RedisService;
import com.ho.common.tools.util.BigDecimalUtil;
import com.ho.filecenter.config.WeatherDbConfig;
import com.ho.filecenter.constant.WeatherTypeConstant;
import com.ho.filecenter.entity.City;
import com.ho.filecenter.mapper.CityMapper;
import com.ho.filecenter.service.WeatherService;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.lang.StringUtils;
import org.lionsoul.ip2region.DataBlock;
import org.lionsoul.ip2region.DbSearcher;
import org.lionsoul.ip2region.Util;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;

import java.lang.reflect.Method;
import java.math.BigDecimal;
import java.util.Map;
import java.util.concurrent.TimeUnit;

/**
 * @author gyan
 * @desc: TODO
 * @DateTime: 2022/11/15 8:45
 */
@Service
@Slf4j
public class WeatherServiceImpl implements WeatherService {
    //weatherPath
    @Value("${weather.path}")
    String weatherPath;

    //afterPath
    @Value("${weather.after}")
    String afterPath;

    //token
    @Value("${weather.token}")
    String token;

    @Value("${spring.profiles.active}")
    String env;

    @Autowired
    CityMapper cityMapper;

    @Autowired
    RedisService redisService;

    @Autowired
    BigDecimalUtil bigDecimalUtil;

    @Value("${path.weather}")
    String path;

    //DbSearcher
    @Override
    public WeatherRespVo getWeather(String ipAddr) {
        WeatherRespVo weather = new WeatherRespVo();
        try {
            //2023-01-03 fan update 改为从内存中读取 原来代码先注释掉
            //File file = new File(path);
            //log.info("file:{}",file);
            //if (file.exists()) {
            //DbConfig config = new DbConfig();
            //searcher = new DbSearcher(config, file.getPath());
            DbSearcher searcher = WeatherDbConfig.dbSearcher;
            log.info("searcher:{}", searcher);
            Method method = searcher.getClass().getMethod("btreeSearch", String.class);
            log.info("method:{}", method);
            if (!Util.isIpAddress(ipAddr)) {
                log.error("Error: Invalid ip address");
            }
            DataBlock dataBlock1 = (DataBlock) method.invoke(searcher, ipAddr);
            if (dataBlock1 == null) {
                log.error("DataBlock is null");
                return weather;
            }
            //进行判断 拿到城市名称 进行分割字符串
            //定义省份
            String provincezh = "";
            //定义城市
            String cityzh = "";
            if (dataBlock1.getRegion() != null) {
                String region = dataBlock1.getRegion();
                log.info("DataBlock.getRegion:{}", region);
                String[] regionList = region.split("\\|");
                provincezh = regionList[2].replace("省", "");
                cityzh = regionList[3].replace("市", "");
            }
            //根据城市名在本地库中查询城市编号
            City city = cityMapper.selectByProvinceAndCity(provincezh, cityzh);
            log.info("city: {}", city);
            weather.setCityzh(cityzh);
            //到缓存中查找是否存在
            StringBuilder sb = new StringBuilder(RedisKeyConstant.WEATHER_TEMPERATURE);
            StringBuilder append = sb.append(city.getProvinceen()).append(":").append(city.getLeaderen());
            String weatherName = append.toString();
            if (redisService.hasKey(weatherName)) {
                WeatherRespVo weatherRespVo = (WeatherRespVo) redisService.get(weatherName);
                return weatherRespVo;
            }
            //拼接url
            //https://api.caiyunapp.com/v2.6/TAkhjf8d1nlSlspN/101.6656,39.2072/daily?dailysteps=1
            //调用方法
            if (city != null) {
                weather = getWeatherFromApi(city.getLon(), city.getLat());
                weather.setCityzh(cityzh);
                //设置为12小时缓存
                redisService.set(weatherName, weather, 3, TimeUnit.HOURS);
            }
        } catch (Exception e) {
            log.error(e.getMessage());
        }
        return weather;
    }


    @Override
    public WeatherRespVo getWeatherFromAddr(Integer stationId, String addr) {
        WeatherRespVo weather = new WeatherRespVo();
        if (addr == null || addr.isEmpty()) {
            return weather;
        }
        String provincezh = null;
        String cityzh = null;
        //对直辖市进行特殊处理,直辖市的省市都是同名
        if (bDirect(addr)) {
            int provinceIndex = addr.indexOf("市");
            provincezh = addr.substring(0, provinceIndex);
            cityzh = provincezh;
        } else {
            //将地址按照省市截取,从city表中取到对应数据
            int provinceIndex = addr.indexOf("省");
            int cityIndex = addr.indexOf("市");
            provincezh = addr.substring(0, provinceIndex);
            cityzh = addr.substring(provinceIndex + 1, cityIndex);
        }
        //根据城市名在本地库中查询城市编号
        City city = cityMapper.selectByProvinceAndCity(provincezh, cityzh);
        log.info("city: {}", city);
        weather.setCityzh(cityzh);

        //这个方法不做缓存
        StringBuilder sb = new StringBuilder(RedisKeyConstant.WEATHER_TEMPERATURE);
        StringBuilder append = sb.append(city.getProvinceen()).append(":").append(city.getLeaderen());
        String weatherName = append.toString();
        log.info("weatherName:{}", weatherName);
        if (redisService.hasKey(weatherName)) {
            return (WeatherRespVo) redisService.get(weatherName);
        }
        //调用外部接口
        weather = getWeatherFromApi(city.getLon(), city.getLat());
        weather.setCityzh(cityzh);
        redisService.set(weatherName, weather, 3, TimeUnit.HOURS);
        //将数据放在redis中
        return weather;
    }


    private boolean bDirect(String addr) {
        if (addr.contains("北京市") || addr.contains("天津市") || addr.contains("上海市") || addr.contains("重庆市")) {
            return true;
        }
        return false;
    }

    //抽取一个公共方法查询天气
    @Override
    public WeatherRespVo getWeatherFromApi(String lat, String lon) {
        WeatherRespVo vo = new WeatherRespVo();
        if (StringUtils.isEmpty(lon) || StringUtils.isEmpty(lat)) {
            return vo;
        }
        StringBuilder url = new StringBuilder();
        StringBuilder appendUrl = url.append(weatherPath).append("/").append(token).append("/").append(lon).append(",").append(lat).append(afterPath);
        String weatherUrl = appendUrl.toString();
        HttpResponse httpResponse = HttpRequest.get(weatherUrl).execute();
        String body = httpResponse.body();
        log.info("body:" + body);
//              String body ="{\"status\":\"ok\",\"api_version\":\"v2.6\",\"api_status\":\"alpha\",\"lang\":\"zh_CN\",\"unit\":\"metric\",\"tzshift\":28800,\"timezone\":\"Asia/Shanghai\",\"server_time\":1668741792,\"location\":[32.041544,118.767413],\"result\":{\"daily\":{\"status\":\"ok\",\"astro\":[{\"date\":\"2022-11-18T00:00+08:00\",\"sunrise\":{\"time\":\"06:36\"},\"sunset\":{\"time\":\"17:04\"}}],\"precipitation_08h_20h\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":0.0,\"min\":0.0,\"avg\":0.0,\"probability\":0}],\"precipitation_20h_32h\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":1.9782,\"min\":0.0,\"avg\":0.6893,\"probability\":70}],\"precipitation\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":1.1557,\"min\":0.0,\"avg\":0.0889,\"probability\":60}],\"temperature\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":16.0,\"min\":13.2,\"avg\":13.84}],\"temperature_08h_20h\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":15.67,\"min\":13.6,\"avg\":14.25}],\"temperature_20h_32h\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":16.0,\"min\":13.0,\"avg\":14.05}],\"wind\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":{\"speed\":18.02,\"direction\":86.38},\"min\":{\"speed\":7.76,\"direction\":46.14},\"avg\":{\"speed\":12.68,\"direction\":73.4}}],\"wind_08h_20h\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":{\"speed\":18.02,\"direction\":86.38},\"min\":{\"speed\":11.02,\"direction\":74.0},\"avg\":{\"speed\":13.92,\"direction\":74.31}}],\"wind_20h_32h\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":{\"speed\":13.42,\"direction\":62.13},\"min\":{\"speed\":4.44,\"direction\":21.79},\"avg\":{\"speed\":8.08,\"direction\":49.37}}],\"humidity\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":0.89,\"min\":0.77,\"avg\":0.82}],\"cloudrate\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":1.0,\"min\":0.3,\"avg\":0.89}],\"pressure\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":102020.52,\"min\":101780.52,\"avg\":101879.58}],\"visibility\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":24.13,\"min\":8.86,\"avg\":11.23}],\"dswrf\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":170.1,\"min\":0.0,\"avg\":68.1}],\"air_quality\":{\"aqi\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":{\"chn\":36,\"usa\":71},\"avg\":{\"chn\":25,\"usa\":60},\"min\":{\"chn\":16,\"usa\":30}}],\"pm25\":[{\"date\":\"2022-11-18T00:00+08:00\",\"max\":22,\"avg\":16,\"min\":7}]},\"skycon\":[{\"date\":\"2022-11-18T00:00+08:00\",\"value\":\"LIGHT_RAIN\"}],\"skycon_08h_20h\":[{\"date\":\"2022-11-18T00:00+08:00\",\"value\":\"CLOUDY\"}],\"skycon_20h_32h\":[{\"date\":\"2022-11-18T00:00+08:00\",\"value\":\"MODERATE_RAIN\"}],\"life_index\":{\"ultraviolet\":[{\"date\":\"2022-11-18T00:00+08:00\",\"index\":\"3\",\"desc\":\"中等\"}],\"carWashing\":[{\"date\":\"2022-11-18T00:00+08:00\",\"index\":\"3\",\"desc\":\"较不适宜\"}],\"dressing\":[{\"date\":\"2022-11-18T00:00+08:00\",\"index\":\"5\",\"desc\":\"凉爽\"}],\"comfort\":[{\"date\":\"2022-11-18T00:00+08:00\",\"index\":\"6\",\"desc\":\"凉爽\"}],\"coldRisk\":[{\"date\":\"2022-11-18T00:00+08:00\",\"index\":\"3\",\"desc\":\"易发\"}]}},\"primary\":0}}";
        BigDecimal maxTemperature = BigDecimal.ZERO;
        BigDecimal minTemperature = BigDecimal.ZERO;
        String skyCon = "";
        String speedAndDirection = "";
        Map<String, JSONObject> map = JSONObject.parseObject(body, Map.class);
        if ("ok".equals(map.get("status"))) {
            JSONObject resultJSONObject = map.get("result");
            Map<String, Object> resultMap = resultJSONObject.getInnerMap();
            JSONObject dailyJSONObject = (JSONObject) resultMap.get("daily");
            Map<String, Object> dailyMap = dailyJSONObject.getInnerMap();
            JSONArray tempJSONArray = (JSONArray) dailyMap.get("temperature");
            JSONObject tempJSONObject = (JSONObject) tempJSONArray.get(0);
            Map<String, Object> temMap = tempJSONObject.getInnerMap();
            maxTemperature = (BigDecimal) temMap.get("max");
            minTemperature = (BigDecimal) temMap.get("min");
            //拿风向
            JSONArray windJSONArray = (JSONArray) dailyMap.get("wind");
            JSONObject windJSONObject = (JSONObject) windJSONArray.get(0);
            JSONObject windAvgJSONObject = (JSONObject) windJSONObject.getInnerMap().get("avg");
            Map<String, Object> windAvgMap = windAvgJSONObject.getInnerMap();
            BigDecimal speed = (BigDecimal) windAvgMap.get("speed");
            BigDecimal direction = (BigDecimal) windAvgMap.get("direction");
            double speedDouble = speed.doubleValue();
            double directionDouble = direction.doubleValue();
            String weatherSpeed = WeatherTypeConstant.getSpeed(speedDouble);
            String weatherDirection = WeatherTypeConstant.getDirection(directionDouble);
            speedAndDirection = weatherDirection + weatherSpeed;

            //获取天气现象
            JSONArray skyconJSONArray = (JSONArray) dailyMap.get("skycon");
            JSONObject skyconJSONObject = (JSONObject) skyconJSONArray.get(0);
            Map<String, Object> skyconMap = skyconJSONObject.getInnerMap();
            String value = (String) skyconMap.get("value");
            skyCon = WeatherTypeConstant.getSkyCon(value);

        }
        vo.setMaxTemperature(maxTemperature);
        vo.setMinTemperature(minTemperature);
        vo.setSkyCon(skyCon);
        vo.setSpeedAndDirection(speedAndDirection);
        log.info("vo:" + vo);
        return vo;
    }
}
