package com.zd.forward.serivce;

import com.alibaba.fastjson.JSONObject;
import com.zd.common.core.constant.HttpStatus;
import com.zd.common.core.constant.SecurityConstants;
import com.zd.common.core.domain.R;
import com.zd.common.core.utils.StringUtils;
import com.zd.common.core.web.domain.AjaxResult;
import com.zd.forward.config.AlgorithmYml;
import com.zd.forward.domain.VideoRequestData;
import com.zd.forward.properties.FireProperties;
import com.zd.system.api.domain.Algorithm;
import com.zd.system.api.domain.PlayVo;
import com.zd.system.api.speak.RemoteSpeakService;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.ParameterizedTypeReference;
import org.springframework.data.redis.core.ListOperations;
import org.springframework.data.redis.core.RedisTemplate;
import org.springframework.http.*;
import org.springframework.scheduling.annotation.Async;
import org.springframework.stereotype.Service;
import org.springframework.web.client.RestTemplate;

import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.concurrent.ConcurrentHashMap;
import java.util.concurrent.TimeUnit;

import static com.zd.common.core.constant.Constants.MAP_INIT_SIZE;

@Service
public class SendSginAccessLogService {

    Logger logger = LoggerFactory.getLogger(SendSginAccessLogService.class);

    private final RestTemplate restTemplateLocal;
    public final RedisTemplate<Object, Object> redisTemplate;
    private final LoginService loginLab;
    private final AlgorithmYml algorithmYml;

    private final RemoteSpeakService remoteSpeakService;

    /**
     * 报警次数记录
     */
    static Map<String, Integer> alarmMap = new ConcurrentHashMap<>();
    /**
     * 超时时间设置MAP
     */
    static Map<String, Long> expiryMap = new ConcurrentHashMap<>();

    @Autowired
    public SendSginAccessLogService(RestTemplate restTemplateLocal, RedisTemplate<Object, Object> redisTemplate, LoginService loginLab, AlgorithmYml algorithmYml, RemoteSpeakService remoteSpeakService) {
        this.restTemplateLocal = restTemplateLocal;
        this.redisTemplate = redisTemplate;
        this.loginLab = loginLab;
        this.algorithmYml = algorithmYml;
        this.remoteSpeakService = remoteSpeakService;
    }

    @Async
    public void sendAddLogRest(String code, Long id, Boolean f, String msg, String token, String url) {
        JSONObject json = new JSONObject();
        json.put("signId", id);
        json.put("code", code);
        json.put("result", f);
        json.put("msg", msg);
        HttpHeaders headers = new HttpHeaders();
        MediaType type = MediaType.parseMediaType("application/json; charset=UTF-8");
        headers.setContentType(type);
        headers.add("Accept", MediaType.APPLICATION_JSON.toString());
        headers.add(SecurityConstants.TOKEN_AUTHENTICATION, token);
        HttpEntity<String> formEntity = new HttpEntity<>(json.toString(), headers);
        logger.info("保存检查日志记录，地址：{}", url);
        String s = restTemplateLocal.postForEntity(url, formEntity, String.class).getBody();
        logger.info("保存检查日志记录结果:{}", s);

    }

    /**
     * 通过实验室ID获取实验室负责人电话
     */
    public String getAdminPhoneBySubId(Long subId, String url) {
        ParameterizedTypeReference<R<String>> reference = new ParameterizedTypeReference<R<String>>() {
        };
        R<String> send = send(null, url + "laboratory/subject/" + subId + "/admin/phone", HttpMethod.GET, reference);
        return send != null ? send.getData() : "";
    }

