import os
import pickle
import matplotlib.pyplot as plt
import numpy as np
import pandas as pd
import seaborn as sns


def plot_optimization_result(datasource, directory):
    sns.set_theme(style='whitegrid')  # "white", "dark", "whitegrid", "darkgrid", "ticks"
    plt.rcParams["figure.figsize"] = (16, 9)
    fig, axs = plt.subplots(2, 2)
    plt.subplots_adjust(wspace=0.7, hspace=0.3)
    plt.autoscale(tight=True)
    T = np.array([i for i in range(24)])

    # 绘制步长成本 in ax[0]
    axs[0, 0].cla()
    axs[0, 0].set_ylabel('Cost')
    axs[0, 0].set_xlabel('Time (h)')
    axs[0, 0].bar(T, datasource['step_cost'])

    # 绘制soc和价格 in ax[1]
    axs[0, 1].cla()
    # 设置第一个 y 轴
    axs[0, 1].set_ylabel('Price')
    axs[0, 1].set_xlabel('Time [h]')
    line1, = axs[0, 1].plot(T, datasource['price'], drawstyle='steps-mid', label='Price', color='pink')
    # 创建第二个 y 轴
    ax2 = axs[0, 1].twinx()
    ax2.set_ylabel('SOC')
    line2, = ax2.plot(T, datasource['soc'], drawstyle='steps-mid', label='SOC', color='grey')
    # 为每个轴分别创建图例
    lines = [line1, line2]
    labels = [line.get_label() for line in lines]
    axs[0, 1].legend(lines, labels, loc='upper right', bbox_to_anchor=(1.4, 1),
                     fontsize=12, frameon=False, labelspacing=0.3)

    # 绘制累计发电量和消耗量 in ax[2]
    axs[1, 0].cla()
    axs[1, 0].set_ylabel('Power [kWh]')
    axs[1, 0].set_xlabel('Time [h]')
    # 处理电池充放电数据
    battery_positive = np.maximum(np.array(datasource['battery_energy_change']), 0)  # charge
    battery_negative = np.minimum(np.array(datasource['battery_energy_change']), 0)  # discharge
    # 处理电网进出口数据
    imported_from_grid = np.array(datasource['grid_import'])
    exported_2_grid = np.array(datasource['grid_export'])

    axs[1, 0].bar(T, datasource['gen1'], label='Gen1')
    axs[1, 0].bar(T, datasource['gen2'], label='Gen2', bottom=datasource['gen1'])
    axs[1, 0].bar(T, datasource['gen3'], label='Gen3', bottom=datasource['gen2'] + datasource['gen1'])
    axs[1, 0].bar(T, -battery_positive, color='blue', hatch='/', label='ESS charge')
    axs[1, 0].bar(T, -battery_negative, hatch='/', label='ESS discharge',
                  bottom=datasource['gen3'] + datasource['gen2'] + datasource['gen1'])
    axs[1, 0].bar(T, datasource['pv'], label='Pv Gen',
                  bottom=-battery_negative + datasource['gen3'] + datasource['gen2'] + datasource['gen1'])
    axs[1, 0].bar(T, datasource['wind'], label='Wind Gen',
                  bottom=datasource['pv'] - battery_negative + datasource['gen3'] + datasource['gen2'] + datasource[
                      'gen1'])
    # 生成即进口
    axs[1, 0].bar(T, imported_from_grid, label='Grid import',
                  bottom=datasource['pv'] + datasource['wind'] - battery_negative + datasource['gen3'] + datasource[
                      'gen2'] + datasource['gen1'])
    # 负载即出口
    axs[1, 0].bar(T, -exported_2_grid, label='Grid export', bottom=-battery_positive)
    # 绘制净负载曲线
    axs[1, 0].plot(T, datasource['load'], linewidth=2.0, label='Load', drawstyle='steps-mid', alpha=0.7)
    axs[1, 0].legend(loc='upper right', bbox_to_anchor=(1.4, 1), fontsize=12, frameon=False, labelspacing=0.3)

    fig.savefig(f"{directory}/gurobi.svg", format='svg', dpi=600, bbox_inches='tight')
    print('gurobi figure have been ploted and saved')


