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;
import java.util.List;

@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 User currentUser;

    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 breakField = new NumberField("Break (min)");
    private final NumberField targetField = new NumberField("Target Time (min)");
    private final TextArea commentArea = new TextArea("Comment");
    private final ComboBox<DayStatus> statusCombo = new ComboBox<>("Status");

    private final Button saveBtn = new Button("Save");
    private final Button updateBtn = new Button("Update");
    private final Button deleteBtn = new Button("Delete");

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

    private final DatePicker fromDate = new DatePicker("From");
    private final DatePicker toDate = new DatePicker("To");
    private final Button applyFilterBtn = new Button("Apply Filter");

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

        setSizeFull();

        initializeUser();
        configureFormFields();
        configureButtons();
        configureGrid();

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

        add(buildFormLayout(), buildButtonLayout(), buildDateRangeFilterLayout(), entryGrid);
        refreshGrid();
        toggleSaveButton();
    }

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

    private void configureFormFields() {
        datePicker.setValue(LocalDate.now());
        breakField.setValue(30.0);
        targetField.setValue(480.0);
        statusCombo.setItems(DayStatus.values());
        statusCombo.setValue(DayStatus.REMOTE);
    }

    private HorizontalLayout buildFormLayout() {
        return new HorizontalLayout(datePicker, startTimePicker, endTimePicker,
                breakField, targetField, commentArea, statusCombo);
    }

    private HorizontalLayout buildButtonLayout() {
        updateBtn.setEnabled(false);
        deleteBtn.setEnabled(false);
        return new HorizontalLayout(saveBtn, updateBtn, deleteBtn);
    }

    private HorizontalLayout buildDateRangeFilterLayout() {
        applyFilterBtn.addClickListener(e -> refreshGrid());

        HorizontalLayout filterLayout = new HorizontalLayout(fromDate, toDate, applyFilterBtn);
        filterLayout.setAlignItems(Alignment.END);
        return filterLayout;
    }

    private void configureButtons() {
        saveBtn.addClickListener(e -> saveEntry());
        updateBtn.addClickListener(e -> updateEntry());
        deleteBtn.addClickListener(e -> deleteEntry());
    }

    private void saveEntry() {
        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(breakField.getValue().intValue())
                .targetMinutes(targetField.getValue().intValue())
                .status(statusCombo.getValue())
                .comment(commentArea.getValue())
                .build();

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

    private void updateEntry() {
        if (selectedEntry == null) return;

        selectedEntry.setDate(datePicker.getValue());
        selectedEntry.setStartTime(startTimePicker.getValue());
        selectedEntry.setEndTime(endTimePicker.getValue());
        selectedEntry.setPauseMinutes(breakField.getValue().intValue());
        selectedEntry.setTargetMinutes(targetField.getValue().intValue());
        selectedEntry.setStatus(statusCombo.getValue());
        selectedEntry.setComment(commentArea.getValue());

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

    private void deleteEntry() {
        if (selectedEntry == null) return;

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

    private void configureGrid() {
        entryGrid.setSizeFull();

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

        entryGrid.getColumns().forEach(col -> col.setAutoWidth(true));

        entryGrid.asSingleSelect().addValueChangeListener(event -> populateForm(event.getValue()));
    }

    private void refreshGrid() {
        List<TimeEntry> entries = timeEntryService.getEntriesForUser(currentUser);

        if (fromDate.getValue() != null) {
            entries = entries.stream()
                    .filter(entry -> !entry.getDate().isBefore(fromDate.getValue()))
                    .toList();
        }

        if (toDate.getValue() != null) {
            entries = entries.stream()
                    .filter(entry -> !entry.getDate().isAfter(toDate.getValue()))
                    .toList();
        }

        entryGrid.setItems(entries);
    }

    private void populateForm(TimeEntry entry) {
        selectedEntry = entry;

        if (entry != null) {
            datePicker.setValue(entry.getDate());
            startTimePicker.setValue(entry.getStartTime());
            endTimePicker.setValue(entry.getEndTime());
            breakField.setValue((double) entry.getPauseMinutes());
            targetField.setValue((double) entry.getTargetMinutes());
            statusCombo.setValue(entry.getStatus());
            commentArea.setValue(entry.getComment() != null ? entry.getComment() : "");

            updateBtn.setEnabled(true);
            deleteBtn.setEnabled(true);
            saveBtn.setEnabled(false);
        } else {
            clearForm();
        }
    }

    private void clearForm() {
        selectedEntry = null;
        datePicker.setValue(LocalDate.now());
        startTimePicker.clear();
        endTimePicker.clear();
        breakField.setValue(30.0);
        targetField.setValue(480.0);
        statusCombo.setValue(DayStatus.REMOTE);
        commentArea.clear();
        updateBtn.setEnabled(false);
        deleteBtn.setEnabled(false);
        toggleSaveButton();
    }

    private void toggleSaveButton() {
        saveBtn.setEnabled(isDateAvailable(datePicker.getValue()));
    }

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