package vassistent.ui;

import org.jfree.chart.ChartFactory;
import org.jfree.chart.ChartPanel;
import org.jfree.chart.JFreeChart;
import org.jfree.chart.axis.DateAxis;
import org.jfree.chart.axis.NumberAxis;
import org.jfree.chart.axis.NumberTickUnit;
import org.jfree.chart.plot.ValueMarker;
import org.jfree.chart.plot.XYPlot;
import org.jfree.chart.renderer.xy.XYLineAndShapeRenderer;
import org.jfree.chart.ui.Layer;
import org.jfree.chart.ui.RectangleAnchor;
import org.jfree.chart.ui.TextAnchor;
import org.jfree.data.category.DefaultCategoryDataset;
import org.jfree.data.time.Millisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import vassistent.model.ProblemLevel;
import vassistent.model.RatioPoint;

import javax.swing.*;
import java.awt.*;
import java.sql.Timestamp;
import java.time.ZoneId;
import java.util.Arrays;
import java.util.Date;
import java.util.List;

/**
 * Dashboard panel that renders the ratio history chart and current level indicator.
 */
public class DashboardView extends JPanel {

    private TimeSeries series;
    private ProblemLevelBar levelBar;

    private JButton reloadPixelStreamingViewButton;
    private JButton openFullscreenButton;

    /**
     * Creates the dashboard panel with problem-level bar and time-series chart.
     */
    public DashboardView() {
        setLayout(new BorderLayout());
        setBorder(BorderFactory.createEmptyBorder(10,10,10,10));
        setOpaque(false);

        JPanel card = new JPanel(new BorderLayout(10,10));
        card.setBorder(BorderFactory.createEmptyBorder(10,10,10,10));

        card.setBackground(UIManager.getColor("Panel.background"));
        card.setOpaque(true);

        card.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createLineBorder(
                        UIManager.getColor("Component.borderColor")
                ),
                BorderFactory.createEmptyBorder(12,12,12,12)
        ));

        // ---------- TOP: Problem Level ----------
        JPanel topWrapper = new JPanel(new BorderLayout());
        topWrapper.setBorder(BorderFactory.createEmptyBorder(0,0,10,0));
        topWrapper.setOpaque(false);

        levelBar = new ProblemLevelBar();
        topWrapper.add(levelBar, BorderLayout.CENTER);

        card.add(topWrapper, BorderLayout.NORTH);

        // ---------- CENTER: Chart ----------

        series = new TimeSeries("Ratio");

        TimeSeriesCollection dataset = new TimeSeriesCollection(series);

        JFreeChart chart = ChartFactory.createTimeSeriesChart(
                "Ratio Verlauf",
                "Zeit",
                "Durchschnitt",
                dataset
        );

        XYPlot plot = chart.getXYPlot();

        long tenMinutes = 10 * 60 * 1000L;

        DateAxis domainAxis = (DateAxis) plot.getDomainAxis();

        domainAxis.setFixedAutoRange(tenMinutes);
        domainAxis.setAutoRange(true);

        XYLineAndShapeRenderer renderer =
                (XYLineAndShapeRenderer) plot.getRenderer();

        renderer.setDefaultShapesVisible(false);
        renderer.setSeriesStroke(0,
                new BasicStroke(
                        2.5f,
                        BasicStroke.CAP_ROUND,
                        BasicStroke.JOIN_ROUND
                ));

        // Threshold Lines
        addThresholdLine(plot, 0.5, "Warning");
        addThresholdLine(plot, 0.8, "High");
        addThresholdLine(plot, 0.9, "Disaster");

        chart.getXYPlot().getRangeAxis().setRange(0.0, 1.02);
        NumberAxis rangeAxis = (NumberAxis) chart.getXYPlot().getRangeAxis();
        rangeAxis.setTickUnit(new NumberTickUnit(0.1));

        chart.setAntiAlias(true);
        chart.setTextAntiAlias(true);
        chart.getPlot().setBackgroundPaint(new Color(245,245,245));
        chart.getPlot().setOutlineVisible(false);

        ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setBorder(BorderFactory.createEmptyBorder(5,5,5,5));

        card.add(chartPanel, BorderLayout.CENTER);

        add(card, BorderLayout.CENTER);
    }

    /**
     * Replaces chart data with the given ratio points.
     *
     * @param points ratio points ordered by time
     */
    public void updateChart(List<RatioPoint> points) {
        if (points == null || points.isEmpty())
            return;

        series.clear();

        for (RatioPoint point : points) {

            series.addOrUpdate(
                    new Millisecond(
                            Date.from(
                                    point.getTimestamp()
                                            .atZone(ZoneId.systemDefault())
                                            .toInstant()
                            )
                    ),
                    point.getRatio()
            );
        }
    }

    /**
     * Updates the visual problem level bar using the latest ratio.
     *
     * @param ratio latest computed ratio
     */
    public void updateProblemLevel(double ratio) {
        levelBar.setRatio(ratio);
    }

    /**
     * Returns the button intended to reload the pixel streaming view.
     *
     * @return reload button (may be {@code null} until implemented)
     */
    public JButton getReloadPixelStreamingViewButton() {
        return reloadPixelStreamingViewButton;
    }

    /**
     * Returns the button intended to open fullscreen mode.
     *
     * @return fullscreen button (may be {@code null} until implemented)
     */
    public JButton getOpenFullscreenButton() {
        return openFullscreenButton;
    }

    /**
     * Adds a horizontal threshold marker with label to the chart.
     *
     * @param plot target plot
     * @param value y-axis value for the threshold
     * @param label label rendered near the marker
     */
    private void addThresholdLine(XYPlot plot, double value, String label) {

        ValueMarker marker = new ValueMarker(value);

        marker.setPaint(new Color(150,150,150,150));

        float[] dash = {6.0f, 6.0f};
        marker.setStroke(new BasicStroke(
                1f,
                BasicStroke.CAP_BUTT,
                BasicStroke.JOIN_MITER,
                10.0f,
                dash,
                0.0f
        ));

        marker.setLabel(label);
        marker.setLabelFont(new Font("Segoe UI", Font.PLAIN, 11));
        marker.setLabelPaint(new Color(160,160,160));

        marker.setLabelAnchor(RectangleAnchor.RIGHT);
        marker.setLabelTextAnchor(TextAnchor.TOP_RIGHT);

        plot.addRangeMarker(marker, Layer.BACKGROUND);
    }
}
