package gui;

import com.github.lgooddatepicker.components.DatePickerSettings;
import com.github.lgooddatepicker.components.DateTimePicker;
import com.github.lgooddatepicker.components.TimePickerSettings;
import config.Labels;
import core.manager.ColorManager;
import core.manager.ConstantManager;
import core.parameter.ParameterBuilder;
import core.processing.GetFromRemoteAndStore;
import gui.chart.ChartDatasetManager;
import gui.gantt.MonitorGantt2;
import gui.table.RawDataTable;
import gui.util.ProgressBarUtil;
import lombok.Getter;
import lombok.Setter;
import lombok.extern.slf4j.Slf4j;
import net.miginfocom.swing.MigLayout;
import org.jfree.chart.util.GanttParam;
import config.profile.ConnProfile;
import profile.IProfile;
import store.StoreManager;

import javax.inject.Inject;
import javax.inject.Named;
import javax.inject.Singleton;
import javax.swing.*;
import javax.swing.border.EtchedBorder;
import java.awt.*;
import java.awt.event.ItemEvent;
import java.io.IOException;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.LinkedHashMap;
import java.util.Map;
import java.util.concurrent.atomic.AtomicInteger;

@Slf4j
@Singleton
public class MonitorDbPanel {
    private BasicFrame jFrame;
    private ColorManager colorManager;
    private StoreManager storeManager;
    private GetFromRemoteAndStore getFromRemoteAndStore;

    private ChartDatasetManager chartDatasetManager;
    private MainTabbedPane mainTabbedPane;

    private JSplitPane topActivitySplitPane;
    private JSplitPane detailSplitPane;
    private JTabbedPane mainGanttAndRaw;
    private JTabbedPane detailGanttAndRaw;

    private JPanel controlMainDetailHistory;

    private MonitorGantt2 monitorGantt20;
    private RawDataTable rawDataTable20;

    @Getter @Setter private ConnProfile connProfile;
    @Getter @Setter private IProfile iProfile;

    @Getter @Setter private HistoryPanel historyPanel;

    @Inject
    public MonitorDbPanel(BasicFrame jFrame,
                          ColorManager colorManager,
                          StoreManager storeManager,
                          GetFromRemoteAndStore getFromRemoteAndStore,
                          @Named("mainTabPane") MainTabbedPane mainTabbedPane,
                          ChartDatasetManager chartDatasetManager) {
        this.jFrame = jFrame;
        this.colorManager = colorManager;
        this.storeManager = storeManager;
        this.getFromRemoteAndStore = getFromRemoteAndStore;
        this.mainTabbedPane = mainTabbedPane;
        this.chartDatasetManager = chartDatasetManager;
    }

    public void initialize() {
        try {
            storeManager.setUpBDBAndDAO(connProfile.getConnName());
        } catch (IOException e) {
            e.printStackTrace();
        }

        initializeChartDataset();
    }

    public void initializeGui(){
        topActivitySplitPane = new JSplitPane();
        topActivitySplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
        topActivitySplitPane.setOneTouchExpandable(true);
        topActivitySplitPane.setDividerSize(10);
        topActivitySplitPane.setDividerLocation(300);

        mainGanttAndRaw = new JTabbedPane();
        mainGanttAndRaw.add("Top sql & sessions", chartDatasetManager.getMainNameChartDataset().getMonitorGantt2());
        mainGanttAndRaw.add("Raw data", chartDatasetManager.getMainNameChartDataset().getRawDataTable());
        mainGanttAndRaw.add("ASH Report", chartDatasetManager.getMainNameChartDataset().getAshReport());

        topActivitySplitPane.add(chartDatasetManager.getMainNameChartDataset().getStackChartPanel(), JSplitPane.TOP);
        topActivitySplitPane.add(mainGanttAndRaw, JSplitPane.BOTTOM);

        chartDatasetManager.getMainNameChartDataset().getMonitorGantt2().setHistory(false);

        loadDetailChart();
        loadHistory();
    }

    public void adddGui(){
        mainTabbedPane.add("Top Activity", topActivitySplitPane);
        mainTabbedPane.add("Detail", detailSplitPane);
        mainTabbedPane.add("History", controlMainDetailHistory);
    }

    public void addGuiHistory(){
        mainTabbedPane.add("History", controlMainDetailHistory);
    }

    private void initializeChartDataset(){
        chartDatasetManager.setConnProfile(this.connProfile);
        chartDatasetManager.initialize();
    }

