package org.dromara.system.controller;

import cn.hutool.core.date.DateUtil;
import cn.hutool.core.util.StrUtil;
import cn.hutool.json.JSONArray;
import cn.hutool.json.JSONObject;
import cn.hutool.json.JSONUtil;
import com.dtflys.forest.backend.okhttp3.OkHttp3;
import jakarta.annotation.Resource;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import okhttp3.OkHttpClient;
import okhttp3.Request;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.utils.SpringUtils;
import org.dromara.common.mybatis.core.page.PageQuery;
import org.dromara.common.mybatis.core.page.TableDataInfo;
import org.dromara.common.redis.utils.CacheUtils;
import org.dromara.common.redis.utils.RedisUtils;
import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.bo.SysDictDataBo;
import org.dromara.system.domain.bo.TblCarInfoBo;
import org.dromara.system.domain.vo.SysDictDataVo;
import org.dromara.system.domain.vo.TblCarInfoVo;
import org.dromara.system.service.ISysDictDataService;
import org.dromara.system.service.ITblCarDriveWarningService;
import org.dromara.util.CabinetUtil;
import org.dromara.util.MessageUtils;
import org.dromara.util.YingshiHttp;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;

import java.time.Duration;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.List;
import java.util.Map;

import static org.dromara.util.CabinetUtil.CABINET_BOXS;
import static org.dromara.util.CabinetUtil.CABINET_INFO;

@Validated
@RequiredArgsConstructor
@RestController
@Slf4j
@RequestMapping("/system/common")
public class CommonController extends TblBaseController {

    @Value("${yingshi.appkey}")
    String appkey;
    @Value("${yingshi.appsecret}")
    String appsecret;

    private final YingshiHttp yingshiHttp;
//    @Resource
//    YingshiHttp yingshiHttp;
    final  static String ACCESTOKEN = "yingshi_token";
    private final OkHttpClient client = new OkHttpClient();
    @GetMapping("/{code}/getPlayConfig")
    public Object getPlayurl(@PathVariable String code) {

        //获取token
        String accesstoken = RedisUtils.getCacheObject(ACCESTOKEN);
        if (accesstoken == null) {
            //登录获取
            Map resdata =  yingshiHttp.getAccessToken(appkey,appsecret);
            accesstoken =  ((Map<String,Object>)resdata.get("data")).get("accessToken").toString();
            Long expire = Long.valueOf(((Map<String,Object>)resdata.get("data")).get("expireTime").toString());
            RedisUtils.setCacheObject(ACCESTOKEN,accesstoken, Duration.ofMillis(expire- DateUtil.current()));
        }
        Map resdata =  yingshiHttp.getLiveAddress(accesstoken,code);
        String msg = "系统错误";
        try{
            msg= (String) resdata.get("msg");
            Integer codei = Integer.parseInt(resdata.get("code").toString());
            if(codei!=200) throw new Exception();
            String playurl =  ((Map<String,Object>)resdata.get("data")).get("url").toString();

            Map<String,Object> ret = new HashMap<>();
            ret.put("url",playurl);
            ret.put("accessToken",accesstoken);

            return R.ok(ret);

        }catch (Exception e){
           return R.fail(msg);
        }
//        log.info("{}",resdata);

//        return R.ok();

    }

    /**
     * 语音及LED播放
     * @param data
     * @return
     */
    @PostMapping("/play")
    public Object playtts(@RequestBody Map<String,Object> data) {

        String message = data.get("message").toString();
        List<String> codes = (List<String>) data.get("devicelist");
        List<String> tts = new ArrayList<>();
        List<String> leds = new ArrayList<>();
        for (String code : codes) {
            if(code.contains("tts")){
                tts.add(code.split("_")[2]);
            }if(code.contains("led")){
                leds.add(code.split("_")[2]);
            }

        }
        try {
            for (String ttsi : tts){
                MessageUtils.sendTTs(ttsi,message);
            }
            for (String led : leds){
                MessageUtils.sendLed(led,message);
            }

        }catch (Exception e){
            R.fail("发送失败");
        }

        return R.ok();


    }

