package org.example.petshopdesktop.controllers.dialogcontrollers;

import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.Alert;
import javafx.scene.control.Button;
import javafx.scene.control.ComboBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.ListCell;
import javafx.scene.control.TextField;
import javafx.scene.input.MouseEvent;
import javafx.scene.layout.VBox;
import javafx.stage.Stage;
import org.example.petshopdesktop.api.dto.adoption.AdoptionRequest;
import org.example.petshopdesktop.api.dto.common.DropdownOption;
import org.example.petshopdesktop.api.endpoints.AdoptionApi;
import org.example.petshopdesktop.api.endpoints.DropdownApi;
import org.example.petshopdesktop.api.endpoints.PetApi;
import org.example.petshopdesktop.auth.UserSession;
import org.example.petshopdesktop.models.Adoption;
import org.example.petshopdesktop.util.ActivityLogger;

import java.math.BigDecimal;
import java.time.LocalDate;
import java.util.List;
import java.util.Objects;

public class AdoptionDialogController {

    @FXML private Button btnCancel;
    @FXML private Button btnSave;
    @FXML private ComboBox<String> cbAdoptionStatus;
    @FXML private ComboBox<DropdownOption> cbCustomer;
    @FXML private ComboBox<DropdownOption> cbEmployee;
    @FXML private ComboBox<DropdownOption> cbPet;
    @FXML private ComboBox<DropdownOption> cbStore;
    @FXML private VBox vbStore;
    @FXML private DatePicker dpAdoptionDate;
    @FXML private TextField txtAdoptionFee;
    @FXML private Label lblAdoptionId;
    @FXML private Label lblMode;

    private String mode = null;
    private Adoption selectedAdoption = null;
    private boolean suppressStatusListener = false;
    private Long pendingStoreId = null;
    private boolean isEditing = false;

    private final ObservableList<String> statusList = FXCollections.observableArrayList(
            "Pending", "Completed", "Missed", "Cancelled"
    );