    public void setProfile(IProfile iProfile0){
        this.iProfile = iProfile0;
        this.monitorGantt20.setIProfile(iProfile0);
        this.historyPanel.setIProfile(iProfile0);
        this.rawDataTable20.setIProfile(iProfile0);
    }

    private void loadDetailChart(){
        Map<String, JRadioButton> mapRadioButton = new LinkedHashMap<>();

        detailSplitPane = new JSplitPane();
        detailSplitPane.setOrientation(JSplitPane.VERTICAL_SPLIT);
        detailSplitPane.setOneTouchExpandable(true);
        detailSplitPane.setDividerSize(10);
        detailSplitPane.setDividerLocation(300);

        JPanel controlStackedChartInner = new JPanel();
        controlStackedChartInner.setLayout(new BorderLayout());

        AtomicInteger atomicInt = new AtomicInteger(0);
        MigLayout migLayout = new MigLayout("", "[fill, grow]", "[fill, grow]");
        JPanel jPanelStackedCharts = new JPanel(migLayout);

        final JToolBar buttonPanel;
        final ButtonGroup bg = new ButtonGroup();
        buttonPanel = new JToolBar("PanelButton");
        buttonPanel.setFloatable(false);
        buttonPanel.setBorder(new EtchedBorder());

        monitorGantt20 = new MonitorGantt2(jFrame, storeManager, getFromRemoteAndStore, colorManager);
        monitorGantt20.setHistory(false);
        rawDataTable20 = new RawDataTable(jFrame, storeManager);

        detailGanttAndRaw = new JTabbedPane();

        detailGanttAndRaw.add("Top sql & sessions", monitorGantt20);
        detailGanttAndRaw.add("Raw data", rawDataTable20);

        chartDatasetManager.getNameChartDatasetDetail().stream().forEach(e -> {
            String strChartPanel = "cell 0 0, hidemode 3";
            JRadioButton aRadio = new JRadioButton(e.getName());

            aRadio.addItemListener(evt -> {
                AbstractButton sel = (AbstractButton)evt.getItemSelectable();
                if(evt.getStateChange() == ItemEvent.SELECTED){
                    if (sel.getText().equalsIgnoreCase(e.getName())){
                        chartDatasetManager.getNameChartDatasetDetail()
                                .stream()
                                .forEach(l -> {
                                    l.getStackChartPanel().getStackedChart().getChartPanel().setVisible(false);
                                    e.getMonitorGantt2().setVisible(false);
                                });
                        e.getStackChartPanel().getStackedChart().getChartPanel().setVisible(true);

                        monitorGantt20.setWaitClassG(e.getName());
                        rawDataTable20.setWaitClassValue(e.getName());

                        monitorGantt20.clearGui();
                        monitorGantt20.repaint();
                    }
                }
            });

            mapRadioButton.put(e.getName(), aRadio);

            // bug auto color
            //e.getStackChartPanel().initialize();
            // bug auto color

            e.getStackChartPanel().getStackedChart().setChartTitle(e.getName());
            e.getStackChartPanel().getStackedChart().getChartPanel().setVisible(false);
            jPanelStackedCharts.add(e.getStackChartPanel().getStackedChart().getChartPanel(), strChartPanel);

            e.getStackChartPanel().addChartListenerReleaseMouse(monitorGantt20);
            e.getStackChartPanel().addChartListenerReleaseMouse(rawDataTable20);

            atomicInt.getAndIncrement();
        });

        if (atomicInt.get() != 0) {
            mapRadioButton.entrySet().stream().forEach(e -> {
                bg.add(e.getValue());
                buttonPanel.add(e.getValue());
            });
            mapRadioButton.entrySet().stream().findFirst().get().getValue().doClick();

            controlStackedChartInner.add(buttonPanel, BorderLayout.NORTH);
            controlStackedChartInner.add(jPanelStackedCharts, BorderLayout.CENTER);

            detailSplitPane.add(controlStackedChartInner, JSplitPane.TOP);
            detailSplitPane.add(detailGanttAndRaw, JSplitPane.BOTTOM);
        }
    }