    @PostMapping("/playlist/static")
    public Object playlistInfo() throws Exception {

        List<Map<String,String>> data = new ArrayList<>();

        for (Object key :   CacheUtils.keys("playlist")) {
            data.add((Map<String,String>) CacheUtils.get("playlist",key));
        }

        if(data.size()<1) return data;
        try {
            data.sort((o1, o2) -> {
                try {
                    return (DateUtil.parseDateTime(o2.get("time")).getTime() - DateUtil.parseDateTime(o1.get("time")).getTime())>0?1:-1;
                } catch (Exception e) {
                    log.error(e.getMessage());
                    log.error(o1.get("time"));
                    log.error(o2.get("time"));
                    return -1;
                }
            });
        }catch (Exception e){}
        if(data.size()<10) return data;
        return data.subList(0,10);
    }



    /**
     * 获取柜子统计信息
     * @return
     * @throws Exception
     */
    @PostMapping("/cabinet/boxstatic")
    public Object cabinetInfo() throws Exception {
        Map<String,Object> data = new HashMap<>();
        CacheUtils.keys(CABINET_INFO).forEach(item->{
            if(item.toString().contains("box")){
                data.put(item.toString(),CacheUtils.get(CABINET_INFO,item));
            }
        });

        return data;
    }

    @PostMapping("/devicemsg")
    public Object devicemsg() throws Exception {
        Map<String,Object> data = new HashMap<>();
        CacheUtils.keys("offline").forEach(item->{
            Map<String,Object> c = new HashMap<>();
            if(CacheUtils.get("offline",item) instanceof  String){
                CacheUtils.put("offline",item,new HashMap<>());
            }else{
                c = CacheUtils.get("offline",item);
                if(c.keySet().size()>0){
                    data.put(item.toString(),c);
                }
            }
        });
        return data;
    }



    @PostMapping("/station/devs")
    public Object stationDevs() throws Exception {
        Map<String,Map<String,String>> devMap = new HashMap<>();
        SysDictDataBo bo =new SysDictDataBo();
        bo.setDictType("tbl_sites");
        List<SysDictDataVo> list = SpringUtils.getBean(ISysDictDataService.class).selectDictDataList(bo);
        try {
            list.forEach(item->{
                if(StrUtil.isNotEmpty(item.getRemark())){
                    JSONArray jsonArray = JSONUtil.parseArray(item.getRemark());
                    jsonArray.forEach(item2->{
                        Map<String,String> c =new HashMap<>();
                        c.put("name",((JSONObject)item2).getStr("name"));
                        c.put("offline","0");
                        if(((JSONObject)item2).getStr("type").equals("cabinet")){
                           Map offline = CacheUtils.get("offline",((JSONObject)item2).getStr("code"));
                           if(offline!=null && offline.keySet().size()>0){
                               c.put("offline","1");
                           }
                        }
                        devMap.put(((JSONObject)item2).getStr("type")+((JSONObject)item2).getStr("code"),c);
                    });
                }
            });
        }catch (Exception e){
            log.error(e.getMessage());

        }
        return devMap;
    }

    /**
     * 通过POST请求获取指定柜子的信息。
     *
     * 此方法处理来自客户端的POST请求，旨在根据柜子代码获取特定柜子的详细信息。
     * 使用路径参数{@code code}来指定具体的柜子。
     *
     * @param code 柜子的唯一标识代码，作为路径参数传递。
     * @return 返回包含柜子信息的对象。具体结构取决于实现。
     * @throws Exception 如果获取柜子信息过程中发生错误。
     */
    @PostMapping("/cabinet/{code}/info")
    public Object cabinetInfo(@PathVariable String code) throws Exception {
        return CacheUtils.get(CABINET_INFO,code);
    }

    /**
     * 通过POST请求获取指定柜子的所有箱子的信息。
     *
     * 此方法处理来自客户端的POST请求，旨在根据柜子代码获取特定柜子的所有箱子的信息。
     * 使用路径参数{@code code}来指定具体的柜子。
     *
     * @param code 柜子的唯一标识代码，作为路径参数传递。
     * @return 返回包含柜子箱子信息的对象。具体结构取决于实现。
     * @throws Exception 如果获取柜子箱子信息过程中发生错误。
     */
    @PostMapping("/cabinet/{code}/allbox/info")
    public Object cabinetBoxInfo(@PathVariable String code) throws Exception {
        return CacheUtils.get(CABINET_BOXS,code);
    }

