package de.nilzbu.mytimetracker.ui.view;

import com.vaadin.flow.component.Component;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.html.Div;
import com.vaadin.flow.component.html.H2;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.tabs.Tab;
import com.vaadin.flow.component.tabs.Tabs;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import de.nilzbu.mytimetracker.model.TimeEntry;
import de.nilzbu.mytimetracker.model.User;
import de.nilzbu.mytimetracker.repository.UserRepository;
import de.nilzbu.mytimetracker.service.TimeEntryService;
import de.nilzbu.mytimetracker.ui.component.ChartJsComponent;
import de.nilzbu.mytimetracker.ui.layout.MainLayout;
import jakarta.annotation.security.PermitAll;
import org.springframework.security.core.context.SecurityContextHolder;

import java.time.LocalDate;
import java.util.*;
import java.util.stream.Collectors;
import java.util.stream.IntStream;

@PermitAll
@PageTitle("Startseite")
@Route(value = "", layout = MainLayout.class)
public class MainView extends VerticalLayout {

    private final TimeEntryService timeEntryService;
    private final UserRepository userRepository;

    private User currentUser;
    private final ComboBox<Integer> jahrAuswahl = new ComboBox<>("Jahr");
    private final ComboBox<Integer> monatAuswahl = new ComboBox<>("Monat");
    private final ComboBox<Integer> quartalAuswahl = new ComboBox<>("Quartal");

    private final Div filterContainer = new Div();
    private final Div content = new Div();

    public MainView(TimeEntryService timeEntryService, UserRepository userRepository) {
        this.timeEntryService = timeEntryService;
        this.userRepository = userRepository;

        setSizeFull();
        setPadding(false);
        setSpacing(false);
        setMargin(false);

        initializeCurrentUser();
        configureFilter();

        Tabs tabs = new Tabs(new Tab("Gesamt"), new Tab("Jahr"), new Tab("Quartal"), new Tab("Monat"));
        tabs.addSelectedChangeListener(e -> updateContent(tabs.getSelectedTab().getLabel()));

        add(new H2("Dashboard"), tabs, filterContainer, content);

        content.setSizeFull();
        content.getStyle().set("overflow", "auto");
        setFlexGrow(1, content);

        updateContent("Gesamt");
    }

    private void initializeCurrentUser() {
        String username = SecurityContextHolder.getContext().getAuthentication().getName();
        this.currentUser = userRepository.findByUsername(username)
                .orElseThrow(() -> new RuntimeException("Benutzer nicht gefunden"));
    }

    private void configureFilter() {
        jahrAuswahl.setItems(IntStream.rangeClosed(2020, LocalDate.now().getYear()).boxed().toList());
        jahrAuswahl.setValue(LocalDate.now().getYear());

        monatAuswahl.setItems(IntStream.rangeClosed(1, 12).boxed().toList());
        monatAuswahl.setValue(LocalDate.now().getMonthValue());

        quartalAuswahl.setItems(1, 2, 3, 4);
        quartalAuswahl.setValue((LocalDate.now().getMonthValue() - 1) / 3 + 1);
    }

    private void updateContent(String scope) {
        content.removeAll();
        filterContainer.removeAll();

        jahrAuswahl.setVisible(false);
        monatAuswahl.setVisible(false);
        quartalAuswahl.setVisible(false);

        List<TimeEntry> entries;

        switch (scope) {
            case "Monat" -> {
                filterContainer.add(jahrAuswahl, monatAuswahl);
                jahrAuswahl.setVisible(true);
                monatAuswahl.setVisible(true);

                jahrAuswahl.addValueChangeListener(e -> updateContent("Monat"));
                monatAuswahl.addValueChangeListener(e -> updateContent("Monat"));

                entries = timeEntryService.getEntriesForMonth(currentUser, jahrAuswahl.getValue(), monatAuswahl.getValue());
            }
            case "Quartal" -> {
                filterContainer.add(jahrAuswahl, quartalAuswahl);
                jahrAuswahl.setVisible(true);
                quartalAuswahl.setVisible(true);

                jahrAuswahl.addValueChangeListener(e -> updateContent("Quartal"));
                quartalAuswahl.addValueChangeListener(e -> updateContent("Quartal"));

                entries = timeEntryService.getEntriesForQuarter(currentUser, jahrAuswahl.getValue(), quartalAuswahl.getValue());
            }
            case "Jahr" -> {
                filterContainer.add(jahrAuswahl);
                jahrAuswahl.setVisible(true);

                jahrAuswahl.addValueChangeListener(e -> updateContent("Jahr"));

                entries = timeEntryService.getEntriesForYear(currentUser, jahrAuswahl.getValue());
            }
            default -> {
                entries = timeEntryService.getEntriesForUser(currentUser);
            }
        }

        renderCharts(entries);
    }

    private void renderCharts(List<TimeEntry> scopedEntries) {
        List<TimeEntry> allEntries = timeEntryService.getEntriesForUser(currentUser);

        VerticalLayout layout = new VerticalLayout();
        layout.setSizeFull();
        layout.setPadding(false);
        layout.setSpacing(true);

        Component first = createCategoryBarChart(scopedEntries);
        Component second = createOvertimeLineChart(allEntries, scopedEntries);

        first.getStyle().set("minHeight", "45vh");
        second.getStyle().set("minHeight", "50vh");

        layout.add(first, second);
        layout.setFlexGrow(1, first);
        layout.setFlexGrow(1, second);

        content.add(layout);
    }

    private Component createCategoryBarChart(List<TimeEntry> entries) {
        Map<String, Long> categoryCounts = entries.stream()
                .collect(Collectors.groupingBy(e -> e.getStatus().name(), Collectors.counting()));

        return new ChartJsComponent(
                ChartJsComponent.generateBarChartData(categoryCounts),
                "Einträge nach Kategorie");
    }

    private Component createOvertimeLineChart(List<TimeEntry> allEntries, List<TimeEntry> scopeEntries) {
        Map<LocalDate, Double> saldoPerDay = new TreeMap<>();
        int accumulatedMinutes = 0;

        List<TimeEntry> sorted = allEntries.stream()
                .sorted(Comparator.comparing(TimeEntry::getDate))
                .toList();

        for (TimeEntry entry : sorted) {
            accumulatedMinutes += timeEntryService.calculateNetWorkMinutes(entry) - entry.getTargetMinutes();
            saldoPerDay.put(entry.getDate(), accumulatedMinutes / 60.0); // Umwandlung in Stunden
        }

        List<LocalDate> datesInScope = scopeEntries.stream()
                .map(TimeEntry::getDate)
                .sorted()
                .distinct()
                .toList();

        List<Double> values = datesInScope.stream()
                .map(date -> saldoPerDay.getOrDefault(date, 0.0))
                .toList();

        return new ChartJsComponent(
                ChartJsComponent.generateLineChartData(datesInScope, values),
                "Überstunden-Saldo im Verlauf (in Stunden)");
    }
}