    public void loadHistory(){
        controlMainDetailHistory = new JPanel();
        controlMainDetailHistory.setLayout(new BorderLayout());

        MigLayout lm0 = new MigLayout("", "[][]", "[]");
        JPanel mainStartEndDateTimePicker = new JPanel(lm0);

        MigLayout lm1 = new MigLayout("fillx", "[1lp][1lp][1lp][1lp][1lp][1lp][1lp][1lp]");
        JPanel startEndDateTimePicker = new JPanel(lm1);

        historyPanel = new HistoryPanel(jFrame, colorManager, storeManager, getFromRemoteAndStore, chartDatasetManager);

        Map<String, JRadioButton> mapRadioButton = new LinkedHashMap<>();

        final JToolBar buttonPanel;
        final ButtonGroup bg = new ButtonGroup();
        buttonPanel = new JToolBar("PanelButtonHistory");
        buttonPanel.setFloatable(false);
        buttonPanel.setBorder(new EtchedBorder());

        Custom custom = new Custom(buttonPanel);
        custom.initialize();

        JRadioButton aRadioHour8 = new JRadioButton(String.valueOf(ConstantManager.History.Hour8));
        aRadioHour8.addItemListener(evt -> {
            AbstractButton sel = (AbstractButton)evt.getItemSelectable();
            if(evt.getStateChange() == ItemEvent.SELECTED){
                if (sel.getText().equalsIgnoreCase(String.valueOf(ConstantManager.History.Hour8))){
                    ProgressBarUtil.runProgressDialog(()
                            -> historyPanel.initializeGui(getGanttParam(8)), jFrame, "Loading data ..");
                    custom.setEnabled(false);
                }
            }
        });

        JRadioButton aRadioHour12 = new JRadioButton(String.valueOf(ConstantManager.History.Hour12));
        aRadioHour12.addItemListener(evt -> {
            AbstractButton sel = (AbstractButton)evt.getItemSelectable();
            if(evt.getStateChange() == ItemEvent.SELECTED){
                if (sel.getText().equalsIgnoreCase(String.valueOf(ConstantManager.History.Hour12))){
                    ProgressBarUtil.runProgressDialog(()
                            -> historyPanel.initializeGui(getGanttParam(12)), jFrame, "Loading data ..");
                    custom.setEnabled(false);
                }
            }
        });

        JRadioButton aRadioDay1 = new JRadioButton(String.valueOf(ConstantManager.History.Day1));
        aRadioDay1.addItemListener(evt -> {
            AbstractButton sel = (AbstractButton)evt.getItemSelectable();
            if(evt.getStateChange() == ItemEvent.SELECTED){
                if (sel.getText().equalsIgnoreCase(String.valueOf(ConstantManager.History.Day1))){
                    ProgressBarUtil.runProgressDialog(()
                            -> historyPanel.initializeGui(getGanttParam(24)), jFrame, "Loading data ..");
                    custom.setEnabled(false);
                }
            }
        });

        JRadioButton aRadioWeek = new JRadioButton(String.valueOf(ConstantManager.History.Week));
        aRadioWeek.addItemListener(evt -> {
            AbstractButton sel = (AbstractButton)evt.getItemSelectable();
            if(evt.getStateChange() == ItemEvent.SELECTED){
                if (sel.getText().equalsIgnoreCase(String.valueOf(ConstantManager.History.Week))){
                    ProgressBarUtil.runProgressDialog(()
                            -> historyPanel.initializeGui(getGanttParam(168)), jFrame, "Loading data ..");
                    custom.setEnabled(false);
                }
            }
        });

        JRadioButton aRadioMonth = new JRadioButton(String.valueOf(ConstantManager.History.Month));
        aRadioMonth.addItemListener(evt -> {
            AbstractButton sel = (AbstractButton)evt.getItemSelectable();
            if(evt.getStateChange() == ItemEvent.SELECTED){
                if (sel.getText().equalsIgnoreCase(String.valueOf(ConstantManager.History.Month))){
                    ProgressBarUtil.runProgressDialog(()
                            -> historyPanel.initializeGui(getGanttParam(740)), jFrame, "Loading data ..");
                    custom.setEnabled(false);
                }
            }
        });

        JRadioButton aRadioCustom = new JRadioButton(String.valueOf(ConstantManager.History.Custom));
        aRadioCustom.addItemListener(evt -> {
            AbstractButton sel = (AbstractButton)evt.getItemSelectable();
            if(evt.getStateChange() == ItemEvent.SELECTED){
                if (sel.getText().equalsIgnoreCase(String.valueOf(ConstantManager.History.Custom))){
                    custom.setEnabled(true);
                }
            }
        });

        mapRadioButton.put(String.valueOf(ConstantManager.History.Hour8), aRadioHour8);
        mapRadioButton.put(String.valueOf(ConstantManager.History.Hour12), aRadioHour12);
        mapRadioButton.put(String.valueOf(ConstantManager.History.Day1), aRadioDay1);
        mapRadioButton.put(String.valueOf(ConstantManager.History.Week), aRadioWeek);
        mapRadioButton.put(String.valueOf(ConstantManager.History.Month), aRadioMonth);
        mapRadioButton.put(String.valueOf(ConstantManager.History.Custom), aRadioCustom);

        mapRadioButton.entrySet().stream().forEach(e ->{
            bg.add(e.getValue());
            buttonPanel.add(e.getValue());
        });

        custom.fillButtonPanel();

        mapRadioButton.entrySet().stream().findFirst()
                .filter(e -> e.getKey().equalsIgnoreCase(String.valueOf(ConstantManager.History.Hour8)))
                .get().getValue().doClick();

        startEndDateTimePicker.add(new JLabel(), ""); // empty
        startEndDateTimePicker.add(buttonPanel, "gap 1");
        startEndDateTimePicker.add(new JLabel(), ""); // empty

        startEndDateTimePicker.add(new JLabel(Labels.getLabel("gui.history.date.start")), "");
        startEndDateTimePicker.add(custom.getDtpStart(), "gap 1");
        startEndDateTimePicker.add(new JLabel(), ""); // empty
        startEndDateTimePicker.add(new JLabel(Labels.getLabel("gui.history.date.end")), "");
        startEndDateTimePicker.add(custom.getDtpEnd(), "gap 1");
        startEndDateTimePicker.add(new JLabel(), ""); // empty
        startEndDateTimePicker.add(custom.getLoadButton(), "gap 1");

        mainStartEndDateTimePicker.add(startEndDateTimePicker, "span 2, wmin 100");

        controlMainDetailHistory.add(mainStartEndDateTimePicker/*buttonPanel*/, BorderLayout.NORTH);
        controlMainDetailHistory.add(historyPanel, BorderLayout.CENTER);

        controlMainDetailHistory.revalidate();
    }