    /**
     * 根据时间范围获取柜子统计（body需传{"startTime":"xxx","endTime":"xxx"} xxx为日期）。
     *
     * 此方法处理来自客户端的POST请求，旨在根据柜子代码获取特定柜子的统计信息。
     * 使用路径参数{@code code}来指定具体的柜子。
     *
     * @param code 柜子的唯一标识代码，作为路径参数传递。
     * @return 返回包含柜子统计信息的对象。具体结构取决于实现。
     * @throws Exception 如果获取柜子统计信息过程中发生错误。
     */
    @PostMapping("/cabinet/{code}/statistic")
    public Object cabinetBoxInfo(@PathVariable String code,@RequestBody Map<String,String> data) throws Exception {
        data = data == null?new HashMap<>():data;
        String startTime = data.get("startTime");
        String endTime = data.get("endTime");
        if(startTime == null || endTime == null){
            return R.fail("参数不完整");
        }
        return  CabinetUtil.getCabinetStatistics(code,startTime,endTime);
    }

    /**
     * 打开柜子指定格子。
     *
     * 此方法处理来自客户端的POST请求，旨在根据柜子代码获取特定柜子的统计信息。
     * 使用路径参数{@code code}来指定具体的柜子。
     *
     * @param code 柜子的唯一标识代码，作为路径参数传递。
     * @return 返回包含柜子统计信息的对象。具体结构取决于实现。
     * @throws Exception 如果获取柜子统计信息过程中发生错误。
     */
    @PostMapping("/cabinet/{code}/openlock/{lockAddress}")
    public Object openCabinetBox(@PathVariable String code,@PathVariable String lockAddress) throws Exception {
        return  CabinetUtil.openCabinetBoxs(code,lockAddress);
    }

    /**
     * 打开柜子所有格子。
     *
     * 此方法处理来自客户端的POST请求，旨在根据柜子代码获取特定柜子的统计信息。
     * 使用路径参数{@code code}来指定具体的柜子。
     *
     * @param code 柜子的唯一标识代码，作为路径参数传递。
     * @return 返回包含柜子统计信息的对象。具体结构取决于实现。
     * @throws Exception 如果获取柜子统计信息过程中发生错误。
     */
    @PostMapping("/cabinet/{code}/lock/openall")
    public Object openCabinetAllBox(@PathVariable String code) throws Exception {
        return  CabinetUtil.openCabinetBoxAll(code);
    }

    /**
     * 清理柜子的格子（不打开）。
     *
     * 此方法处理来自客户端的POST请求，旨在根据柜子代码获取特定柜子的统计信息。
     * 使用路径参数{@code code}来指定具体的柜子。
     *
     * @param code 柜子的唯一标识代码，作为路径参数传递。
     * @return 返回包含柜子统计信息的对象。具体结构取决于实现。
     * @throws Exception 如果获取柜子统计信息过程中发生错误。
     */
    @PostMapping("/cabinet/{code}/box/{boxuuid}/clear")
    public Object clearCabinetAllBox(@PathVariable String code,@PathVariable String boxuuid) throws Exception {
        return  CabinetUtil.clearCabinetBox(code,boxuuid);
    }

    /**
     * 清理柜子的格子（打开）。
     *
     * 此方法处理来自客户端的POST请求，旨在根据柜子代码获取特定柜子的统计信息。
     * 使用路径参数{@code code}来指定具体的柜子。
     *
     * @param code 柜子的唯一标识代码，作为路径参数传递。
     * @return 返回包含柜子统计信息的对象。具体结构取决于实现。
     * @throws Exception 如果获取柜子统计信息过程中发生错误。
     */
    @PostMapping("/cabinet/{code}/box/{boxuuid}/openclear")
    public Object clearOpenCabinetAllBox(@PathVariable String code,@PathVariable String boxuuid) throws Exception {
        return  CabinetUtil.clearCabinetBoxOpen(code,boxuuid);
    }

    /**
     * 获取取件码。
     *
     * 此方法处理来自客户端的POST请求，旨在根据柜子代码获取特定柜子的统计信息。
     * 使用路径参数{@code code}来指定具体的柜子。
     *
     * @param phone 手机号，作为路径参数传递。
     * @return 返回包含柜子统计信息的对象。具体结构取决于实现。
     * @throws Exception 如果获取柜子统计信息过程中发生错误。
     */
    @PostMapping("/cabinet/mobile/{phone}")
    public Object cabinetQJM(@PathVariable String phone) throws Exception {
        return  CabinetUtil.getQJM(phone);
    }






}
