package com.yutou.bilibili.BiliBili;

import com.yutou.bilibili.BiliBili.Datas.BiliBiliUpData;
import com.yutou.bilibili.BiliBili.Datas.GiftData;
import com.alibaba.fastjson.JSON;
import com.alibaba.fastjson.JSONArray;
import com.alibaba.fastjson.JSONObject;
import com.yutou.bilibili.BiliBili.Services.IBiliBiliLiveService;
import com.yutou.bilibili.BiliBili.Tools.SaveLive;
import com.yutou.bilibili.Tools.AppTools;
import com.yutou.bilibili.Tools.Log;
import com.yutou.bilibili.Tools.RedisTools;
import com.yutou.bilibili.mybatis.Bili.mybatis.model.BilibiliUpInfo;
import org.springframework.util.StringUtils;

import javax.annotation.Resource;
import javax.xml.bind.DatatypeConverter;
import java.io.*;
import java.net.HttpURLConnection;
import java.net.URL;
import java.nio.ByteBuffer;
import java.nio.charset.StandardCharsets;
import java.util.*;
import java.util.zip.Inflater;

public class LiveUtils {
    private static String cookie = null;
    private static Map<Integer,Boolean> liveStateMap=new HashMap<>();

    public LiveUtils() {

    }


    public static String getLiveUrl(int roomId) {
        JSONObject json = http_get("https://api.live.bilibili.com/xlive/web-room/v1/index/getDanmuInfo?id=" + roomId + "&type=0");
        if (json != null) {
            return "wss://" + json.getJSONObject("data").getJSONArray("host_list").getJSONObject(0).getString("host") + "/sub";
        }
        return null;
    }

    public static void printHex(byte[] bytes) {
        String str = DatatypeConverter.printHexBinary(bytes);
        for (int i = 0; i < str.length(); i = i + 4) {
            if (i % 32 == 0 && i != 0) {
                com.yutou.bilibili.Tools.Log.i("\n");
            }
            if (str.length() - i > 4) {
                com.yutou.bilibili.Tools.Log.i(str.substring(i, i + 4));
            } else {
                com.yutou.bilibili.Tools.Log.i(str.substring(i));
            }
        }
    }
    public static String getHex(byte[] bytes){
        return DatatypeConverter.printHexBinary(bytes);
    }

    public static byte[] dec(byte[] data) {
        byte[] output = new byte[0];

        Inflater decompresser = new Inflater();
        decompresser.reset();
        decompresser.setInput(data);

        ByteArrayOutputStream o = new ByteArrayOutputStream(data.length);
        try {
            byte[] buf = new byte[1024];
            while (!decompresser.finished()) {
                int i = decompresser.inflate(buf);
                o.write(buf, 0, i);
            }
            output = o.toByteArray();
        } catch (Exception e) {
            // com.yutou.bilibili.Tools.Log.e(e);
            try {
                JSONObject json = JSONObject.parseObject(new String(data, StandardCharsets.UTF_8));
                ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
                // outputStream.write(toLH(json.toJSONString().length() + 16));
                //outputStream.write(new byte[]{0, 16, 0, 1, 0, 0, 0, 5, 0, 0, 0, 1});
                outputStream.write(json.toJSONString().getBytes(StandardCharsets.UTF_8));
                output = outputStream.toByteArray();
            } catch (Exception e1) {
                output = data;
            }
        } finally {
            try {
                o.close();
            } catch (IOException e) {
                com.yutou.bilibili.Tools.Log.e(e);
            }
        }

        decompresser.end();
        return output;
    }

    public static List<String> getMsgList(byte[] bytes, List<String> list, boolean isOne) {
        int len = 16;
        ByteBuffer datas = ByteBuffer.allocate(bytes.length - len);
        byte[] heads = new byte[4];
        //获取到头信息
        System.arraycopy(bytes, 0, heads, 0, 4);
        int size = bytesToInt2(heads, 0) - 16;

        //datas=MainApp.dec(datas);
        if (size == datas.array().length) {
            System.arraycopy(bytes, len, datas.array(), 0, bytes.length - len);
            list.add(new String(datas.array(), StandardCharsets.UTF_8));
        } else {
            try {
                // com.yutou.bilibili.Tools.Log.i("datas size = " + size);
                if (size > 1000000000) {
                    try {
                        JSONObject.parseObject(new String(bytes));
                        list.add(new String(bytes, StandardCharsets.UTF_8));
                        return list;
                    } catch (Exception e) {
                        com.yutou.bilibili.Tools.Log.e(e);
                    }
                }
                datas.clear();
                datas = ByteBuffer.allocate(size);
                System.arraycopy(bytes, len, datas.array(), 0, size);
                list.add(new String(datas.array(), StandardCharsets.UTF_8));
                byte[] tmps = new byte[bytes.length - size - 16];
                int length = bytes.length - (size + len);
                System.arraycopy(bytes, size + (len), tmps, 0, length);

                getMsgList(tmps, list, false);
            } catch (Exception e) {
                list.add(new String(bytes, StandardCharsets.UTF_8));
            }

        }
        return list;
    }

