package de.votian.web.view;

import com.vaadin.flow.component.button.Button;
import com.vaadin.flow.component.button.ButtonVariant;
import com.vaadin.flow.component.combobox.ComboBox;
import com.vaadin.flow.component.datepicker.DatePicker;
import com.vaadin.flow.component.formlayout.FormLayout;
import com.vaadin.flow.component.grid.Grid;
import com.vaadin.flow.component.html.H3;
import com.vaadin.flow.component.notification.Notification;
import com.vaadin.flow.component.notification.NotificationVariant;
import com.vaadin.flow.component.orderedlayout.HorizontalLayout;
import com.vaadin.flow.component.orderedlayout.VerticalLayout;
import com.vaadin.flow.component.textfield.IntegerField;
import com.vaadin.flow.component.textfield.NumberField;
import com.vaadin.flow.component.textfield.TextField;
import com.vaadin.flow.router.PageTitle;
import com.vaadin.flow.router.Route;
import de.votian.web.model.SessionData;
import de.votian.web.service.RestClientService;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;

@Route(value = "pricing", layout = MainLayout.class)
@PageTitle("Votian - Preise")
public class PricingView extends VerticalLayout {

    private final RestClientService restClient;
    private final SessionData sessionData;

    private final ComboBox<Map<String, Object>> customerBox = new ComboBox<>("Kunde");
    private final ComboBox<Map<String, Object>> typeBox = new ComboBox<>("Leistungstyp");
    private final Grid<Map<String, Object>> grid = new Grid<>();
    private final NumberField priceField = new NumberField("Preis");
    private final NumberField courierPriceField = new NumberField("Kurierpreis");
    private final NumberField discountField = new NumberField("Rabatt");
    private final DatePicker validFromField = new DatePicker("Gueltig ab");
    private Long selectedServiceId;

    public PricingView(RestClientService restClient, SessionData sessionData) {
        this.restClient = restClient;
        this.sessionData = sessionData;

        setPadding(true);
        setSpacing(true);

        customerBox.setItemLabelGenerator(item -> (String) item.getOrDefault("companyName", "Global"));
        customerBox.addValueChangeListener(event -> loadPrices());

        typeBox.setItemLabelGenerator(item -> (String) item.getOrDefault("name", ""));

        Button reloadButton = new Button("Neu laden", event -> loadPrices());
        reloadButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);

        HorizontalLayout filterBar = new HorizontalLayout(customerBox, reloadButton);
        filterBar.setAlignItems(Alignment.BASELINE);

        grid.addColumn(item -> item.get("serviceTypeName")).setHeader("Typ").setAutoWidth(true);
        grid.addColumn(item -> item.get("serviceName")).setHeader("Leistung").setFlexGrow(1);
        grid.addColumn(item -> item.get("price")).setHeader("Preis").setAutoWidth(true);
        grid.addColumn(item -> item.get("courierPrice")).setHeader("Kurierpreis").setAutoWidth(true);
        grid.addColumn(item -> item.get("discount")).setHeader("Rabatt").setAutoWidth(true);
        grid.addColumn(item -> item.get("validFrom")).setHeader("Gueltig ab").setAutoWidth(true);
        grid.setHeight("320px");
        grid.addSelectionListener(event -> event.getFirstSelectedItem().ifPresent(this::selectPrice));

        validFromField.setValue(LocalDate.now());

        Button savePriceButton = new Button("Preis speichern", event -> savePrice());
        savePriceButton.addThemeVariants(ButtonVariant.LUMO_PRIMARY);
        savePriceButton.setEnabled(sessionData.canManagePricing());

        FormLayout priceForm = new FormLayout();
        priceForm.setResponsiveSteps(new FormLayout.ResponsiveStep("0", 1),
                new FormLayout.ResponsiveStep("700px", 2));
        priceForm.add(priceField, courierPriceField, discountField, validFromField, savePriceButton);