    public void saveAlarm(VideoRequestData videoRequestData) {
        String cid = videoRequestData.getCid();
        if (Boolean.TRUE.equals(redisTemplate.hasKey(cid))) {
            Integer count = (Integer) redisTemplate.opsForValue().get(cid);
            if (count == null) {
                count = 0;
            }
            redisTemplate.opsForValue().set(cid, count + 1, 30, TimeUnit.SECONDS);
            R<Object> r = sendAlarm(videoRequestData);
            if (r.getCode() != HttpStatus.SUCCESS) {
                logger.error("警报发送失败，警报类型；{}，失败原因：{}", videoRequestData.getAlgo_name(), r.getMsg());
            }
        } else {
            redisTemplate.opsForValue().set(cid, 1, 30, TimeUnit.SECONDS);
        }

    }

    public void saveAlarm(FireProperties properties) {
        String hardwareNum = properties.getHardwareNum();
        long currentTimeMillis = System.currentTimeMillis();
        if (expiryMap.containsKey(hardwareNum)) {
            Long expiryTime = expiryMap.get(hardwareNum);
            if (currentTimeMillis > expiryTime) {
                expiryMap.remove(hardwareNum);
                alarmMap.remove(hardwareNum);
            }else {
                send(properties, hardwareNum);
            }
            int count = alarmMap.get(hardwareNum) == null ? 0 : alarmMap.get(hardwareNum);
            ++count;
            alarmMap.put(hardwareNum, count);
            expiryMap.put(hardwareNum, currentTimeMillis + 30 * 1000);
            logger.info("已触发火焰警报：{}次",alarmMap.get(hardwareNum));
        } else {
            alarmMap.put(hardwareNum, 1);
            expiryMap.put(hardwareNum, currentTimeMillis + 30 * 1000);
        }
    }

    private void send(FireProperties properties, String hardwareNum) {
        R<Object> r = send(properties);
        if (r.getCode() != HttpStatus.SUCCESS) {
            logger.error("火焰警报失败原因：{}", r.getMsg());
        }
    }

    public void playMp3() {
        if (!algorithmYml.isLoudspeakerSwitch()) {
            return;
        }
        String loudspeakerIp1 = algorithmYml.getLoudspeakerIp1();
        String loudspeakerIp2 = algorithmYml.getLoudspeakerIp2();
        R deviceList = remoteSpeakService.getDeviceList(1, 10, 5L);
        if (deviceList.getCode() == HttpStatus.SUCCESS) {
            List<Map<String, Object>> mapList = (List<Map<String, Object>>) deviceList.getData();
            for (Map<String, Object> map : mapList) {
                if (StringUtils.isNotNull(map.get("deviceSn")) && StringUtils.isNotNull(map.get("port"))) {
                    PlayVo playVo = new PlayVo();
                    playVo.setSn(map.get("deviceSn") + "");
                    playVo.setPort(Integer.parseInt(map.get("port") + ""));
                    sendText(loudspeakerIp1, playVo);
                    sendText(loudspeakerIp2, playVo);
                }
            }
        }
    }

    private void sendText(String ip, PlayVo playVo) {
        String url = algorithmYml.getTargetUrl() + "/zd-speaker/speaker/textPlayMusic?ip={ip}&texts={texts}";
        HttpEntity<PlayVo> requestEntity = getMapHttpEntity(playVo);
        if (StringUtils.isNotEmpty(ip)) {
            List<String> texts = new ArrayList<>();
            texts.add("当前环境监测到无人值守");
            ResponseEntity<AjaxResult> response = restTemplateLocal.postForEntity(url, requestEntity, AjaxResult.class, ip, texts);
            logger.info("响应码：{}，响应结果：{}", response.getStatusCode(), response.getBody());
        }
    }

    /**
     * 发送火焰警报
     */
    public R<Object> sendAlarm(VideoRequestData videoRequestData) {
        Map<String, Object> requestMap = new HashMap<>(MAP_INIT_SIZE);
        List<Map<String, Object>> maps = new ArrayList<>();
        Integer aid = videoRequestData.getAid();
        Map<Integer, AlgorithmYml.AlarmConfig> alarmConfigMap = algorithmYml.getAlarmConfigMap();
        if (alarmConfigMap.containsKey(aid)) {
            AlgorithmYml.AlarmConfig alarmConfig = alarmConfigMap.get(aid);
            Map<String, Object> params = new HashMap<>(MAP_INIT_SIZE);
            params.put("hardwareNum", videoRequestData.getCid());
            params.put("val", videoRequestData.getStatus());
            return getParams(requestMap, maps, alarmConfig, params);
        }
        return R.fail("未找到算法");
    }

