package com.example.views;

import com.example.components.ApexChart;
import com.example.components.BarChart;
import com.example.components.Card;
import com.example.components.Fa;
import com.example.components.GridStackItem;
import com.example.components.GridStackLayout;
import com.example.components.LineChart;
import com.example.components.PieChart;
import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.html.Paragraph;
import com.vaadin.flow.component.html.Span;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.HasDynamicTitle;
import com.vaadin.flow.router.Route;

import java.util.List;

/**
 * The dashboard: a {@link GridStackLayout} of draggable/resizable cards whose
 * layout is persisted per browser, plus controls to add widgets and reset the
 * layout at runtime. Widgets are removed by their own close button (see
 * {@link GridStackItem#setClosable(boolean)}), not from the toolbar.
 */
@Route("")
public class DashboardView extends VerticalLayout implements HasDynamicTitle {

    private static final String STORAGE_KEY = "dashboard";

    private final GridStackLayout grid = new GridStackLayout();
    private final Span status = new Span();
    private int extraWidgetCount;

    public DashboardView() {
        addClassName("dialect-content");

        grid.setWidthFull();
        grid.setStorageKey(STORAGE_KEY);
        grid.addLayoutChangeListener(e -> status.setText(
                getTranslation("gridstack.status", e.getPositions().size())));

        grid.add(
                new GridStackItem("revenue-trend", 0, 0, 6, 3,
                        new Card(getTranslation("card.revenueTrend"), lineChart())),
                new GridStackItem("revenue-month", 6, 0, 6, 3,
                        new Card(getTranslation("card.revenueByMonth"), barChart())),
                new GridStackItem("revenue-region", 0, 3, 5, 3,
                        new Card(getTranslation("card.revenueByRegion"), pieChart())),
                new GridStackItem("hint", 5, 3, 7, 3,
                        new Card(getTranslation("card.gridstackHint"),
                                new Paragraph(getTranslation("gridstack.hint")))));

        status.setText(getTranslation("gridstack.statusInitial"));
        status.addClassName("dialect-muted");

        add(toolbar(), grid);
    }

    private HorizontalLayout toolbar() {
        Button add = new Button(getTranslation("gridstack.addWidget"), Fa.ADD.create(),
                e -> addWidget());
        add.addThemeVariants(ButtonVariant.LUMO_PRIMARY);

        Button reset = new Button(getTranslation("gridstack.reset"), Fa.RESET.create(),
                e -> grid.resetLayout());

        HorizontalLayout toolbar = new HorizontalLayout(add, reset, status);
        toolbar.setPadding(false);
        toolbar.setWidthFull();
        toolbar.setAlignItems(Alignment.CENTER);
        return toolbar;
    }

    private void addWidget() {
        // The id must stay stable across reloads for the saved layout to match
        // it again, so it is derived from a counter rather than a random UUID.
        // The counter only ever grows: closing a widget must not hand its id to
        // the next one, or the new widget would inherit the closed one's saved
        // position.
        extraWidgetCount++;
        String title = getTranslation("gridstack.widget", extraWidgetCount);
        grid.add(new GridStackItem("extra-" + extraWidgetCount, 0, 0, 4, 2,
                new Card(title, new Paragraph(getTranslation("gridstack.widgetText")))));
    }

    private Component lineChart() {
        LineChart chart = new LineChart();
        chart.setData(getTranslation("chart.revenueSeries"),
                List.of(30.0, 40.0, 35.0, 50.0, 49.0, 60.0), months());
        chart.addPointClickListener(e -> Notification.show(getTranslation(
                "chart.pointClick", e.getSeriesIndex(), e.getDataPointIndex())));
        return sizeFull(chart);
    }

    private Component barChart() {
        BarChart chart = new BarChart();
        chart.setData(getTranslation("chart.revenueSeries"),
                List.of(30.0, 40.0, 35.0, 50.0, 49.0, 60.0), months());
        chart.addPointClickListener(e -> Notification.show(getTranslation(
                "chart.pointClick", e.getSeriesIndex(), e.getDataPointIndex())));
        return sizeFull(chart);
    }

    private Component pieChart() {
        PieChart chart = new PieChart();
        chart.setData(List.of(30.0, 40.0, 35.0, 50.0),
                List.of(getTranslation("region.north"), getTranslation("region.south"),
                        getTranslation("region.east"), getTranslation("region.west")));
        chart.addPointClickListener(e -> Notification.show(
                getTranslation("chart.sliceClick", e.getDataPointIndex())));
        return sizeFull(chart);
    }

    /** Charts fill their grid item instead of using a fixed pixel height, so
     *  resizing a widget resizes the chart (grid-stack.ts fires a window
     *  resize on resizestop, which ApexCharts reflows on). */
    private Component sizeFull(ApexChart chart) {
        chart.setWidthFull();
        chart.setHeight("100%");
        return chart;
    }

    private List<String> months() {
        return List.of(
                getTranslation("month.jan"), getTranslation("month.feb"),
                getTranslation("month.mar"), getTranslation("month.apr"),
                getTranslation("month.may"), getTranslation("month.jun"));
    }

    @Override
    public String getPageTitle() {
        return getTranslation("page.dashboard");
    }
}
