package de.nilzbu.mytimetracker.ui.component;

import com.vaadin.flow.component.AttachEvent;
import com.vaadin.flow.component.Tag;
import com.vaadin.flow.component.dependency.JsModule;
import com.vaadin.flow.component.dependency.NpmPackage;
import com.vaadin.flow.component.html.Div;
import elemental.json.Json;
import elemental.json.JsonArray;
import elemental.json.JsonObject;

import java.time.LocalDate;
import java.util.List;
import java.util.Map;

@Tag("div")
@JsModule("https://cdn.jsdelivr.net/npm/chart.js")
@NpmPackage(value = "chart.js", version = "4.4.0")
public class ChartJsComponent extends Div {

    private final JsonObject chartData;
    private final String chartTitle;

    public ChartJsComponent(JsonObject chartData, String chartTitle) {
        this.chartData = chartData;
        this.chartTitle = chartTitle;
        setWidthFull();
        setHeight("500px");
    }

    @Override
    protected void onAttach(AttachEvent attachEvent) {
        renderChart();
    }

    private void renderChart() {
        getElement().executeJs(
                """
                const canvas = document.createElement('canvas');
                appendChild(canvas);
                const ctx = canvas.getContext('2d');
                new Chart(ctx, {
                  type: $0,
                  data: $1,
                  options: {
                    responsive: true,
                    maintainAspectRatio: false,
                    plugins: {
                      legend: {
                        position: 'top'
                      },
                      title: {
                        display: true,
                        text: $2
                      }
                    }
                  }
                });
                """,
                detectChartType(chartData),
                chartData,
                chartTitle
        );
    }

    /**
     * Detects chart type based on chart data.
     * If no definitive type can be determined, defaults to "bar".
     */
    private String detectChartType(JsonObject data) {
        try {
            JsonArray datasets = data.getArray("datasets");
            if (datasets.length() > 0) {
                JsonObject firstDataset = datasets.getObject(0);
                if (firstDataset.hasKey("fill") && !firstDataset.getBoolean("fill")) {
                    return "line";
                }
            }
        } catch (Exception ignored) {
        }
        return "bar";
    }

    /**
     * Creates JSON chart data for a bar chart based on category counts.
     */
    public static JsonObject generateBarChartData(Map<String, Long> categoryCounts) {
        JsonObject data = Json.createObject();
        JsonArray labels = Json.createArray();
        JsonArray values = Json.createArray();
        JsonArray colors = Json.createArray();

        String[] defaultColors = {
                "#1e7e34", "#138496", "#ffc107", "#dc3545", "#6f42c1", "#20c997"
        };

        int index = 0;
        for (Map.Entry<String, Long> entry : categoryCounts.entrySet()) {
            labels.set(index, Json.create(entry.getKey()));
            values.set(index, Json.create(entry.getValue()));
            colors.set(index, Json.create(defaultColors[index % defaultColors.length]));
            index++;
        }

        JsonObject dataset = Json.createObject();
        dataset.put("label", "Entries by Category");
        dataset.put("data", values);
        dataset.put("backgroundColor", colors);

        JsonArray datasets = Json.createArray();
        datasets.set(0, dataset);

        data.put("labels", labels);
        data.put("datasets", datasets);

        return data;
    }

    /**
     * Creates JSON chart data for a line chart showing overtime balance.
     */
    public static JsonObject generateLineChartData(List<LocalDate> dates, List<Double> balanceValues) {
        JsonObject data = Json.createObject();
        JsonArray labels = Json.createArray();
        JsonArray values = Json.createArray();

        for (int i = 0; i < dates.size(); i++) {
            labels.set(i, Json.create(dates.get(i).toString()));
            values.set(i, Json.create(balanceValues.get(i)));
        }

        JsonObject dataset = Json.createObject();
        dataset.put("label", "Overtime Balance (hours)");
        dataset.put("data", values);
        dataset.put("borderColor", "rgb(54, 162, 235)");
        dataset.put("tension", 0.1);
        dataset.put("fill", false);

        JsonArray datasets = Json.createArray();
        datasets.set(0, dataset);

        data.put("labels", labels);
        data.put("datasets", datasets);

        return data;
    }
}