    /**
     * 发送火焰警报
     */
    public R<Object> send(FireProperties properties) {
        Map<String, Object> requestMap = new HashMap<>(MAP_INIT_SIZE);
        List<Map<String, Object>> maps = new ArrayList<>();
        Integer aid = properties.getAlgoId();
        Map<Integer, AlgorithmYml.AlarmConfig> alarmConfigMap = algorithmYml.getAlarmConfigMap();
        AlgorithmYml.AlarmConfig alarmConfig = alarmConfigMap.get(aid);
        Map<String, Object> params = new HashMap<>(MAP_INIT_SIZE);
        params.put("hardwareNum", properties.getHardwareNum());
        params.put("subId", properties.getLabId());
        params.put("val", 1);
        return getParams(requestMap, maps, alarmConfig, params);
    }

    private R<Object> getParams(Map<String, Object> requestMap, List<Map<String, Object>> maps, AlgorithmYml.AlarmConfig alarmConfig, Map<String, Object> params) {
        params.put("funNum", alarmConfig.getFunNum());
        params.put("describe", alarmConfig.getDescribe());
        maps.add(params);
        requestMap.put("functionStatuses", maps);
        ParameterizedTypeReference<R<Object>> reference = new ParameterizedTypeReference<R<Object>>() {
        };
        return send(requestMap, algorithmYml.getTargetUrl() + "laboratory/plan/triggerRiskPlan", HttpMethod.POST, reference);
    }

    private <T> R<T> send(Map<String, Object> params, String url, HttpMethod method, ParameterizedTypeReference<R<T>> reference) {
        HttpEntity<Map<String, Object>> requestEntity = getMapHttpEntity(params);
        ResponseEntity<R<T>> exchange = restTemplateLocal.exchange(url, method, requestEntity, reference);
        R<T> body = exchange.getBody();
        if (body != null && body.getCode() == HttpStatus.UNAUTHORIZED) {
            requestEntity = getMapHttpEntityLogin(params);
            exchange = restTemplateLocal.exchange(url, method, requestEntity, reference);

        }
        body = exchange.getBody();
        return body;
    }

    /**
     * 保存算法结果
     */
    public void saveAlgorithmResult(Algorithm algorithm) {
        ListOperations<Object, Object> listOperations = redisTemplate.opsForList();
        listOperations.leftPush("AlgorithmResult:", algorithm);
    }


    /**
     * 通过实验室ID获取实验室正常打卡人数
     */
    public Integer getSubAccessCountBySubId(Long subId, String url) {
        ParameterizedTypeReference<R<Integer>> reference = new ParameterizedTypeReference<R<Integer>>() {
        };
        R<Integer> send = send(null, url + "laboratory/subject/manger/records/" + subId + "/count", HttpMethod.GET, reference);
        return send == null ? 0 : send.getData();
    }

    private <T> HttpEntity<T> getMapHttpEntity(T params) {
        String token = loginLab.getToken();
        HttpHeaders headers = new HttpHeaders();
        headers.add(SecurityConstants.TOKEN_AUTHENTICATION, token);
        return new HttpEntity<>(params, headers);
    }

    private <T> HttpEntity<T> getMapHttpEntityLogin(T params) {
        loginLab.loginLab();
        String token = loginLab.getToken();
        HttpHeaders headers = new HttpHeaders();
        headers.add(SecurityConstants.TOKEN_AUTHENTICATION, token);
        return new HttpEntity<>(params, headers);
    }
}