def plot_evaluation_information(eval_data, directory):
    sns.set_theme(style='whitegrid')
    with open(eval_data, 'rb') as tf:
        test_data = pickle.load(tf)
    # 用条形图表示每一步的不平衡和奖励
    plt.rcParams["figure.figsize"] = (16, 9)
    fig, axs = plt.subplots(2, 2)
    plt.subplots_adjust(wspace=0.7, hspace=0.3)
    plt.autoscale(tight=True)

    # 为评估环境准备数据
    eval_data = pd.DataFrame(test_data['system_info'])
    eval_data.columns = ['time_step', 'price', 'load', 'action', 'real_action', 'soc', 'battery', 'gen1', 'gen2',
                         'gen3', 'pv', 'wind', 'unbalance', 'operation_cost', 'reward']

    # 绘制奖励 in axs[0]
    axs[0, 0].cla()
    axs[0, 0].set_xlabel('Time (h)')
    axs[0, 0].set_ylabel('Cost')
    axs[0, 0].bar(eval_data['time_step'], eval_data['operation_cost'])

    # 绘制能源充/放电与价格关系图 in ax[1]
    axs[0, 1].cla()
    axs[0, 1].set_xlabel('Time (h)')
    axs[0, 1].set_ylabel('Price')
    line1, = axs[0, 1].plot(eval_data['time_step'], eval_data['price'], drawstyle='steps-mid', label='Price',
                            color='pink')
    ax2 = axs[0, 1].twinx()
    ax2.set_ylabel('SOC')
    line2, = ax2.plot(eval_data['time_step'], eval_data['soc'], drawstyle='steps-mid', label='SOC', color='grey')
    lines = [line1, line2]
    labels = [line.get_label() for line in lines]
    axs[0, 1].legend(lines, labels, loc='upper right', bbox_to_anchor=(1.4, 1),
                     fontsize=12, frameon=False, labelspacing=0.3)

    # 绘制发电量和负载量 in ax[2]
    axs[1, 0].cla()
    axs[1, 0].set_xlabel('Time [h]')
    axs[1, 0].set_ylabel('Power [kWh]')
    # axs[1,0].set_xticks([i for i in range(24)], [i for i in range(1, 25)])

    battery_positive = np.maximum(np.array(eval_data['battery']), 0)  # charge
    battery_negative = np.minimum(np.array(eval_data['battery']), 0)  # discharge
    imported_from_grid = np.minimum(np.array(eval_data['unbalance']), 0)
    exported_2_grid = np.maximum(np.array(eval_data['unbalance']), 0)

    x = eval_data['time_step']
    axs[1, 0].bar(x, eval_data['gen1'], label='Gen1')
    axs[1, 0].bar(x, eval_data['gen2'], label='Gen2', bottom=eval_data['gen1'])
    axs[1, 0].bar(x, eval_data['gen3'], label='Gen3', bottom=eval_data['gen1'] + eval_data['gen2'])
    axs[1, 0].bar(x, -battery_positive, color='blue', hatch='/', label='ESS charge')
    axs[1, 0].bar(x, -battery_negative, label='ESS discharge', hatch='/',
                  bottom=eval_data['gen1'] + eval_data['gen2'] + eval_data['gen3'])

    axs[1, 0].bar(x, eval_data['pv'], label='Pv Gen',
                  bottom=-battery_negative + eval_data['gen3'] + eval_data['gen2'] + eval_data['gen1'])
    axs[1, 0].bar(x, eval_data['wind'], label='Wind Gen',
                  bottom=eval_data['pv'] - battery_negative + eval_data['gen3'] + eval_data['gen2'] + eval_data['gen1'])

    axs[1, 0].bar(x, imported_from_grid, label='Grid import',
                  bottom=eval_data['pv'] + eval_data['wind'] - battery_negative + eval_data['gen3'] + eval_data[
                      'gen2'] + eval_data['gen1'])
    axs[1, 0].bar(x, -exported_2_grid, label='Grid export', bottom=-battery_positive)

    axs[1, 0].plot(x, eval_data['load'], linewidth=2.0, drawstyle='steps-mid', label='Load')
    axs[1, 0].legend(loc='upper right', bbox_to_anchor=(1.4, 1), fontsize=12, frameon=False, labelspacing=0.3)

    # 绘制不平衡度 in axs[3]
    axs[1, 1].cla()
    axs[1, 1].set_xlabel('Time [h]')
    axs[1, 1].set_ylabel('Power [kWh]')
    axs[1, 1].bar(eval_data['time_step'], eval_data['unbalance'], label='Exchange with Grid', width=0.4)
    axs[1, 1].bar(eval_data['time_step'] + 0.4, eval_data['load'], label='netload', width=0.4)
    axs[1, 1].legend(loc='upper right', bbox_to_anchor=(1.45, 1), fontsize=12, frameon=False, labelspacing=0.5)
    # fig.savefig(f"{directory}/rl.svg", format='svg', dpi=600, bbox_inches='tight')
    print('rl figure have been ploted and saved')


