import datetime
import re
from calendar import monthrange

NO_DATA_EXPRESS = ""


def get_current_date_time():
    """
    获取当前时间 datetime obj
    return current datetime obj
    :return:
    """
    return datetime.datetime.now()


def convert_to_dt(date):
    """
    convert date string to datatime obj
    :param date: 2018-01-01, 2018-01-01 12:00:00
    :return:
    """
    if type(date) is datetime.datetime:
        return date
    if date is None or date == "":
        return get_current_date_time()
    if re.match("\d\d\d\d-\d\d-\d\d$", date):
        return datetime.datetime.strptime(date, "%Y-%m-%d")
    elif re.match("\d\d\d\d-\d\d-\d\d \d\d:\d\d:\d\d$", date):
        return datetime.datetime.strptime(date, "%Y-%m-%d %H:%M:%S")
    elif re.match("\d\d\d\d$", date):
        return datetime.datetime.strptime(date, "%Y")
    elif re.match("\d\d\d\d-\d\d$", date):
        return datetime.datetime.strptime(date, "%Y-%m")
    elif re.match("\d\d\d\d-\d\d-\d\dT\d\d:\d\d:\d\d\+08:00$", date):
        return datetime.datetime.strptime(date, "%Y-%m-%dT%H:%M:%S+08:00")
    else:
        raise Exception("Invalid datetime string: %s" % date)


def get_slots_between_date(start, end, interval_type, growth_type=None):
    date_dts = []
    start = convert_to_dt(start)
    end = convert_to_dt(end)
    if interval_type == "day":
        if growth_type == "month":
            days = monthrange(start.year, start.month)[1]
            start = datetime.datetime(year=start.year, month=start.month,
                                      day=1)
            for i in range(days):
                date_dts.append([start, start + datetime.timedelta(days=1)])
                start += datetime.timedelta(days=1)
        else:
            while start <= end:
                date_dts.append([start, start + datetime.timedelta(days=1)])
                start += datetime.timedelta(days=1)
    elif interval_type == "month":
        start_months = start.year * 12 + start.month
        end_months = end.year * 12 + end.month
        year = start.year
        month = start.month
        for i in range(end_months - start_months + 1):
            if month > 12:
                year += 1
                month = 1
            if month == 12:
                sub_end_year = year + 1
                sub_end_month = 1
            else:
                sub_end_year = year
                sub_end_month = month + 1
            date_dts.append([datetime.datetime(year=year, month=month, day=1),
                            datetime.datetime(year=sub_end_year, month=sub_end_month, day=1)])
            month += 1
    elif interval_type == "year":
        for i in range(end.year - start.year + 1):
            date_dts.append([datetime.datetime(year=(start.year + i), month=1, day=1),
                             datetime.datetime(year=(start.year + i + 1), month=1, day=1)])
    elif interval_type == "15min":
        end += datetime.timedelta(days=1)
        slot_numbers = int((end.timestamp()-start.timestamp())/900)
        for i in range(slot_numbers):
            date_dts.append([start + datetime.timedelta(minutes=15*i),
                             start + datetime.timedelta(minutes=15*i+1)])
    elif interval_type == "hour":
        end += datetime.timedelta(days=1)
        slot_numbers = int((end.timestamp()-start.timestamp())/3600)
        for i in range(slot_numbers):
            date_dts.append([start + datetime.timedelta(hours=i),
                             start + datetime.timedelta(hours=i+1)])
    return date_dts


def get_current_date():
    """
    获取当前日期 datetime obj
    return current datetime obj
    :return:
    """
    now = get_current_date_time()
    return datetime.datetime(now.year, now.month, now.day)


