#!/usr/bin/env python
# -*- coding:utf-8 -*-
"""
Date: 2024/3/20 16:00
Desc: 新浪财经-国内期货-实时数据获取
https://vip.stock.finance.sina.com.cn/quotes_service/view/qihuohangqing.html#titlePos_3
P.S. 注意采集速度, 容易封禁 IP, 如果不能访问请稍后再试
"""

import json
import time
from functools import lru_cache

import pandas as pd
import requests
import py_mini_racer

from akshare.futures.cons import (
    zh_subscribe_exchange_symbol_url,
    zh_match_main_contract_url,
    zh_match_main_contract_payload,
)
from akshare.futures.futures_contract_detail import futures_contract_detail
from akshare.utils import demjson


@lru_cache()
def futures_symbol_mark() -> pd.DataFrame:
    """
    期货的品种和代码映射
    https://vip.stock.finance.sina.com.cn/quotes_service/view/js/qihuohangqing.js
    :return: 期货的品种和代码映射
    :rtype: pandas.DataFrame
    """
    url = (
        "https://vip.stock.finance.sina.com.cn/quotes_service/view/js/qihuohangqing.js"
    )
    r = requests.get(url)
    r.encoding = "gb2312"
    data_text = r.text
    raw_json = data_text[data_text.find("{") : data_text.find("}") + 1]
    data_json = demjson.decode(raw_json)
    czce_mark_list = [item[1] for item in data_json["czce"][1:]]
    dce_mark_list = [item[1] for item in data_json["dce"][1:]]
    shfe_mark_list = [item[1] for item in data_json["shfe"][1:]]
    cffex_mark_list = [item[1] for item in data_json["cffex"][1:]]
    gfex_mark_list = [item[1] for item in data_json["gfex"][1:]]
    all_mark_list = (
        czce_mark_list
        + dce_mark_list
        + shfe_mark_list
        + cffex_mark_list
        + gfex_mark_list
    )

    czce_market_name_list = [data_json["czce"][0]] * len(czce_mark_list)
    dce_market_name_list = [data_json["dce"][0]] * len(dce_mark_list)
    shfe_market_name_list = [data_json["shfe"][0]] * len(shfe_mark_list)
    cffex_market_name_list = [data_json["cffex"][0]] * len(cffex_mark_list)
    gfex_market_name_list = [data_json["gfex"][0]] * len(gfex_mark_list)
    all_market_name_list = (
        czce_market_name_list
        + dce_market_name_list
        + shfe_market_name_list
        + cffex_market_name_list
        + gfex_market_name_list
    )

    czce_symbol_list = [item[0] for item in data_json["czce"][1:]]
    dce_symbol_list = [item[0] for item in data_json["dce"][1:]]
    shfe_symbol_list = [item[0] for item in data_json["shfe"][1:]]
    cffex_symbol_list = [item[0] for item in data_json["cffex"][1:]]
    gfex_symbol_list = [item[0] for item in data_json["gfex"][1:]]
    all_symbol_list = (
        czce_symbol_list
        + dce_symbol_list
        + shfe_symbol_list
        + cffex_symbol_list
        + gfex_symbol_list
    )

    temp_df = pd.DataFrame([all_market_name_list, all_symbol_list, all_mark_list]).T
    temp_df.columns = [
        "exchange",
        "symbol",
        "mark",
    ]
    return temp_df


