package ru.vyatsu.qr_access_admin.door.view;

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.icon.VaadinIcon;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import jakarta.annotation.security.PermitAll;
import jakarta.persistence.EntityManager;
import jakarta.persistence.EntityManagerFactory;
import jakarta.persistence.Query;
import ru.vyatsu.qr_access_admin.common.MainLayout;
import ru.vyatsu.qr_access_admin.door.component.DoorEditor;
import ru.vyatsu.qr_access_admin.door.entity.DoorEntity;
import ru.vyatsu.qr_access_admin.door.entity.DoorRepository;
import ru.vyatsu.qr_access_admin.door.schedule.entity.ScheduleEntity;
import ru.vyatsu.qr_access_admin.door.schedule.entity.ScheduleRepository;
import ru.vyatsu.qr_access_admin.unit.entity.UnitRepository;

import java.util.*;
import java.util.stream.Collectors;

import static org.apache.commons.lang3.StringUtils.isBlank;

@Route(value = "doors", layout = MainLayout.class)
@PageTitle("Двери")
@PermitAll
public class DoorView extends VerticalLayout {
    private final Grid<DoorEntity> grid;
    private final DoorRepository repository;
    private final ScheduleRepository scheduleRepository;
    private final DoorEditor editor;
    private final EntityManagerFactory emf;

    public DoorView(DoorRepository repository, UnitRepository unitRepository, ScheduleRepository scheduleRepository, EntityManagerFactory emf) {
        this.repository = repository;
        this.scheduleRepository = scheduleRepository;
        this.emf = emf;

        var addButton = new Button("Добавить дверь", VaadinIcon.PLUS.create());

        grid = new Grid<>(DoorEntity.class);
        grid.setColumns("description", "unitId", "count");
        editor = new DoorEditor(unitRepository, scheduleRepository, repository);

        var actionsLayout = new HorizontalLayout(addButton);
        add(actionsLayout, grid, editor);

        this.configureEditor();

        addButton.addClickListener(e -> editDoor(new DoorEntity()));

        grid.setHeight("200px");

        grid.asSingleSelect().addValueChangeListener(e -> editDoor(e.getValue()));

        refreshDoorsGrid();
    }

    private void refreshDoorsGrid() {
        List<DoorEntity> entities = repository.findAllByParentDoorIdsIsNull();

        grid.setItems(entities);
    }

    private void editDoor(DoorEntity door) {
        if (door == null) {
            editor.setVisible(false);
        } else {
            editor.setVisible(true);
            editor.setCurrentDoor(door);
        }
    }

    private void configureEditor() {
        editor.setVisible(false);

        editor.setSaveListener(doorEditInfo -> {
            DoorEntity savedDoor = repository.save(doorEditInfo.mainDoor());
            Map<String, DoorEntity> doorsToSave = new HashMap<>();
            doorEditInfo.additionalDoorsToSave().values().forEach(ad -> {
                if (isBlank(ad.getParentDoorIds())) {
                    ad.setParentDoorIds(savedDoor.getId());
                } else {
                    Set<String> parentDoorIds = Arrays.stream(ad.getParentDoorIds().split(","))
                            .collect(Collectors.toSet());
                    parentDoorIds.add(savedDoor.getId());
                    ad.setParentDoorIds(String.join(",", parentDoorIds));
                }
                doorsToSave.put(ad.getId(), ad);
            });
            doorEditInfo.additionalDoorsWasLinked().forEach((id, door) -> {
                if (!doorEditInfo.additionalDoorsToSave().containsKey(id)) {
                    Set<String> parentIds = Arrays.stream(door.getParentDoorIds().split(","))
                            .collect(Collectors.toSet());
                    parentIds.remove(savedDoor.getId());
                    door.setParentDoorIds(String.join(",", parentIds));
                    doorsToSave.put(id, door);
                }
            });
            repository.saveAll(doorsToSave.values());
            for (ScheduleEntity se : doorEditInfo.schedule()) {
                se.setDoorId(savedDoor.getId());
            }
            scheduleRepository.saveAll(doorEditInfo.schedule());
            refreshDoorsGrid();
            editDoor(null);
        });

        editor.setDeleteListener(door -> {
            EntityManager em = emf.createEntityManager();
            em.getTransaction().begin();
            Query scheduleDeleteQuery = em.createQuery("delete from ScheduleEntity s where s.doorId = :doorId");
            scheduleDeleteQuery.setParameter("doorId", door.getId());
            scheduleDeleteQuery.executeUpdate();
            Query doorDeleteQuery = em.createQuery("delete from DoorEntity d where d.id = :id");
            doorDeleteQuery.setParameter("id", door.getId());
            doorDeleteQuery.executeUpdate();
            em.getTransaction().commit();
            refreshDoorsGrid();
            editDoor(null);
        });

        editor.setCancelListener(() -> editDoor(null));
    }
}