    public static byte[] toLH(int n) {
        byte[] b = new byte[4];
        b[3] = (byte) (n & 0xff);
        b[2] = (byte) (n >> 8 & 0xff);
        b[1] = (byte) (n >> 16 & 0xff);
        b[0] = (byte) (n >> 24 & 0xff);
        return b;
    }

    public static int bytesToInt2(byte[] src, int offset) {
        int value;
        value = (int) (((src[offset] & 0xFF) << 24)
                | ((src[offset + 1] & 0xFF) << 16)
                | ((src[offset + 2] & 0xFF) << 8)
                | (src[offset + 3] & 0xFF));
        return value;
    }

    public static String getCookie() {
        if (StringUtils.isEmpty(getFile("cookies.json"))) {

            return "";
        }
        JSONObject json = JSONObject.parseObject(getFile("cookies.json"));
        StringBuilder builder = new StringBuilder();
        for (String s : json.keySet()) {
            builder.append(s).append("=").append(json.getString(s)).append(";");

        }
        return builder.toString();
    }

    /* public static String createCookie(){
         String bid="AUTO"+AppTools.randomString(16,new String[]{AppTools.numbers});
         bid="AUTO6616152607312876";
         return String.format("LIVE_BUVID=%s; _uuid=%sinfoc; buvid3=%sinfoc; sid=%s; fingerprint=%s; buvid_fp=%sinfoc; buvid_fp_plain=%sinfoc; PVID=%d;"
                 ,bid
                 ,UUID.randomUUID().toString()
                 ,UUID.randomUUID().toString()
                 ,"bm3byv4p"
                 ,"074eae35a01a56c40558a54ab33179e5"
                 ,UUID.randomUUID().toString()
                 ,UUID.randomUUID().toString()
                 ,AppTools.randomCommon(0,9,1)[0]);
     }*/
    private static long oldBiliBiliHttpTime = 0;