def futures_zh_realtime(symbol: str = "PTA") -> pd.DataFrame:
    """
    期货品种当前时刻所有可交易的合约实时数据
    https://vip.stock.finance.sina.com.cn/quotes_service/view/qihuohangqing.html#titlePos_1
    :param symbol: 品种名称；可以通过 ak.futures_symbol_mark() 获取所有品种命名表
    :type symbol: str
    :return: 期货品种当前时刻所有可交易的合约实时数据
    :rtype: pandas.DataFrame
    """
    _futures_symbol_mark_df = futures_symbol_mark()
    symbol_mark_map = dict(
        zip(_futures_symbol_mark_df["symbol"], _futures_symbol_mark_df["mark"])
    )
    url = "https://vip.stock.finance.sina.com.cn/quotes_service/api/json_v2.php/Market_Center.getHQFuturesData"
    params = {
        "page": "1",
        "sort": "position",
        "asc": "0",
        "node": symbol_mark_map[symbol],
        "base": "futures",
    }
    r = requests.get(url, params=params)
    data_json = r.json()
    temp_df = pd.DataFrame(data_json)

    temp_df["trade"] = pd.to_numeric(temp_df["trade"], errors="coerce")
    temp_df["settlement"] = pd.to_numeric(temp_df["settlement"], errors="coerce")
    temp_df["presettlement"] = pd.to_numeric(temp_df["presettlement"], errors="coerce")
    temp_df["open"] = pd.to_numeric(temp_df["open"], errors="coerce")
    temp_df["high"] = pd.to_numeric(temp_df["high"], errors="coerce")
    temp_df["low"] = pd.to_numeric(temp_df["low"], errors="coerce")
    temp_df["close"] = pd.to_numeric(temp_df["close"], errors="coerce")
    temp_df["bidprice1"] = pd.to_numeric(temp_df["bidprice1"], errors="coerce")
    temp_df["askprice1"] = pd.to_numeric(temp_df["askprice1"], errors="coerce")
    temp_df["bidvol1"] = pd.to_numeric(temp_df["bidvol1"], errors="coerce")
    temp_df["askvol1"] = pd.to_numeric(temp_df["askvol1"], errors="coerce")
    temp_df["volume"] = pd.to_numeric(temp_df["volume"], errors="coerce")
    temp_df["position"] = pd.to_numeric(temp_df["position"], errors="coerce")
    temp_df["preclose"] = pd.to_numeric(temp_df["preclose"], errors="coerce")
    temp_df["changepercent"] = pd.to_numeric(temp_df["changepercent"], errors="coerce")
    temp_df["bid"] = pd.to_numeric(temp_df["bid"], errors="coerce")
    temp_df["ask"] = pd.to_numeric(temp_df["ask"], errors="coerce")
    temp_df["prevsettlement"] = pd.to_numeric(
        temp_df["prevsettlement"], errors="coerce"
    )
    return temp_df


def zh_subscribe_exchange_symbol(symbol: str = "cffex") -> pd.DataFrame:
    """
    交易所具体的可交易品种
    https://vip.stock.finance.sina.com.cn/quotes_service/view/qihuohangqing.html#titlePos_1
    :param symbol: choice of {'czce', 'dce', 'shfe', 'cffex', 'gfex'}
    :type symbol: str
    :return: 交易所具体的可交易品种
    :rtype: dict
    """
    r = requests.get(zh_subscribe_exchange_symbol_url)
    r.encoding = "gbk"
    data_text = r.text
    data_json = demjson.decode(
        data_text[data_text.find("{") : data_text.find("};") + 1]
    )
    if symbol == "czce":
        data_json["czce"].remove("郑州商品交易所")
        return pd.DataFrame(data_json["czce"])
    if symbol == "dce":
        data_json["dce"].remove("大连商品交易所")
        return pd.DataFrame(data_json["dce"])
    if symbol == "shfe":
        data_json["shfe"].remove("上海期货交易所")
        return pd.DataFrame(data_json["shfe"])
    if symbol == "cffex":
        data_json["cffex"].remove("中国金融期货交易所")
        return pd.DataFrame(data_json["cffex"])
    if symbol == "gfex":
        data_json["gfex"].remove("广州期货交易所")
        return pd.DataFrame(data_json["gfex"])