def plot_soc(gurobi, rl_data, directory):
    with open(rl_data, 'rb') as tf:
        test_data = pickle.load(tf)

    rl_data = pd.DataFrame(test_data['system_info'])
    rl_data.columns = ['time_step', 'price', 'load', 'action', 'real_action', 'soc', 'battery', 'gen1', 'gen2',
                       'gen3', 'pv', 'wind', 'unbalance', 'operation_cost', 'reward']
    T = rl_data['time_step']

    plt.rcParams["figure.figsize"] = (6, 4)  # 10 3
    fig, axs = plt.subplots(1, 1)
    plt.autoscale(tight=True)

    axs.cla()
    axs.set_xlabel('Time [h]', fontsize=12)
    axs.set_ylabel('Price', fontsize=12)
    line1, = axs.plot(T, gurobi['price'] / 10, drawstyle='steps-mid', label='Price', color='pink')
    axs.grid(True, which='both', axis='y', linestyle='None', linewidth=0, color='black')
    axs.grid(True, which='both', axis='x', linestyle='--', linewidth=0.5, color='black')

    ax2 = axs.twinx()
    ax2.set_ylabel('SOC', fontsize=12)
    line2, = ax2.plot(T, gurobi['soc'], drawstyle='steps-mid', label='MILP', color='grey')
    line3, = ax2.plot(T, rl_data['soc'], drawstyle='steps-mid', label='LMPPO', color='blue')
    ax2.grid(True, which='both', axis='both', linestyle='--', linewidth=0.5, color='black')

    lines = [line1, line2, line3]
    labels = [line.get_label() for line in lines]
    axs.legend(lines, labels, loc='upper right', fontsize=12, frameon=True, framealpha=0.8)

    print('soc figure have been ploted and saved')
    fig.savefig(f"{directory}/soc.png", format='png', dpi=600, bbox_inches='tight')


