package de.nilzbu.mytimetracker.ui.view;

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.grid.Grid;
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.component.textfield.NumberField;
import com.vaadin.flow.component.textfield.TextArea;
import com.vaadin.flow.component.timepicker.TimePicker;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import de.nilzbu.mytimetracker.model.DayStatus;
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.layout.MainLayout;
import jakarta.annotation.security.PermitAll;
import org.springframework.security.core.context.SecurityContextHolder;

import java.time.LocalDate;

@Route(value = "time-entry", layout = MainLayout.class)
@PageTitle("Time Entry")
@PermitAll
public class TimeEntryView extends VerticalLayout {

    private final TimeEntryService timeEntryService;
    private final UserRepository userRepository;

    private final DatePicker datePicker = new DatePicker("Date");
    private final TimePicker startTimePicker = new TimePicker("Start Time");
    private final TimePicker endTimePicker = new TimePicker("End Time");
    private final NumberField breakMinutesField = new NumberField("Break (minutes)");
    private final NumberField targetMinutesField = new NumberField("Target Time (minutes)");
    private final TextArea commentField = new TextArea("Comment");
    private final ComboBox<DayStatus> statusComboBox = new ComboBox<>("Status");

    private final Button saveButton = new Button("Save");
    private final Button updateButton = new Button("Update");
    private final Button deleteButton = new Button("Delete");

    private final Grid<TimeEntry> entryGrid = new Grid<>(TimeEntry.class, false);

    private TimeEntry selectedEntry = null;
    private User currentUser;

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

        initializeCurrentUser();
        configureFields();
        configureButtons();
        configureGrid();

        datePicker.addValueChangeListener(e -> checkIfDateAlreadyExists());

        add(createFormLayout(), createButtonLayout(), entryGrid);
        refreshGrid();
        checkIfDateAlreadyExists(); // Initiale Prüfung
    }

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

    private void configureFields() {
        datePicker.setValue(LocalDate.now());
        breakMinutesField.setValue(30.0);
        targetMinutesField.setValue(480.0);

        statusComboBox.setItems(DayStatus.values());
        statusComboBox.setValue(DayStatus.REMOTE);
    }

    private HorizontalLayout createFormLayout() {
        return new HorizontalLayout(
                datePicker,
                startTimePicker,
                endTimePicker,
                breakMinutesField,
                targetMinutesField,
                commentField,
                statusComboBox
        );
    }

    private HorizontalLayout createButtonLayout() {
        updateButton.setEnabled(false);
        deleteButton.setEnabled(false);
        return new HorizontalLayout(saveButton, updateButton, deleteButton);
    }

    private void configureButtons() {
        saveButton.addClickListener(e -> {
            if (!isDateAvailable(datePicker.getValue())) {
                Notification.show("An entry already exists for this date.");
                return;
            }

            TimeEntry entry = TimeEntry.builder()
                    .user(currentUser)
                    .date(datePicker.getValue())
                    .startTime(startTimePicker.getValue())
                    .endTime(endTimePicker.getValue())
                    .pauseMinutes(breakMinutesField.getValue().intValue())
                    .targetMinutes(targetMinutesField.getValue().intValue())
                    .status(statusComboBox.getValue())
                    .comment(commentField.getValue())
                    .build();

            timeEntryService.save(entry);
            clearForm();
            refreshGrid();
            Notification.show("Entry saved");
        });

        updateButton.addClickListener(e -> {
            if (selectedEntry == null) return;

            selectedEntry.setDate(datePicker.getValue());
            selectedEntry.setStartTime(startTimePicker.getValue());
            selectedEntry.setEndTime(endTimePicker.getValue());
            selectedEntry.setPauseMinutes(breakMinutesField.getValue().intValue());
            selectedEntry.setTargetMinutes(targetMinutesField.getValue().intValue());
            selectedEntry.setStatus(statusComboBox.getValue());
            selectedEntry.setComment(commentField.getValue());

            timeEntryService.save(selectedEntry);
            clearForm();
            refreshGrid();
            Notification.show("Entry updated");
        });

        deleteButton.addClickListener(e -> {
            if (selectedEntry == null) return;

            timeEntryService.delete(selectedEntry);
            clearForm();
            refreshGrid();
            Notification.show("Entry deleted");
        });
    }

    private void configureGrid() {
        entryGrid.addColumn(TimeEntry::getDate).setHeader("Date");
        entryGrid.addColumn(TimeEntry::getStartTime).setHeader("Start");
        entryGrid.addColumn(TimeEntry::getEndTime).setHeader("End");
        entryGrid.addColumn(TimeEntry::getPauseMinutes).setHeader("Break (min)");
        entryGrid.addColumn(TimeEntry::getTargetMinutes).setHeader("Target (min)");
        entryGrid.addColumn(timeEntryService::calculateNetWorkMinutes).setHeader("Actual (min)");
        entryGrid.addColumn(TimeEntry::getStatus).setHeader("Status");
        entryGrid.addColumn(TimeEntry::getComment).setHeader("Comment");
        entryGrid.addColumn(timeEntryService::calculateDeviation).setHeader("Deviation (min)");

        entryGrid.asSingleSelect().addValueChangeListener(event -> {
            selectedEntry = event.getValue();
            if (selectedEntry != null) {
                datePicker.setValue(selectedEntry.getDate());
                startTimePicker.setValue(selectedEntry.getStartTime());
                endTimePicker.setValue(selectedEntry.getEndTime());
                breakMinutesField.setValue((double) selectedEntry.getPauseMinutes());
                targetMinutesField.setValue((double) selectedEntry.getTargetMinutes());
                statusComboBox.setValue(selectedEntry.getStatus());
                commentField.setValue(selectedEntry.getComment() != null ? selectedEntry.getComment() : "");

                updateButton.setEnabled(true);
                deleteButton.setEnabled(true);
                saveButton.setEnabled(false);
            } else {
                updateButton.setEnabled(false);
                deleteButton.setEnabled(false);
                checkIfDateAlreadyExists();
            }
        });
    }

    private void refreshGrid() {
        entryGrid.setItems(timeEntryService.getEntriesForUser(currentUser));
    }

    private void clearForm() {
        selectedEntry = null;
        datePicker.setValue(LocalDate.now());
        startTimePicker.clear();
        endTimePicker.clear();
        breakMinutesField.setValue(30.0);
        targetMinutesField.setValue(480.0);
        statusComboBox.setValue(DayStatus.REMOTE);
        commentField.clear();
        updateButton.setEnabled(false);
        deleteButton.setEnabled(false);
        checkIfDateAlreadyExists();
    }

    private void checkIfDateAlreadyExists() {
        LocalDate date = datePicker.getValue();
        if (!isDateAvailable(date)) {
            saveButton.setEnabled(false);
        } else {
            saveButton.setEnabled(true);
        }
    }

    private boolean isDateAvailable(LocalDate date) {
        return timeEntryService.getEntriesForUser(currentUser).stream()
                .noneMatch(entry -> entry.getDate().equals(date));
    }
}