def match_main_contract(symbol: str = "cffex") -> str:
    """
    新浪财经-期货-主力合约
    https://vip.stock.finance.sina.com.cn/quotes_service/view/qihuohangqing.html#titlePos_1
    :param symbol: choice of {'czce', 'dce', 'shfe', 'cffex', 'gfex'}
    :type symbol: str
    :return: 主力合约的字符串
    :rtype: str
    """
    subscribe_exchange_list = []
    exchange_symbol_list = zh_subscribe_exchange_symbol(symbol).iloc[:, 1].tolist()
    for item in exchange_symbol_list:
        # item = 'sngz_qh'
        zh_match_main_contract_payload.update({"node": item})
        res = requests.get(
            zh_match_main_contract_url, params=zh_match_main_contract_payload
        )
        data_json = demjson.decode(res.text)
        data_df = pd.DataFrame(data_json)
        try:
            main_contract = data_df[data_df.iloc[:, 3:].duplicated()]
            print(main_contract["symbol"].values[0])
            subscribe_exchange_list.append(main_contract["symbol"].values[0])
        except:  # noqa: E722
            if len(data_df) == 1:
                subscribe_exchange_list.append(data_df["symbol"].values[0])
                print(data_df["symbol"].values[0])
            else:
                print(item, "无主力合约")
            continue
    print(f"{symbol}主力合约获取成功")
    return ",".join([item for item in subscribe_exchange_list])