        TextField newTypeNameField = new TextField("Neuer Leistungstyp");
        IntegerField newTypeModeField = new IntegerField("Typ-Modus");
        newTypeModeField.setValue(0);
        Button addTypeButton = new Button("Typ anlegen", event -> addType(newTypeNameField, newTypeModeField));

        TextField newServiceNameField = new TextField("Neue Leistung");
        IntegerField newServiceModeField = new IntegerField("Leistungs-Modus");
        newServiceModeField.setValue(0);
        Button addServiceButton = new Button("Leistung anlegen", event -> addService(newServiceNameField, newServiceModeField));
        addTypeButton.setEnabled(sessionData.canManagePricing());
        addServiceButton.setEnabled(sessionData.canManagePricing());

        FormLayout catalogForm = new FormLayout();
        catalogForm.setResponsiveSteps(new FormLayout.ResponsiveStep("0", 1),
                new FormLayout.ResponsiveStep("900px", 3));
        catalogForm.add(newTypeNameField, newTypeModeField, addTypeButton, newServiceNameField, typeBox, newServiceModeField, addServiceButton);

        add(new H3("Preisverwaltung"), filterBar, grid, new H3("Preis bearbeiten"), priceForm,
                new H3("Leistungen und Typen"), catalogForm);

        loadCustomers();
        loadTypes();
        loadPrices();
    }

    private void loadCustomers() {
        if (sessionData.getHeadquartersId() == null) {
            return;
        }
        try {
            Object[] result = restClient.get("/customers/hq/" + sessionData.getHeadquartersId(), Object[].class);
            List<Map<String, Object>> items = new ArrayList<>();
            Map<String, Object> global = new LinkedHashMap<>();
            global.put("id", 0L);
            global.put("companyName", "Globale Preise");
            items.add(global);
            if (result != null) {
                for (Object obj : result) {
                    if (obj instanceof Map<?, ?> map) {
                        @SuppressWarnings("unchecked")
                        Map<String, Object> typed = (Map<String, Object>) map;
                        items.add(typed);
                    }
                }
            }
            customerBox.setItems(items);
            customerBox.setValue(items.get(0));
        } catch (Exception e) {
            Notification.show("Kunden konnten nicht geladen werden.", 4000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_ERROR);
        }
    }

    private void loadTypes() {
        if (sessionData.getHeadquartersId() == null) {
            return;
        }
        try {
            Object[] result = restClient.get("/services/types/hq/" + sessionData.getHeadquartersId(), Object[].class);
            List<Map<String, Object>> items = new ArrayList<>();
            if (result != null) {
                for (Object obj : result) {
                    if (obj instanceof Map<?, ?> map) {
                        @SuppressWarnings("unchecked")
                        Map<String, Object> typed = (Map<String, Object>) map;
                        items.add(typed);
                    }
                }
            }
            typeBox.setItems(items);
        } catch (Exception e) {
            Notification.show("Leistungstypen konnten nicht geladen werden.", 4000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_ERROR);
        }
    }

    private void loadPrices() {
        if (sessionData.getHeadquartersId() == null) {
            return;
        }

        String customerParam = "";
        Map<String, Object> selectedCustomer = customerBox.getValue();
        if (selectedCustomer != null && selectedCustomer.get("id") instanceof Number number && number.longValue() > 0) {
            customerParam = "&customerId=" + number.longValue();
        }

        try {
            Object[] result = restClient.get("/services/prices?hqId=" + sessionData.getHeadquartersId() + customerParam, Object[].class);
            List<Map<String, Object>> items = new ArrayList<>();
            if (result != null) {
                for (Object obj : result) {
                    if (obj instanceof Map<?, ?> map) {
                        @SuppressWarnings("unchecked")
                        Map<String, Object> typed = (Map<String, Object>) map;
                        items.add(typed);
                    }
                }
            }
            grid.setItems(items);
        } catch (Exception e) {
            Notification.show("Preise konnten nicht geladen werden.", 4000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_ERROR);
        }
    }

    private void selectPrice(Map<String, Object> item) {
        selectedServiceId = item.get("serviceId") instanceof Number number ? number.longValue() : null;
        priceField.setValue(asDouble(item.get("price")));
        courierPriceField.setValue(asDouble(item.get("courierPrice")));
        discountField.setValue(asDouble(item.get("discount")));
        if (item.get("validFrom") != null) {
            validFromField.setValue(LocalDate.parse(item.get("validFrom").toString()));
        }
    }

    private void savePrice() {
        if (!sessionData.canManagePricing()) {
            Notification.show("Keine Berechtigung zur Preispflege.", 3000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_ERROR);
            return;
        }
        if (selectedServiceId == null || sessionData.getHeadquartersId() == null) {
            Notification.show("Bitte zuerst eine Leistung auswaehlen.", 3000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_ERROR);
            return;
        }

        try {
            Map<String, Object> request = new LinkedHashMap<>();
            request.put("serviceId", selectedServiceId);
            request.put("headquartersId", sessionData.getHeadquartersId());
            request.put("customerId", selectedCustomerId());
            request.put("date", validFromField.getValue() != null ? validFromField.getValue().toString() : LocalDate.now().toString());
            request.put("price", decimal(priceField.getValue()));
            request.put("courierPrice", decimal(courierPriceField.getValue()));
            request.put("discount", decimal(discountField.getValue()));

            restClient.post("/services/history", request, LinkedHashMap.class);
            Notification.show("Preis gespeichert.", 3000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_SUCCESS);
            loadPrices();
        } catch (Exception e) {
            Notification.show("Preis konnte nicht gespeichert werden.", 5000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_ERROR);
        }
    }

    private void addType(TextField nameField, IntegerField modeField) {
        if (!sessionData.canManagePricing()) {
            return;
        }
        if (sessionData.getHeadquartersId() == null || nameField.getValue().isBlank()) {
            return;
        }
        try {
            Map<String, Object> request = new LinkedHashMap<>();
            request.put("name", nameField.getValue());
            request.put("mode", modeField.getValue());
            request.put("headquartersId", sessionData.getHeadquartersId());
            request.put("customerId", selectedCustomerId());
            restClient.post("/services/types", request, LinkedHashMap.class);
            nameField.clear();
            loadTypes();
        } catch (Exception e) {
            Notification.show("Leistungstyp konnte nicht gespeichert werden.", 4000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_ERROR);
        }
    }

    private void addService(TextField nameField, IntegerField modeField) {
        if (!sessionData.canManagePricing()) {
            return;
        }
        if (sessionData.getHeadquartersId() == null || nameField.getValue().isBlank() || typeBox.getValue() == null) {
            return;
        }
        try {
            Map<String, Object> request = new LinkedHashMap<>();
            request.put("name", nameField.getValue());
            request.put("mode", modeField.getValue());
            request.put("headquartersId", sessionData.getHeadquartersId());
            request.put("customerId", selectedCustomerId());
            request.put("serviceTypeId", typeBox.getValue().get("id"));
            restClient.post("/services/entity", request, LinkedHashMap.class);
            nameField.clear();
            loadPrices();
        } catch (Exception e) {
            Notification.show("Leistung konnte nicht gespeichert werden.", 4000, Notification.Position.MIDDLE)
                    .addThemeVariants(NotificationVariant.LUMO_ERROR);
        }
    }

    private Long selectedCustomerId() {
        Map<String, Object> selectedCustomer = customerBox.getValue();
        if (selectedCustomer != null && selectedCustomer.get("id") instanceof Number number) {
            return number.longValue();
        }
        return 0L;
    }

    private Double asDouble(Object value) {
        return value instanceof Number ? ((Number) value).doubleValue() : null;
    }

    private BigDecimal decimal(Double value) {
        return value != null ? BigDecimal.valueOf(value) : null;
    }
}
