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.time.Millisecond;
import org.jfree.data.time.TimeSeries;
import org.jfree.data.time.TimeSeriesCollection;
import vassistent.model.RatioPoint;

import javax.swing.*;
import java.awt.*;
import java.text.SimpleDateFormat;
import java.time.ZoneId;
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(0, 12));
        setBorder(BorderFactory.createEmptyBorder(4, 4, 4, 4));
        setOpaque(false);

        JPanel card = new JPanel(new BorderLayout(0, 14));
        card.setBackground(new Color(22, 28, 37));
        card.setOpaque(true);
        card.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createLineBorder(
                        new Color(58, 72, 90)
                ),
                BorderFactory.createEmptyBorder(14, 14, 14, 14)
        ));

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

        JLabel topLabel = new JLabel("Current Risk Level");
        topLabel.setFont(new Font("Segoe UI Semibold", Font.PLAIN, 24));
        topLabel.setForeground(new Color(230, 237, 249));
        topWrapper.add(topLabel, BorderLayout.NORTH);

        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();
        chart.setBackgroundPaint(new Color(22, 28, 37));
        chart.getTitle().setPaint(new Color(222, 231, 245));
        chart.getTitle().setFont(new Font("Segoe UI Semibold", Font.PLAIN, 16));

        long tenMinutes = 10 * 60 * 1000L;

        DateAxis domainAxis = (DateAxis) plot.getDomainAxis();
        domainAxis.setFixedAutoRange(tenMinutes);
        domainAxis.setAutoRange(true);
        domainAxis.setDateFormatOverride(new SimpleDateFormat("HH:mm:ss"));
        domainAxis.setLabelPaint(new Color(170, 185, 208));
        domainAxis.setTickLabelPaint(new Color(170, 185, 208));
        domainAxis.setTickMarkPaint(new Color(89, 105, 128));

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

        renderer.setDefaultShapesVisible(false);
        renderer.setSeriesPaint(0, new Color(67, 175, 255));
        renderer.setSeriesStroke(0,
                new BasicStroke(
                        3.0f,
                        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));
        rangeAxis.setLabelPaint(new Color(170, 185, 208));
        rangeAxis.setTickLabelPaint(new Color(170, 185, 208));
        rangeAxis.setTickMarkPaint(new Color(89, 105, 128));

        plot.setBackgroundPaint(new Color(16, 20, 27));
        plot.setOutlineVisible(false);
        plot.setRangeGridlinePaint(new Color(89, 105, 128, 120));
        plot.setDomainGridlinePaint(new Color(89, 105, 128, 120));

        chart.setAntiAlias(true);
        chart.setTextAntiAlias(true);

        ChartPanel chartPanel = new ChartPanel(chart);
        chartPanel.setOpaque(false);
        chartPanel.setBackground(new Color(16, 20, 27));
        chartPanel.setBorder(BorderFactory.createCompoundBorder(
                BorderFactory.createLineBorder(new Color(58, 72, 90)),
                BorderFactory.createEmptyBorder(8, 8, 8, 8)
        ));

        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(getThresholdColor(label));

        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 Semibold", Font.PLAIN, 12));
        marker.setLabelPaint(new Color(188, 203, 223));

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

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

    /**
     * Returns a distinct marker color for each threshold level.
     *
     * @param label threshold label
     * @return translucent marker color
     */
    private Color getThresholdColor(String label) {
        switch (label) {
            case "Warning":
                return new Color(255, 210, 69, 165);
            case "High":
                return new Color(255, 153, 65, 170);
            case "Disaster":
                return new Color(255, 92, 92, 175);
            default:
                return new Color(168, 178, 194, 140);
        }
    }
}