def futures_zh_spot(
    symbol: str = "V2309",
    market: str = "CF",
    adjust: str = "0",
) -> pd.DataFrame:
    """
    期货的实时行情数据
    https://vip.stock.finance.sina.com.cn/quotes_service/view/qihuohangqing.html#titlePos_1
    :param symbol: 合约名称的字符串组合
    :type symbol: str
    :param market: CF 为商品期货
    :type market: str
    :param adjust: '1' or '0'；字符串的 0 或 1；返回合约、交易所和最小变动单位的实时数据, 返回数据会变慢
    :type adjust: str
    :return: 期货的实时行情数据
    :rtype: pandas.DataFrame
    """
    file_data = "Math.round(Math.random() * 2147483648).toString(16)"
    ctx = py_mini_racer.MiniRacer()
    rn_code = ctx.eval(file_data)
    subscribe_list = ",".join(["nf_" + item.strip() for item in symbol.split(",")])
    url = f"https://hq.sinajs.cn/rn={rn_code}&list={subscribe_list}"
    headers = {
        "Accept": "*/*",
        "Accept-Encoding": "gzip, deflate",
        "Accept-Language": "zh-CN,zh;q=0.9,en;q=0.8",
        "Cache-Control": "no-cache",
        "Host": "hq.sinajs.cn",
        "Pragma": "no-cache",
        "Proxy-Connection": "keep-alive",
        "Referer": "https://vip.stock.finance.sina.com.cn/",
        "User-Agent": "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) "
        "Chrome/97.0.4692.71 Safari/537.36",
    }
    r = requests.get(url, headers=headers)
    data_df = pd.DataFrame(
        [
            item.strip().split("=")[1].split(",")
            for item in r.text.split(";")
            if item.strip() != ""
        ]
    )
    data_df.iloc[:, 0] = data_df.iloc[:, 0].str.replace('"', "")
    data_df.iloc[:, -1] = data_df.iloc[:, -1].str.replace('"', "")
    if adjust == "1":
        contract_name_list = [item.split("_")[1] for item in subscribe_list.split(",")]
        contract_min_list = []
        contract_exchange_list = []
        for contract_name in contract_name_list:
            temp_df = futures_contract_detail(symbol=contract_name)
            exchange_name = temp_df[temp_df["item"] == "上市交易所"]["value"].values[0]
            contract_exchange_list.append(exchange_name)
            contract_min = temp_df[temp_df["item"] == "最小变动价位"]["value"].values[0]
            contract_min_list.append(contract_min)
        if market == "CF":
            data_df.columns = [
                "symbol",
                "time",
                "open",
                "high",
                "low",
                "last_close",
                "bid_price",
                "ask_price",
                "current_price",
                "avg_price",
                "last_settle_price",
                "buy_vol",
                "sell_vol",
                "hold",
                "volume",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
            ]
            data_df = data_df[
                [
                    "symbol",
                    "time",
                    "open",
                    "high",
                    "low",
                    "current_price",
                    "bid_price",
                    "ask_price",
                    "buy_vol",
                    "sell_vol",
                    "hold",
                    "volume",
                    "avg_price",
                    "last_close",
                    "last_settle_price",
                ]
            ]
            data_df["exchange"] = contract_exchange_list
            data_df["contract"] = contract_name_list
            data_df["contract_min_change"] = contract_min_list

            data_df["open"] = pd.to_numeric(data_df["open"], errors="coerce")
            data_df["high"] = pd.to_numeric(data_df["high"], errors="coerce")
            data_df["low"] = pd.to_numeric(data_df["low"], errors="coerce")
            data_df["current_price"] = pd.to_numeric(
                data_df["current_price"], errors="coerce"
            )
            data_df["bid_price"] = pd.to_numeric(data_df["bid_price"], errors="coerce")
            data_df["ask_price"] = pd.to_numeric(data_df["ask_price"], errors="coerce")
            data_df["buy_vol"] = pd.to_numeric(data_df["buy_vol"], errors="coerce")
            data_df["sell_vol"] = pd.to_numeric(data_df["sell_vol"], errors="coerce")
            data_df["hold"] = pd.to_numeric(data_df["hold"], errors="coerce")
            data_df["volume"] = pd.to_numeric(data_df["volume"], errors="coerce")
            data_df["avg_price"] = pd.to_numeric(data_df["avg_price"], errors="coerce")
            data_df["last_close"] = pd.to_numeric(
                data_df["last_close"], errors="coerce"
            )
            data_df["last_settle_price"] = pd.to_numeric(
                data_df["last_settle_price"], errors="coerce"
            )
            data_df.dropna(subset=["current_price"], ignore_index=True, inplace=True)
            return data_df
        else:
            data_df.columns = [
                "open",
                "high",
                "low",
                "current_price",
                "volume",
                "amount",
                "hold",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "__",
                "time",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "symbol",
            ]
            data_df = data_df[
                [
                    "symbol",
                    "time",
                    "open",
                    "high",
                    "low",
                    "current_price",
                    "hold",
                    "volume",
                    "amount",
                ]
            ]
            data_df["exchange"] = contract_exchange_list
            data_df["contract"] = contract_name_list
            data_df["contract_min_change"] = contract_min_list
            data_df["open"] = pd.to_numeric(data_df["open"], errors="coerce")
            data_df["high"] = pd.to_numeric(data_df["high"], errors="coerce")
            data_df["low"] = pd.to_numeric(data_df["low"], errors="coerce")
            data_df["current_price"] = pd.to_numeric(
                data_df["current_price"], errors="coerce"
            )
            data_df["hold"] = pd.to_numeric(data_df["hold"], errors="coerce")
            data_df["volume"] = pd.to_numeric(data_df["volume"], errors="coerce")
            data_df["amount"] = pd.to_numeric(data_df["amount"], errors="coerce")
            data_df.dropna(subset=["current_price"], ignore_index=True, inplace=True)
            return data_df
    else:
        if market == "CF":
            # 此处由于 20220601 接口变动，增加了字段，此处增加异常判断，except 后为新代码
            try:
                data_df.columns = [
                    "symbol",
                    "time",
                    "open",
                    "high",
                    "low",
                    "last_close",
                    "bid_price",
                    "ask_price",
                    "current_price",
                    "avg_price",
                    "last_settle_price",
                    "buy_vol",
                    "sell_vol",
                    "hold",
                    "volume",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                ]
            except:  # noqa: E722
                data_df.columns = [
                    "symbol",
                    "time",
                    "open",
                    "high",
                    "low",
                    "last_close",
                    "bid_price",
                    "ask_price",
                    "current_price",
                    "avg_price",
                    "last_settle_price",
                    "buy_vol",
                    "sell_vol",
                    "hold",
                    "volume",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                    "_",
                ]
            data_df = data_df[
                [
                    "symbol",
                    "time",
                    "open",
                    "high",
                    "low",
                    "current_price",
                    "bid_price",
                    "ask_price",
                    "buy_vol",
                    "sell_vol",
                    "hold",
                    "volume",
                    "avg_price",
                    "last_close",
                    "last_settle_price",
                ]
            ]

            data_df["open"] = pd.to_numeric(data_df["open"], errors="coerce")
            data_df["high"] = pd.to_numeric(data_df["high"], errors="coerce")
            data_df["low"] = pd.to_numeric(data_df["low"], errors="coerce")
            data_df["current_price"] = pd.to_numeric(
                data_df["current_price"], errors="coerce"
            )
            data_df["bid_price"] = pd.to_numeric(data_df["bid_price"], errors="coerce")
            data_df["ask_price"] = pd.to_numeric(data_df["ask_price"], errors="coerce")
            data_df["buy_vol"] = pd.to_numeric(data_df["buy_vol"], errors="coerce")
            data_df["sell_vol"] = pd.to_numeric(data_df["sell_vol"], errors="coerce")
            data_df["hold"] = pd.to_numeric(data_df["hold"], errors="coerce")
            data_df["volume"] = pd.to_numeric(data_df["volume"], errors="coerce")
            data_df["avg_price"] = pd.to_numeric(data_df["avg_price"], errors="coerce")
            data_df["last_close"] = pd.to_numeric(
                data_df["last_close"], errors="coerce"
            )
            data_df["last_settle_price"] = pd.to_numeric(
                data_df["last_settle_price"], errors="coerce"
            )
            data_df.dropna(subset=["current_price"], ignore_index=True, inplace=True)
            return data_df
        else:
            data_df.columns = [
                "open",
                "high",
                "low",
                "current_price",
                "volume",
                "amount",
                "hold",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "__",
                "time",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "_",
                "symbol",
            ]
            data_df = data_df[
                [
                    "symbol",
                    "time",
                    "open",
                    "high",
                    "low",
                    "current_price",
                    "hold",
                    "volume",
                    "amount",
                ]
            ]
            data_df["open"] = pd.to_numeric(data_df["open"], errors="coerce")
            data_df["high"] = pd.to_numeric(data_df["high"], errors="coerce")
            data_df["low"] = pd.to_numeric(data_df["low"], errors="coerce")
            data_df["current_price"] = pd.to_numeric(
                data_df["current_price"], errors="coerce"
            )
            data_df["hold"] = pd.to_numeric(data_df["hold"], errors="coerce")
            data_df["volume"] = pd.to_numeric(data_df["volume"], errors="coerce")
            data_df["amount"] = pd.to_numeric(data_df["amount"], errors="coerce")
            data_df.dropna(subset=["current_price"], inplace=True, ignore_index=True)
            return data_df