def plot_energy(gurobi, rl_data, directory):
    with open(rl_data, 'rb') as tf:
        test_data = pickle.load(tf)

    rl_data = pd.DataFrame(test_data['system_info'])
    rl_data.columns = ['time_step', 'price', 'load', 'action', 'real_action', 'soc', 'battery', 'gen1', 'gen2',
                       'gen3', 'pv', 'wind', 'unbalance', 'operation_cost', 'reward']
    T = rl_data['time_step']

    plt.rcParams["figure.figsize"] = (6, 9)
    fig, axs = plt.subplots(2, 1)
    plt.subplots_adjust(wspace=0.5, hspace=0.3)
    plt.autoscale(tight=True)

    axs[0].cla()
    axs[0].set_xlabel('Time [h]\n(a)', fontsize=12)
    axs[0].set_ylabel('Power [kWh]', fontsize=12)
    # 电池充放电数据
    battery_positive = np.maximum(np.array(gurobi['battery_energy_change']), 0)
    battery_negative = np.minimum(np.array(gurobi['battery_energy_change']), 0)
    # 电网进出口数据
    imported_from_grid = np.array(gurobi['grid_import'])
    exported_2_grid = np.array(gurobi['grid_export'])

    axs[0].bar(T, gurobi['gen1'], label='Gen1')
    axs[0].bar(T, gurobi['gen2'], label='Gen2', bottom=gurobi['gen1'])
    axs[0].bar(T, gurobi['gen3'], label='Gen3', bottom=gurobi['gen2'] + gurobi['gen1'])
    axs[0].bar(T, -battery_positive, color='blue', hatch='/', label='ESS charge')
    axs[0].bar(T, -battery_negative, hatch='/', label='ESS discharge',
               bottom=gurobi['gen3'] + gurobi['gen2'] + gurobi['gen1'])
    axs[0].bar(T, gurobi['pv'], label='Pv',
               bottom=-battery_negative + gurobi['gen3'] + gurobi['gen2'] + gurobi['gen1'])
    axs[0].bar(T, gurobi['wind'], label='Wind',
               bottom=gurobi['pv'] - battery_negative + gurobi['gen3'] + gurobi['gen2'] + gurobi['gen1'])
    # 生成即进口
    axs[0].bar(T, imported_from_grid, label='Import',
               bottom=gurobi['pv'] + gurobi['wind'] - battery_negative + gurobi['gen3'] + gurobi['gen2'] + gurobi[
                   'gen1'])
    # 负载即出口
    axs[0].bar(T, -exported_2_grid, label='Export', bottom=-battery_positive)
    # 绘制净负载曲线
    axs[0].plot(T, gurobi['load'], linewidth=2.0, label='Load', drawstyle='steps-mid')
    axs[0].grid(True, which='both', axis='both', linestyle='--', linewidth=0.5, color='black')
    axs[0].legend(loc='upper right', bbox_to_anchor=(1.4, 1), fontsize=12, frameon=False, labelspacing=0.3)

    # rl
    axs[1].cla()
    axs[1].set_xlabel('Time [h]\n(b)', fontsize=12)
    axs[1].set_ylabel('Power [kWh]', fontsize=12)

    battery_positive = np.maximum(np.array(rl_data['battery']), 0)
    battery_negative = np.minimum(np.array(rl_data['battery']), 0)
    imported_from_grid = np.minimum(np.array(rl_data['unbalance']), 0)
    exported_2_grid = np.maximum(np.array(rl_data['unbalance']), 0)

    axs[1].bar(T, rl_data['gen1'], label='Gen1')
    axs[1].bar(T, rl_data['gen2'], label='Gen2', bottom=rl_data['gen1'])
    axs[1].bar(T, rl_data['gen3'], label='Gen3', bottom=rl_data['gen1'] + rl_data['gen2'])
    axs[1].bar(T, -battery_positive, color='blue', hatch='/', label='ESS charge')
    axs[1].bar(T, -battery_negative, label='ESS discharge', hatch='/',
               bottom=rl_data['gen1'] + rl_data['gen2'] + rl_data['gen3'])

    axs[1].bar(T, rl_data['pv'], label='Pv',
               bottom=-battery_negative + rl_data['gen3'] + rl_data['gen2'] + rl_data['gen1'])
    axs[1].bar(T, rl_data['wind'], label='Wind',
               bottom=rl_data['pv'] - battery_negative + rl_data['gen3'] + rl_data['gen2'] + rl_data['gen1'])

    axs[1].bar(T, imported_from_grid, label='Import',
               bottom=rl_data['pv'] + rl_data['wind'] - battery_negative + rl_data['gen3'] + rl_data[
                   'gen2'] + rl_data['gen1'])
    axs[1].bar(T, -exported_2_grid, label='Export', bottom=-battery_positive)

    axs[1].plot(T, rl_data['load'], linewidth=2.0, drawstyle='steps-mid', label='Load')
    axs[1].grid(True, which='both', axis='both', linestyle='--', linewidth=0.5, color='black')
    axs[1].legend(loc='upper right', bbox_to_anchor=(1.4, 1), fontsize=12, frameon=False, labelspacing=0.3)

    print('energy figure have been ploted and saved')
    # fig.savefig(f"{directory}/energy.png", format='png', dpi=600, bbox_inches='tight')