def convert_dt_to_str(dt, date_type=None, just_month=False):
    """
    convert datetime object to string
    :param dt:
    :return:
    """
    if type(dt) is str:
        return dt
    if type(dt) is int:
        return dt
    if date_type == "day":
        return datetime.datetime.strftime(dt, "%m-%d")
    elif date_type == "hour":
        return datetime.datetime.strftime(dt, "%H:00")
    elif date_type == "15min":
        return datetime.datetime.strftime(dt, "%H:%M")
    elif date_type == "minute":
        return datetime.datetime.strftime(dt, "%H:%M")
    elif date_type == "year":
        return datetime.datetime.strftime(dt, "%Y")
    elif date_type == "month":
        if just_month:
            return datetime.datetime.strftime(dt, "%m月")
        return datetime.datetime.strftime(dt, "%Y-%m")
    else:
        return datetime.datetime.strftime(dt, "%Y-%m-%d %H:%M:%S")


def convert_number(number, divisor=10000, precision=2, convert_to_str=False):
    """

    :param number:
    :param divisor:
    :param precision:
    :return:
    """
    try:
        number = float(number) / divisor
        # round函数返回浮点数四舍五入
        number = round(number, precision)
        if convert_to_str:
            str_format = "%%.%sf" % precision
            return str_format % number
        return number
    except Exception as e:
        return number


def format_chart_data(datas, date_type="day", data_type="default"):
    """

    :param datas:
    {
        "2019-01-01": {
            "v1": 1,
            "v2": 2,
            "v3": 3
        },
        "2019-01-02": {
            "v1": 1,
            "v2": 2,
            "v3": 3
        }...
    }
    :param date_type: day, month, year, hour or 15min
    :return:
    {
        "v1": [["01:00", "02:00", ...], [1, 2, ...]],
        "v2": [["01:00", "02:00", ...], [1, 2, ...]],
        ...
    }
    """
    dates = list(datas.keys())
    dates.sort()
    date_strs = [convert_dt_to_str(date, date_type) for date in dates]
    sub_data_types = datas[dates[0]].keys()
    data = {}
    for sub_data_type in sub_data_types:
        data[sub_data_type] = []
        data[sub_data_type].append(date_strs)
        # print(sub_data_type, dates)
        # print(convert_number(datas[date][sub_data_type]) for date in dates)
        data[sub_data_type].append(list(
            convert_number(datas[date][sub_data_type], 1, 2) for date in
            dates))
    return data


DATA_FORMAT = {
    "default": {
        "unit": "",
        "precision": (1, 2)
    },
    "load": {
        "unit": "kW",
        "precision": (1, 0)
    },
    "load_rate": {
        "unit": "%",
        "precision": (0.01, 2)
    },
    "month_small_charge": {
        "unit": "元/月",
        "precision": (1, 2)
    },
    "month_charge": {
        "unit": "万元/月",
        "precision": (10000, 1)
    },
    "percentage": {
        "unit": "%",
        "precision": (0.01, 0)
    },
    "percentage2": {
        "unit": "%",
        "precision": (0.01, 2)
    },
    "plsi": {
        "unit": "",
        "precision": (1, 0)
    },
    "month_power": {
        "unit": "度/月",
        "precision": (1, 2)
    },
    "PCS": {
        "unit": "kW",
        "precision": (1, 2)
    },
    "battery": {
        "unit": "kWh",
        "precision": (1, 2)
    },
    "big_money": {
        "unit": "万元",
        "precision": (10000, 2)
    },
    "big_money4": {
        "unit": "万元",
        "precision": (10000, 4)
    },
    "big_weight4": {
        "unit": "吨",
        "precision": (1000, 4)
    },
    "day": {
        "unit": "天",
        "precision": (1, 0)
    },
    "year": {
        "unit": "年",
        "precision": (1, 0)
    },
    "tc": {
        "unit": "kVA",
        "precision": (1, 0)
    },
    "p": {
        "unit": "kW",
        "precision": (1, 2)
    },
}


def format_value(value, type="default", convert_to_str=True):
    if not type in DATA_FORMAT:
        type = "default"
    try:
        value = float(value)
    except Exception as e:
        return NO_DATA_EXPRESS, DATA_FORMAT[type]["unit"]
    value = convert_number(value, DATA_FORMAT[type]["precision"][0],
                           DATA_FORMAT[type]["precision"][1],
                           convert_to_str=convert_to_str)
    return value, DATA_FORMAT[type]["unit"]