def futures_zh_minute_sina(symbol: str = "IF2008", period: str = "1") -> pd.DataFrame:
    """
    中国各品种期货分钟频率数据
    https://vip.stock.finance.sina.com.cn/quotes_service/view/qihuohangqing.html#titlePos_3
    :param symbol: 可以通过 match_main_contract(symbol="cffex") 获取, 或者访问网页获取
    :type symbol: str
    :param period: choice of {"1": "1分钟", "5": "5分钟", "15": "15分钟", "30": "30分钟", "60": "60分钟"}
    :type period: str
    :return: 指定 symbol 和 period 的数据
    :rtype: pandas.DataFrame
    """
    url = "https://stock2.finance.sina.com.cn/futures/api/jsonp.php/=/InnerFuturesNewService.getFewMinLine"
    params = {
        "symbol": symbol,
        "type": period,
    }
    r = requests.get(url, params=params)
    temp_df = pd.DataFrame(json.loads(r.text.split("=(")[1].split(");")[0]))
    temp_df.columns = [
        "datetime",
        "open",
        "high",
        "low",
        "close",
        "volume",
        "hold",
    ]
    temp_df["open"] = pd.to_numeric(temp_df["open"], errors="coerce")
    temp_df["high"] = pd.to_numeric(temp_df["high"], errors="coerce")
    temp_df["low"] = pd.to_numeric(temp_df["low"], errors="coerce")
    temp_df["close"] = pd.to_numeric(temp_df["close"], errors="coerce")
    temp_df["volume"] = pd.to_numeric(temp_df["volume"], errors="coerce")
    temp_df["hold"] = pd.to_numeric(temp_df["hold"], errors="coerce")
    return temp_df