    private GanttParam getGanttParam(int numberOfHour){
        ParameterBuilder param = new ParameterBuilder.Builder(0L, Long.MAX_VALUE).build();
        long timeStampMillis = storeManager.getDatabaseDAO().getMax(param);

        long currServerOrClientTime = getFromRemoteAndStore.getCurrServerTime() == 0L ?
                timeStampMillis : getFromRemoteAndStore.getCurrServerTime();

        double start = currServerOrClientTime - ConstantManager.CURRENT_WINDOW * numberOfHour;
        double end = currServerOrClientTime;

        return new GanttParam.Builder(start, end).build();
    }

    class Custom {
        private JToolBar buttonPanel;
        @Getter private JButton loadButton;
        @Getter private DateTimePicker dtpStart;
        @Getter private DateTimePicker dtpEnd;

        public Custom(JToolBar buttonPanel) {
            this.buttonPanel = buttonPanel;
            this.loadButton = new JButton(Labels.getLabel("gui.history.date.load.data.button"));
        }

        public void initialize(){
            DatePickerSettings dateSettingsStart = new DatePickerSettings();
            DatePickerSettings dateSettingsEnd = new DatePickerSettings();
            TimePickerSettings timeSettingsStart = new TimePickerSettings();
            TimePickerSettings timeSettingsEnd = new TimePickerSettings();
            dateSettingsStart.setAllowEmptyDates(false);
            timeSettingsStart.setAllowEmptyTimes(false);
            dateSettingsEnd.setAllowEmptyDates(false);
            timeSettingsEnd.setAllowEmptyTimes(false);

            dtpStart = new DateTimePicker(dateSettingsStart, timeSettingsStart);
            dtpEnd = new DateTimePicker(dateSettingsEnd, timeSettingsEnd);

            loadButton = new JButton(Labels.getLabel("gui.history.date.load.data.button"));
            loadButton.addActionListener(e -> loadDataCustom());
        }

        public void fillButtonPanel(){
            this.buttonPanel.add(dtpStart);
            this.buttonPanel.add(dtpEnd);
            this.buttonPanel.add(loadButton);
        }

        public void setEnabled(boolean flag){
            dtpStart.setEnabled(flag);
            dtpEnd.setEnabled(flag);
            loadButton.setEnabled(flag);
        }

        public void loadDataCustom(){
            ProgressBarUtil.runProgressDialog(()
                    -> historyPanel.initializeGui(getParameters()), jFrame, "Loading data ..");
        }

        private GanttParam getParameters(){
            LocalDateTime beginDt = dtpStart.getDateTimePermissive();
            LocalDateTime endDt = dtpEnd.getDateTimePermissive();

            long start = beginDt.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();
            long end = endDt.atZone(ZoneId.systemDefault()).toInstant().toEpochMilli();

            return new GanttParam.Builder(start, end).build();
        }
    }

}