    @FXML
    void initialize() {
        cbAdoptionStatus.setItems(statusList);
        cbAdoptionStatus.valueProperty().addListener((obs, oldVal, newVal) -> {
            if (!suppressStatusListener && newVal != null) {
                applyStatusFieldRules(newVal);
            }
        });

        txtAdoptionFee.setDisable(true);

        LocalDate today = LocalDate.now();
        dpAdoptionDate.setDayCellFactory(picker -> new javafx.scene.control.DateCell() {
            @Override
            public void updateItem(LocalDate item, boolean empty) {
                super.updateItem(item, empty);
                setDisable(empty || item.isBefore(today));
            }
        });

        setupDropdownCellFactory(cbEmployee);
        setupDropdownCellFactory(cbPet);
        setupDropdownCellFactory(cbCustomer);
        setupDropdownCellFactory(cbStore);

        cbPet.valueProperty().addListener((obs, oldVal, newVal) -> {
            if (newVal != null) {
                loadPetPrice(newVal.getId());
            } else {
                txtAdoptionFee.setText("0");
            }
        });

        if (UserSession.getInstance().isAdmin()) {
            vbStore.setVisible(true);
            vbStore.setManaged(true);
            cbPet.setDisable(true);
            cbPet.setPromptText("Select a store first");
            cbEmployee.setDisable(true);
            cbEmployee.setPromptText("Select a store first");
        } else {
            cbEmployee.setPromptText("Select an employee");
        }

        loadDropdownsAsync();

        btnSave.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                buttonSaveClicked(mouseEvent);
            }
        });

        btnCancel.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                closeStage(mouseEvent);
            }
        });
    }

    private void setupDropdownCellFactory(ComboBox<DropdownOption> cb) {
        cb.setCellFactory(param -> new ListCell<>() {
            @Override protected void updateItem(DropdownOption o, boolean empty) {
                super.updateItem(o, empty);
                setText(empty || o == null ? null : o.getLabel());
            }
        });
        cb.setButtonCell(new ListCell<>() {
            @Override protected void updateItem(DropdownOption o, boolean empty) {
                super.updateItem(o, empty);
                setText(empty || o == null ? null : o.getLabel());
            }
        });
    }

    private void loadDropdownsAsync() {
        new Thread(() -> {
            try {
                List<DropdownOption> customers = DropdownApi.getInstance().getCustomers();
                Platform.runLater(() -> {
                    if (customers != null) {
                        cbCustomer.setItems(FXCollections.observableArrayList(customers));
                        applySelectedCustomer();
                    }
                });
            } catch (Exception e) {
                Platform.runLater(() -> ActivityLogger.getInstance().logException(
                    "AdoptionDialogController.loadDropdownsAsync", e, "Loading customers"));
            }
        }).start();

        if (UserSession.getInstance().isAdmin()) {
            new Thread(() -> {
                try {
                    List<DropdownOption> stores = DropdownApi.getInstance().getStores();
                    Platform.runLater(() -> {
                        if (stores != null) {
                            cbStore.setItems(FXCollections.observableArrayList(stores));
                            cbStore.valueProperty().addListener((obs, oldVal, newVal) -> {
                                Long sid = newVal != null ? newVal.getId() : null;
                                cbEmployee.setValue(null);
                                cbEmployee.setItems(FXCollections.observableArrayList());
                                if (sid != null) {
                                    String status = cbAdoptionStatus.getValue();
                                    boolean locked = "Cancelled".equalsIgnoreCase(status)
                                            || "Completed".equalsIgnoreCase(status)
                                            || "Missed".equalsIgnoreCase(status);
                                    if (!locked) {
                                        cbEmployee.setDisable(false);
                                        cbEmployee.setPromptText("Select an employee");
                                    }
                                    loadEmployeesForStore(sid);
                                    if (!isEditing) {
                                        cbPet.setValue(null);
                                        cbPet.setItems(FXCollections.observableArrayList());
                                        cbPet.setDisable(true);
                                        cbPet.setPromptText("Select a pet");
                                        loadAdoptionPetsForStore(sid);
                                    }
                                } else {
                                    String status = cbAdoptionStatus.getValue();
                                    boolean locked = "Cancelled".equalsIgnoreCase(status)
                                            || "Completed".equalsIgnoreCase(status)
                                            || "Missed".equalsIgnoreCase(status);
                                    if (!locked) {
                                        cbEmployee.setDisable(true);
                                        cbEmployee.setPromptText("Select a store first");
                                    }
                                    if (!isEditing) {
                                        cbPet.setValue(null);
                                        cbPet.setItems(FXCollections.observableArrayList());
                                        cbPet.setDisable(true);
                                        cbPet.setPromptText("Select a store first");
                                    }
                                }
                            });
                            if (pendingStoreId != null) {
                                for (DropdownOption store : cbStore.getItems()) {
                                    if (pendingStoreId.equals(store.getId())) {
                                        cbStore.setValue(store);
                                        break;
                                    }
                                }
                                pendingStoreId = null;
                            }
                        }
                    });
                } catch (Exception e) {
                    Platform.runLater(() -> ActivityLogger.getInstance().logException(
                        "AdoptionDialogController.loadDropdownsAsync", e, "Loading stores"));
                }
            }).start();
        } else {
            Long storeId = UserSession.getInstance().getStoreId();
            if (storeId != null && storeId > 0) {
                new Thread(() -> {
                    try {
                        List<DropdownOption> employees = DropdownApi.getInstance().getStoreEmployees(storeId);
                        Platform.runLater(() -> {
                            ObservableList<DropdownOption> employeesObs = FXCollections.observableArrayList(employees != null ? employees : List.of());
                            ensureSelectedEmployeeOption(employeesObs);
                            cbEmployee.setItems(employeesObs);
                            applySelectedEmployee();
                        });
                    } catch (Exception e) {
                        Platform.runLater(() -> {
                            ActivityLogger.getInstance().logException(
                                "AdoptionDialogController.loadDropdownsAsync", e, "Loading employees");
                            cbEmployee.setDisable(true);
                            cbEmployee.setPromptText("Unable to load employees");
                        });
                    }
                }).start();

                new Thread(() -> {
                    try {
                        List<DropdownOption> pets = DropdownApi.getInstance().getAdoptionPets(storeId);
                        Platform.runLater(() -> {
                            if (!isEditing && pets != null) {
                                ObservableList<DropdownOption> petsObs = FXCollections.observableArrayList(pets);
                                cbPet.setItems(petsObs);
                                if (petsObs.isEmpty()) {
                                    cbPet.setDisable(true);
                                    cbPet.setPromptText("No available pets for this store");
                                }
                            }
                        });
                    } catch (Exception e) {
                        Platform.runLater(() -> ActivityLogger.getInstance().logException(
                            "AdoptionDialogController.loadDropdownsAsync", e, "Loading pets"));
                    }
                }).start();
            }
        }
    }

    private void loadEmployeesForStore(Long storeId) {
        new Thread(() -> {
            try {
                List<DropdownOption> employees = DropdownApi.getInstance().getStoreEmployees(storeId);
                Platform.runLater(() -> {
                    ObservableList<DropdownOption> employeesObs = FXCollections.observableArrayList(employees != null ? employees : List.of());
                    ensureSelectedEmployeeOption(employeesObs);
                    cbEmployee.setItems(employeesObs);
                    applySelectedEmployee();
                });
            } catch (Exception e) {
                Platform.runLater(() -> {
                    ActivityLogger.getInstance().logException(
                        "AdoptionDialogController.loadEmployeesForStore", e, "Loading employees for store");
                    cbEmployee.setDisable(true);
                    cbEmployee.setPromptText("Unable to load employees");
                });
            }
        }).start();
    }

    private void loadAdoptionPetsForStore(Long storeId) {
        new Thread(() -> {
            try {
                List<DropdownOption> pets = DropdownApi.getInstance().getAdoptionPets(storeId);
                Platform.runLater(() -> {
                    if (pets != null) {
                        ObservableList<DropdownOption> petsObs = FXCollections.observableArrayList(pets);
                        cbPet.setItems(petsObs);
                        if (petsObs.isEmpty()) {
                            cbPet.setDisable(true);
                            cbPet.setPromptText("No available pets for this store");
                        } else {
                            cbPet.setDisable(false);
                        }
                    }
                });
            } catch (Exception e) {
                Platform.runLater(() -> {
                    ActivityLogger.getInstance().logException(
                        "AdoptionDialogController.loadAdoptionPetsForStore", e, "Loading adoption pets for store");
                    cbPet.setDisable(true);
                    cbPet.setPromptText("Unable to load pets");
                });
            }
        }).start();
    }

    private void applyStatusFieldRules(String status) {
        if ("Cancelled".equalsIgnoreCase(status) || "Completed".equalsIgnoreCase(status) || "Missed".equalsIgnoreCase(status)) {
            cbEmployee.setDisable(true);
            dpAdoptionDate.setDisable(true);
            cbStore.setDisable(true);
        } else {
            cbEmployee.setDisable(false);
            dpAdoptionDate.setDisable(false);
            if (UserSession.getInstance().isAdmin() && !isEditing) cbStore.setDisable(false);
        }
    }

    private void buttonSaveClicked(MouseEvent mouseEvent) {
        String errorMsg = "";

        if (cbPet.getSelectionModel().getSelectedItem() == null) errorMsg += "Pet is required.\n";
        if (cbCustomer.getSelectionModel().getSelectedItem() == null) errorMsg += "Customer is required.\n";
        if (cbEmployee.getSelectionModel().getSelectedItem() == null) errorMsg += "Employee is required.\n";
        if (dpAdoptionDate.getValue() == null) errorMsg += "Adoption Date is required.\n";
        if (cbAdoptionStatus.getSelectionModel().getSelectedItem() == null) errorMsg += "Status is required.\n";

        BigDecimal adoptionFee = BigDecimal.ZERO;
        String feeText = txtAdoptionFee.getText() == null ? "" : txtAdoptionFee.getText().trim();
        if (!feeText.isEmpty()) {
            try {
                adoptionFee = new BigDecimal(feeText);
            } catch (NumberFormatException e) {
                adoptionFee = BigDecimal.ZERO;
            }
        }

        if (errorMsg.isEmpty()) {
            try {
                Long storeId;
                if (UserSession.getInstance().isAdmin()) {
                    if (cbStore.getSelectionModel().getSelectedItem() == null) {
                        Alert alert = new Alert(Alert.AlertType.ERROR);
                        alert.setHeaderText("Input Error");
                        alert.setContentText("Store is required.");
                        alert.showAndWait();
                        return;
                    }
                    storeId = cbStore.getSelectionModel().getSelectedItem().getId();
                } else {
                    storeId = UserSession.getInstance().getStoreId();
                }
                if (storeId == null || storeId <= 0) {
                    throw new IllegalStateException("Store is not set for this account");
                }

                AdoptionRequest request = new AdoptionRequest();
                request.setPetId(cbPet.getSelectionModel().getSelectedItem().getId());
                request.setCustomerId(cbCustomer.getSelectionModel().getSelectedItem().getId());
                request.setEmployeeId(cbEmployee.getSelectionModel().getSelectedItem().getId());
                request.setSourceStoreId(storeId);
                request.setAdoptionDate(dpAdoptionDate.getValue());
                request.setAdoptionStatus(cbAdoptionStatus.getValue());
                request.setAdoptionFee(adoptionFee);

                if (mode.equals("Add")) {
                    AdoptionApi.getInstance().createAdoption(request);
                } else {
                    String[] parts = lblAdoptionId.getText().split(": ");
                    if (parts.length < 2) throw new IllegalStateException("Invalid adoption ID format");
                    Long adoptionId = Long.parseLong(parts[1]);
                    AdoptionApi.getInstance().updateAdoption(adoptionId, request);
                }

                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setHeaderText("Saved");
                alert.setContentText(mode + " succeeded");
                alert.showAndWait();
                closeStage(mouseEvent);
            } catch (Exception e) {
                ActivityLogger.getInstance().logException(
                    "AdoptionDialogController.buttonSaveClicked", e, mode + " adoption");
                Alert alert = new Alert(Alert.AlertType.ERROR);
                alert.setHeaderText("Database Operation Error");
                alert.setContentText(e.getMessage());
                alert.showAndWait();
            }
        } else {
            Alert alert = new Alert(Alert.AlertType.ERROR);
            alert.setHeaderText("Input Error");
            alert.setContentText(errorMsg);
            alert.showAndWait();
        }
    }

    private void closeStage(MouseEvent mouseEvent) {
        Node node = (Node) mouseEvent.getSource();
        Stage stage = (Stage) node.getScene().getWindow();
        stage.close();
    }

    public void displayAdoptionDetails(Adoption adoption) {
        if (adoption == null) return;
        selectedAdoption = adoption;
        isEditing = true;
        lblAdoptionId.setText("ID: " + adoption.getAdoptionId());
        pendingStoreId = adoption.getStoreId();

        if (adoption.getPetId() > 0) {
            DropdownOption petOption = new DropdownOption();
            petOption.setId((long) adoption.getPetId());
            petOption.setLabel(adoption.getPetName() != null && !adoption.getPetName().isBlank()
                    ? adoption.getPetName() : "Pet #" + adoption.getPetId());
            cbPet.setItems(FXCollections.observableArrayList(petOption));
            cbPet.setValue(petOption);
        }

        applySelectedCustomer();
        applySelectedEmployee();

        if (adoption.getAdoptionDate() != null && !adoption.getAdoptionDate().isEmpty()) {
            try {
                dpAdoptionDate.setValue(LocalDate.parse(adoption.getAdoptionDate()));
            } catch (Exception e) {
                ActivityLogger.getInstance().logException(
                    "AdoptionDialogController.displayAdoptionDetails", e, "Parsing adoption date");
            }
        }

        txtAdoptionFee.setText(adoption.getAdoptionFee() > 0
                ? String.format("%.2f", adoption.getAdoptionFee()) : "0.00");

        suppressStatusListener = true;
        cbAdoptionStatus.setItems(statusList);
        for (String status : cbAdoptionStatus.getItems()) {
            if (status.equals(adoption.getAdoptionStatus())) {
                cbAdoptionStatus.getSelectionModel().select(status);
                break;
            }
        }
        suppressStatusListener = false;
        applyEditModeLock();
    }

    private void applyEditModeLock() {
        String status = cbAdoptionStatus.getValue();

        if ("Cancelled".equalsIgnoreCase(status)) {
            cbPet.setDisable(true);
            cbCustomer.setDisable(true);
            cbEmployee.setDisable(true);
            dpAdoptionDate.setDisable(true);
            cbAdoptionStatus.setDisable(true);
            cbAdoptionStatus.setItems(FXCollections.observableArrayList("Cancelled"));
            cbStore.setDisable(true);
            btnSave.setDisable(true);
            return;
        }

        LocalDate adoptionDate = dpAdoptionDate.getValue();
        boolean isPast = adoptionDate != null && adoptionDate.isBefore(LocalDate.now());

        if (isPast) {
            cbPet.setDisable(true);
            cbCustomer.setDisable(true);
            cbEmployee.setDisable(true);
            dpAdoptionDate.setDisable(true);
            cbStore.setDisable(true);
            cbAdoptionStatus.setDisable(false);
            suppressStatusListener = true;
            cbAdoptionStatus.setItems(FXCollections.observableArrayList("Completed", "Missed"));
            if (!cbAdoptionStatus.getItems().contains(cbAdoptionStatus.getValue())) {
                cbAdoptionStatus.getSelectionModel().selectFirst();
            }
            suppressStatusListener = false;
        } else {
            cbPet.setDisable(true);
            cbCustomer.setDisable(true);
            dpAdoptionDate.setDisable(false);
            cbEmployee.setDisable(false);
            cbAdoptionStatus.setDisable(false);
            cbStore.setDisable(true);
            suppressStatusListener = true;
            cbAdoptionStatus.setItems(FXCollections.observableArrayList("Pending", "Cancelled"));
            if (!cbAdoptionStatus.getItems().contains(cbAdoptionStatus.getValue())) {
                cbAdoptionStatus.getSelectionModel().selectFirst();
            }
            suppressStatusListener = false;
        }
    }

    public void setMode(String mode) {
        this.mode = mode;
        lblMode.setText(mode + " Adoption");
        lblAdoptionId.setVisible(mode.equals("Edit"));
        if (mode.equals("Add")) {
            suppressStatusListener = true;
            cbAdoptionStatus.setItems(FXCollections.observableArrayList("Pending"));
            cbAdoptionStatus.setValue("Pending");
            cbAdoptionStatus.setDisable(true);
            suppressStatusListener = false;
            txtAdoptionFee.setText("");
        }
    }

    private void applySelectedPet() {
        if (selectedAdoption == null || selectedAdoption.getPetId() <= 0) return;
        DropdownOption selected = findOptionById(cbPet.getItems(), (long) selectedAdoption.getPetId());
        if (selected != null && !Objects.equals(cbPet.getValue(), selected)) cbPet.setValue(selected);
    }

    private void applySelectedCustomer() {
        if (selectedAdoption == null || selectedAdoption.getCustomerId() <= 0) return;
        DropdownOption selected = findOptionById(cbCustomer.getItems(), (long) selectedAdoption.getCustomerId());
        if (selected != null && !Objects.equals(cbCustomer.getValue(), selected)) cbCustomer.setValue(selected);
    }

    private void applySelectedEmployee() {
        if (selectedAdoption == null || selectedAdoption.getEmployeeId() <= 0) return;
        DropdownOption selected = findOptionById(cbEmployee.getItems(), (long) selectedAdoption.getEmployeeId());
        if (selected != null && !Objects.equals(cbEmployee.getValue(), selected)) cbEmployee.setValue(selected);
    }

    private DropdownOption findOptionById(List<DropdownOption> options, Long id) {
        if (id == null || options == null) return null;
        for (DropdownOption option : options) {
            if (option.getId() != null && option.getId().equals(id)) return option;
        }
        return null;
    }

    private void loadPetPrice(Long petId) {
        new Thread(() -> {
            try {
                var pet = PetApi.getInstance().getPetById(petId);
                Platform.runLater(() -> {
                    if (pet != null && pet.getPetPrice() != null) {
                        txtAdoptionFee.setText(String.format("%.2f", pet.getPetPrice()));
                    } else {
                        txtAdoptionFee.setText("0.00");
                    }
                });
            } catch (Exception e) {
                Platform.runLater(() -> {
                    txtAdoptionFee.setText("0.00");
                    ActivityLogger.getInstance().logException(
                        "AdoptionDialogController.loadPetPrice", e, "Loading pet price");
                });
            }
        }).start();
    }

    private void ensureSelectedEmployeeOption(ObservableList<DropdownOption> options) {
        if (selectedAdoption == null || selectedAdoption.getEmployeeId() <= 0 || options == null) return;
        DropdownOption existing = findOptionById(options, (long) selectedAdoption.getEmployeeId());
        if (existing == null) {
            DropdownOption option = new DropdownOption();
            option.setId((long) selectedAdoption.getEmployeeId());
            option.setLabel(selectedAdoption.getEmployeeName() != null ? selectedAdoption.getEmployeeName() : "Employee #" + selectedAdoption.getEmployeeId());
            options.add(0, option);
        }
    }

    private void ensureSelectedPetOption(ObservableList<DropdownOption> options) {
        if (selectedAdoption == null || selectedAdoption.getPetId() <= 0 || options == null) return;
        DropdownOption existing = findOptionById(options, (long) selectedAdoption.getPetId());
        if (existing == null) {
            DropdownOption option = new DropdownOption();
            option.setId((long) selectedAdoption.getPetId());
            option.setLabel(selectedAdoption.getPetName());
            options.add(0, option);
        }
    }
}