def futures_zh_daily_sina(symbol: str = "RB0") -> pd.DataFrame:
    """
    中国各品种期货日频率数据
    https://finance.sina.com.cn/futures/quotes/V2105.shtml
    :param symbol: 可以通过 match_main_contract(symbol="cffex") 获取, 或者访问网页获取
    :type symbol: str
    :return: 指定 symbol 的数据
    :rtype: pandas.DataFrame
    """
    date = "20210412"
    url = (
        "https://stock2.finance.sina.com.cn/futures/api/jsonp.php/var%20_V21052021_4_12="
        "/InnerFuturesNewService.getDailyKLine"
    )
    params = {
        "symbol": symbol,
        "type": "_".join([date[:4], date[4:6], date[6:]]),
    }
    r = requests.get(url, params=params)
    temp_df = pd.DataFrame(json.loads(r.text.split("=(")[1].split(");")[0]))
    temp_df.columns = [
        "date",
        "open",
        "high",
        "low",
        "close",
        "volume",
        "hold",
        "settle",
    ]
    temp_df["open"] = pd.to_numeric(temp_df["open"], errors="coerce")
    temp_df["high"] = pd.to_numeric(temp_df["high"], errors="coerce")
    temp_df["low"] = pd.to_numeric(temp_df["low"], errors="coerce")
    temp_df["close"] = pd.to_numeric(temp_df["close"], errors="coerce")
    temp_df["volume"] = pd.to_numeric(temp_df["volume"], errors="coerce")
    temp_df["hold"] = pd.to_numeric(temp_df["hold"], errors="coerce")
    temp_df["settle"] = pd.to_numeric(temp_df["settle"], errors="coerce")
    return temp_df


if __name__ == "__main__":
    match_main_contract_df = match_main_contract(symbol="gfex")
    print(match_main_contract_df)

    futures_zh_spot_df = futures_zh_spot(symbol="V2405,V2409", market="CF", adjust="0")
    print(futures_zh_spot_df)

    futures_zh_spot_df = futures_zh_spot(symbol="V2405", market="CF", adjust="0")
    print(futures_zh_spot_df)

    futures_symbol_mark_df = futures_symbol_mark()
    print(futures_symbol_mark_df)

    futures_zh_realtime_df = futures_zh_realtime(symbol="工业硅")
    print(futures_zh_realtime_df)

    futures_zh_minute_sina_df = futures_zh_minute_sina(symbol="RB0", period="1")
    print(futures_zh_minute_sina_df)

    futures_zh_daily_sina_df = futures_zh_daily_sina(symbol="RB0")
    print(futures_zh_daily_sina_df)

    futures_zh_daily_sina_df = futures_zh_daily_sina(symbol="RB2410")
    print(futures_zh_daily_sina_df)

    dce_text = match_main_contract(symbol="dce")
    czce_text = match_main_contract(symbol="czce")
    shfe_text = match_main_contract(symbol="shfe")
    gfex_text = match_main_contract(symbol="gfex")

    while True:
        time.sleep(3)
        futures_zh_spot_df = futures_zh_spot(
            symbol=",".join([dce_text, czce_text, shfe_text, gfex_text]),
            market="CF",
            adjust="0",
        )
        print(futures_zh_spot_df)