def plot_melt(ppo, llm, lmppo, milp, ram, directory):
    with open(ppo, 'rb') as t1:
        ppo = pickle.load(t1)
    with open(llm, 'rb') as t2:
        llm = pickle.load(t2)
    with open(lmppo, 'rb') as t3:
        lmppo = pickle.load(t3)
    with open(milp, 'rb') as t4:
        milp = pickle.load(t4)
    with open(ram, 'rb') as t5:
        ram = pickle.load(t5)

    T = lmppo.index
    milp['unbalance'] = 0
    plt.rcParams["figure.figsize"] = (6, 8)
    fig, (ax1, ax2) = plt.subplots(2, 1)
    plt.subplots_adjust(wspace=0.5, hspace=0.4)
    plt.autoscale(tight=True)

    print('ppo平均奖励', ppo['reward'].mean(), 'ppo平均不平衡度', ppo['unbalance'].mean()/1e3)
    print('llm平均奖励', llm['reward'].mean(), 'llm平均不平衡度', llm['unbalance'].mean()/1e3)
    print('lmppo平均奖励', lmppo['reward'].mean(), 'lmppo平均不平衡度', lmppo['unbalance'].mean()/1e3)
    print('milp平均奖励', milp['reward'].mean(), 'milp平均不平衡度', milp['unbalance'].mean()/1e3)
    print('ram平均奖励', ram['reward'].mean(), 'ram平均不平衡度', ram['unbalance'].mean()/1e3)
    ax1.cla()
    ax1.set_xlabel('Day\n(a)', fontsize=12)
    ax1.set_ylabel('Reward [-]', fontsize=12)
    ax1.plot(T, ppo['reward'], color='#374FE6', label='PPO', marker='o', markersize=5)
    ax1.plot(T, llm['reward'], color='#BB5D5D', label='LLM', marker='o', markersize=5)
    ax1.plot(T, lmppo['reward'], color='#6DBA4F', label='LMPPO', marker='o', markersize=5)
    ax1.plot(T, milp['reward'], color='#8B5B29', label='MILP', marker='o', markersize=5)
    ax1.plot(T, ram['reward'], color='#B0B0B0', label='RAN', marker='o', markersize=5)
    ax1.grid(True, which='both', axis='both', linestyle='--', linewidth=0.5, color='black')
    ax1.legend(loc='upper center', bbox_to_anchor=(0.5, 1.15), fontsize=12, frameon=False, ncol=5, labelspacing=0.3, columnspacing=1.5)

    ax2.cla()
    ax2.set_xlabel('Day\n(b)', fontsize=12)
    ax2.set_ylabel('Power imbalance [kW]', fontsize=12)
    ax2.plot(T, ppo['unbalance'] / 1e3, color='#374FE6', label='PPO', marker='o', markersize=5)
    ax2.plot(T, llm['unbalance'] / 1e3, color='#BB5D5D', label='LLM', marker='o', markersize=5)
    ax2.plot(T, lmppo['unbalance'] / 1e3, color='#6DBA4F', label='LMPPO', marker='o', markersize=5)
    ax2.plot(T, milp['unbalance'], color='#8B5B29', label='MILP', marker='o', markersize=5)
    ax2.plot(T, ram['unbalance'] / 1e3, color='#B0B0B0', label='RAN', marker='o', markersize=5)
    ax2.grid(True, which='both', axis='both', linestyle='--', linewidth=0.5, color='black')
    ax2.legend(loc='upper center', bbox_to_anchor=(0.5, 1.15), fontsize=12, frameon=False, ncol=5, labelspacing=0.3, columnspacing=1.5)

    print('melt figure have been ploted and saved')
    plt.autoscale()
    fig.savefig(f"{directory}/melt.png", format='png', dpi=600, bbox_inches='tight')


def make_dir(directory, feature_change):
    cwd = f'{directory}/DRL_{feature_change}_plots'
    os.makedirs(cwd, exist_ok=True)
    return cwd


class PlotArgs:
    def __init__(self) -> None:
        self.cwd = None
        self.feature_change = None
        self.plot_on = None