    public synchronized static JSONObject http_get(String url) {
        try {
          //  Log.i("调用url = "+url);
            HttpURLConnection connection = getBiliHttpGet(url, getCookie());
            BufferedInputStream stream = new BufferedInputStream(connection.getInputStream());
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] bytes = new byte[1024];
            int len = 0, size;
            while ((len = stream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, len);
                outputStream.flush();
            }
            String str = new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
            outputStream.close();
            try {
                JSONObject json = JSON.parseObject(str);
                return json;
            } catch (Exception e) {
                JSONObject json = new JSONObject();
                json.put("html", str);
                return json;
            } finally {

                stream.close();
                connection.disconnect();
            }

        } catch (IOException e) {
            //com.yutou.bilibili.Tools.Log.e(e);
            Log.e(e);
            Log.i("412 in " + url);
        }
        return null;
    }

    public static JSONObject http_post(String url, String body) {
        try {
            if (System.currentTimeMillis() - oldBiliBiliHttpTime < 1000) {
                try {
                    Thread.sleep(500);
                } catch (InterruptedException e) {
                    com.yutou.bilibili.Tools.Log.e(e);
                }
                oldBiliBiliHttpTime = System.currentTimeMillis();
            }
            HttpURLConnection connection = getBiliHttpPost(url, getCookie());
            OutputStream connectionOutputStream = null;
            if (!StringUtils.isEmpty(body)) {
                connectionOutputStream = connection.getOutputStream();
                connectionOutputStream.write(body.getBytes(StandardCharsets.UTF_8));
                connectionOutputStream.flush();
            }
            BufferedInputStream stream = new BufferedInputStream(connection.getInputStream());
            ByteArrayOutputStream outputStream = new ByteArrayOutputStream();
            byte[] bytes = new byte[1024];
            int len = 0, size;
            while ((len = stream.read(bytes)) != -1) {
                outputStream.write(bytes, 0, len);
                outputStream.flush();
            }
            String str = new String(outputStream.toByteArray(), StandardCharsets.UTF_8);
            outputStream.close();
            try {
                JSONObject json = JSON.parseObject(str);
                json.put("cookie", connection.getHeaderField("Set-Cookie"));
                return json;
            } catch (Exception e) {
                JSONObject json = new JSONObject();
                json.put("html", str);
                json.put("cookie", connection.getHeaderField("Set-Cookie"));
                return json;
            } finally {
                stream.close();
                if (connectionOutputStream != null) {
                    connectionOutputStream.close();
                }
                connection.disconnect();
            }

        } catch (Exception e) {
            com.yutou.bilibili.Tools.Log.e(e);
        }
        return new JSONObject();
    }

    public static HttpURLConnection getBiliHttpPost(String url, String cookie) throws Exception {
        if (System.currentTimeMillis() - oldBiliBiliHttpTime < 1000) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                com.yutou.bilibili.Tools.Log.e(e);
            }
            oldBiliBiliHttpTime = System.currentTimeMillis();
        }
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        connection.setRequestMethod("POST");
        connection.setDoOutput(true);
        connection.setDoInput(true);
        connection.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        connection.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8");
        connection.setRequestProperty("Cache-Control", "max-age=0");
        connection.setRequestProperty("Referer", "https://live.bilibili.com");
        connection.setRequestProperty("Connection", "keep-alive");
        connection.setRequestProperty("Upgrade-Insecure-Requests", "1");
        connection.setRequestProperty("Cookie", cookie);
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36");
        return connection;
    }

    public static HttpURLConnection getBiliHttpGet(String url, String cookie) throws IOException {
        if (System.currentTimeMillis() - oldBiliBiliHttpTime < 1000) {
            try {
                Thread.sleep(500);
            } catch (InterruptedException e) {
                com.yutou.bilibili.Tools.Log.e(e);
            }
            oldBiliBiliHttpTime = System.currentTimeMillis();
        }
        HttpURLConnection connection = (HttpURLConnection) new URL(url).openConnection();
        connection.setRequestProperty("Accept", "text/html,application/xhtml+xml,application/xml;q=0.9,image/webp,*/*;q=0.8");
        connection.setRequestProperty("Accept-Language", "zh-CN,zh;q=0.8");
        connection.setRequestProperty("Cache-Control", "max-age=0");
        connection.setRequestProperty("Referer", "https://live.bilibili.com");
        connection.setRequestProperty("Connection", "keep-alive");
        connection.setRequestProperty("Upgrade-Insecure-Requests", "1");
        connection.setRequestProperty("Cookie", cookie);
        connection.setRequestProperty("User-Agent", "Mozilla/5.0 (Windows NT 6.1; WOW64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/44.0.2403.157 Safari/537.36");
        connection.setReadTimeout(5000);
        connection.setConnectTimeout(5000);
        return connection;
    }


    public static String getFile(String filePath) {
        File file = new File(filePath);
        try {
            BufferedReader reader = new BufferedReader(new FileReader(file));
            String str = "", tmp;
            while ((tmp = reader.readLine()) != null) {
                str += tmp;
            }
            reader.close();
            return str;
        } catch (Exception e) {

        }
        return null;
    }


    public static JSONObject getUserLoginInfo() {
        return LiveUtils.http_get("https://api.bilibili.com/x/web-interface/nav");
    }

    public static Live liveContains(BilibiliUpInfo data) {
        for (Live live : Live.lives.values()) {
            if (live.getInfo().getRoomid().equals(data.getRoomid())) {
                return live;
            }
        }
        return null;
    }

    public static JSONObject getLiveInfo(int roomId) {
        return http_get("https://api.live.bilibili.com/xlive/web-room/v1/index/getInfoByRoom?room_id=" + roomId+"&protocol=0,1&format=0,1,2&codec=0,1&qn=10000&platform=web&ptype=8");

    }
    public static boolean getLiveState(int roomId){
        return liveStateMap.get(roomId);
    }
    public static void reloadLiveState(int roomId){
        JSONObject json = getLiveInfo(roomId);
        if(json!=null){
            liveStateMap.put(roomId,json.getJSONObject("data").getInteger("live_status") == 1);
        }
    }

    public static String getLiveTitle(int roomId) {
        JSONObject json =getLiveInfo(roomId);
        if (json != null) {
            return json.getJSONObject("data").getJSONObject("room_info").getString("title");
        }
        return null;
    }

    public static boolean isLivePlayer(int roomId) {
       /* if (liveStateMap.containsKey(roomId)) {
            return liveStateMap.get(roomId);
        }
        reloadLiveState(roomId);
        return false;*/
        if(!Live.lives.containsKey(roomId)){
            return false;
        }
        return Live.lives.get(roomId).geData().getLive()==1;
    }

    private static void checkLiveSave(int roomId) {
        BilibiliUpInfo upData = new BilibiliUpInfo();
        upData.setRoomid(roomId);
        Live live = liveContains(upData);
        if (live == null) {
            live = new Live();
            live.add(roomId, !StringUtils.isEmpty(AppTools.readFile(new File("cookies.json"))));
        }
        if (!SaveLive.getInstance().checkLive(roomId)) {
            SaveLive.getInstance().addLive(roomId);
        }

    }

    public static class LiveGiftConfig {
        @Resource
        IBiliBiliLiveService service;
        private static LiveGiftConfig config;

        public static LiveGiftConfig getInstance() {
            if (config == null) {
                config = new LiveGiftConfig();
            }
            return config;
        }

        private LiveGiftConfig() {
            init();
        }

        public void init() {
            JSONObject json = http_get("https://api.live.bilibili.com/xlive/web-room/v1/giftPanel/giftConfig?platform=pc");
            if(json==null){
                return;
            }
            JSONArray list = json.getJSONObject("data").getJSONArray("list");
            for (Object o : list) {
                JSONObject item = (JSONObject) o;
                RedisTools.set(2,"bili_gift_"+item.getInteger("id"),item.toJSONString());
            }
        }

    }

    public static void main(String[] args) {
    }

}
