package cn.qinys.platform.upms.api.service.impl;

import cn.qinys.platform.base.exceptions.BizException;
import cn.qinys.platform.base.utils.DateUtils;
import cn.qinys.platform.base.utils.RedisUtils;
import cn.qinys.platform.entity.upms.CommonGeoCount;
import cn.qinys.platform.entity.upms.CommonGeoKey;
import cn.qinys.platform.upms.api.mapper.CommonGeoCountMapper;
import cn.qinys.platform.upms.api.mapper.CommonGeoKeyMapper;
import cn.qinys.platform.upms.api.req.GaoDeGetAddressReq;
import cn.qinys.platform.upms.api.req.GaoDeKeyPageReq;
import cn.qinys.platform.upms.api.resp.GaoDeKeyPageResp;
import cn.qinys.platform.upms.api.service.IGaoDeKeyService;
import com.alibaba.fastjson2.JSONObject;
import com.baomidou.mybatisplus.core.conditions.query.QueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.stereotype.Service;
import org.springframework.util.StringUtils;
import org.springframework.web.client.RestTemplate;

import java.math.BigDecimal;
import java.util.Date;

/**
 * Description:
 *
 * @author tanlie
 * Date: 2024/7/8 8:54
 */
@Slf4j
@Service
public class GaoDeKeyServiceImpl implements IGaoDeKeyService {

    @Resource
    private CommonGeoCountMapper countMapper;
    @Resource
    private CommonGeoKeyMapper geoKeyMapper;
    @Resource
    private RestTemplate restTemplate;
    @Resource
    RedisUtils redisUtils;
    @Resource
    CommonGeoCountMapper geoCountMapper;

    @Override
    public Page<GaoDeKeyPageResp> getPage(GaoDeKeyPageReq req) {
        Page<CommonGeoCount> page = new Page<>(req.getCurrent(), req.getSize());
        QueryWrapper<CommonGeoCount> wrapper = new QueryWrapper<>();
        wrapper.eq(StringUtils.hasLength(req.getKey()), "c.geo_key", req.getKey());
        wrapper.like(StringUtils.hasLength(req.getDate()), "c.date", req.getDate());
        wrapper.like(StringUtils.hasLength(req.getRemark()), "k.remark", req.getRemark());
        wrapper.orderByDesc("id");
        return countMapper.selectCountPage(page, wrapper);
    }

    @Override
    public String getAddress(GaoDeGetAddressReq req) {
        JSONObject res = this.getGaoDeResult("", req.getLongitude(), req.getLatitude(), 0);
        return res == null ? "" : res.getString("formatted_address");
    }

    @Override
    public JSONObject getGaoDeResult(String key, BigDecimal lon, BigDecimal lat, Integer index) {
        if (index >= 100) {
            return null;
        }

        CommonGeoKey geoKey = this.getGaoDeKey();
        index++;
        String url = "https://restapi.amap.com/v3/geocode/regeo?key={0}&location={1},{2}";
        JSONObject res = restTemplate.getForObject(url, JSONObject.class, geoKey.getGeoKey(), lon, lat);
        if (res == null) {
            throw new BizException("逆地理解释出现错误");
        }
        if ("1".equals(res.getString("status"))) {
            log.info("获取逆地理解析信息成功{}", res);
            JSONObject regeocode = res.getJSONObject("regeocode");
            this.countKeyUsage(geoKey.getGeoKey());
            return regeocode;
        } else {
            return this.getGaoDeResult(geoKey.getGeoKey(), lon, lat, index);
        }
    }


    private CommonGeoKey getGaoDeKey() {
        QueryWrapper<CommonGeoKey> wrapper = new QueryWrapper<>();
        wrapper.orderByAsc("update_time", "id");
        wrapper.last("LIMIT 1");
        return geoKeyMapper.selectOne(wrapper);
    }

    private void countKeyUsage(String key) {
        String lockKey = this.getClass() + ":" + key;
        String lockValue = "gao de key count lock is being used";
        boolean hasKey = false;
        for (int i = 0; i < 5; i++) {
            hasKey = redisUtils.tryLock(lockKey, lockValue);
            if (hasKey) {
                break;
            }
            try {
                Thread.sleep(1000L);
            } catch (Exception ignored) {
            }
        }
        // 多次获取不到key，放弃统计
        if (!hasKey) {
            return;
        }
        try {
            String date = DateUtils.dateFormatter(new Date(), "yyyy-MM-dd");
            QueryWrapper<CommonGeoCount> wrapper = new QueryWrapper<>();
            wrapper.eq("date", date);
            wrapper.eq("geo_key", key);
            wrapper.last("LIMIT 1");
            CommonGeoCount exit = geoCountMapper.selectOne(wrapper);
            if (exit != null) {
                exit.setUseCount(exit.getUseCount() + 1);
                exit.setUpdateTime(new Date());
                geoCountMapper.updateById(exit);
                return;
            }
            CommonGeoCount count = new CommonGeoCount();
            count.setGeoKey(key);
            count.setDate(date);
            count.setUseCount(1);
            count.setCreateTime(new Date());
            count.setUpdateTime(new Date());
            geoCountMapper.insert(count);
        } finally {
            redisUtils.unlock(lockKey, lockValue);
        }
    }
}
