package org.example.petshopdesktop.controllers;

import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Modality;
import org.example.petshopdesktop.auth.UserSession;
import javafx.stage.Stage;
import org.example.petshopdesktop.api.dto.common.DropdownOption;
import org.example.petshopdesktop.api.dto.inventory.InventoryResponse;
import org.example.petshopdesktop.api.endpoints.DropdownApi;
import org.example.petshopdesktop.api.endpoints.InventoryApi;
import org.example.petshopdesktop.controllers.dialogcontrollers.InventoryDialogController;
import org.example.petshopdesktop.models.Inventory;
import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;

import java.io.IOException;
import java.util.List;
import java.util.Optional;
import java.util.stream.Collectors;

public class InventoryController {

    //FXML elements
    @FXML
    private Button btnAdd;

    @FXML
    private Button btnDelete;

    @FXML
    private Button btnEdit;

    @FXML
    private Button btnRefresh;

    @FXML
    private Label lblStatus;

    @FXML
    private TableColumn<Inventory, Integer> colInventoryId;

    @FXML
    private TableColumn<Inventory, Integer> colProductId;

    @FXML
    private TableColumn<Inventory, String> colProductName;

    @FXML
    private TableColumn<Inventory, Integer> colQuantity;

    @FXML
    private TableColumn<Inventory, String> colStoreName;

    @FXML
    private TableView<Inventory> tvInventory;

    @FXML
    private TextField txtSearch;

    @FXML
    private ComboBox<DropdownOption> cbStoreFilter;

    private final java.util.ArrayList<DropdownOption> storeOptions = new java.util.ArrayList<>();

    private ObservableList<Inventory> data = FXCollections.observableArrayList();

    //Determines if in add/edit mode
    private String mode = null;

    //Loads upon view bootup
    @FXML
    void initialize() {
        btnEdit.setDisable(true);
        btnDelete.setDisable(true);
        tvInventory.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.SINGLE);

        colInventoryId.setCellValueFactory(new PropertyValueFactory<>("inventoryId"));
        colProductId.setCellValueFactory(new PropertyValueFactory<>("prodId"));
        colProductName.setCellValueFactory(new PropertyValueFactory<>("prodName"));
        colQuantity.setCellValueFactory(new PropertyValueFactory<>("quantity"));
        colStoreName.setCellValueFactory(new PropertyValueFactory<>("storeName"));

        if (UserSession.getInstance().isAdmin()) {
            cbStoreFilter.setVisible(true);
            cbStoreFilter.setManaged(true);
            loadStoreFilter();
        }
        cbStoreFilter.valueProperty().addListener((obs, o, n) -> displayInventory());

        displayInventory();
        TableViewSupport.installDoubleClickAction(tvInventory, selected -> openDialog(selected, "Edit"));

        tvInventory.getSelectionModel().selectedItemProperty().addListener(
                (observable, oldValue, newValue) -> {
                    boolean hasSelection = newValue != null;
                    btnEdit.setDisable(!hasSelection);
                    btnDelete.setDisable(!hasSelection);
                });

        txtSearch.textProperty().addListener((observable, oldValue, newValue) -> {
            displayFilteredInventory(newValue);
        });

        tvInventory.setOnKeyPressed(event -> {
            if (event.getCode() == javafx.scene.input.KeyCode.DELETE) {
                if (tvInventory.getSelectionModel().getSelectedItem() != null) {
                    btnDeleteClicked(null);
                }
            }
        });
    }

    //Opens dialog in add mode
    @FXML
    void btnRefresh(ActionEvent event) {
        txtSearch.clear();
        cbStoreFilter.getSelectionModel().selectFirst();
        tvInventory.getSortOrder().clear();
        displayInventory();
        TableViewSupport.flashStatus(lblStatus, "Refreshed");
    }

    @FXML
    void btnAddClicked(ActionEvent event) {
        mode = "Add";
        openDialog(null, mode);
    }

    @FXML
    void btnDeleteClicked(ActionEvent event) {
        Inventory selectedInventory = tvInventory.getSelectionModel().getSelectedItem();
        if (selectedInventory == null) return;

        Alert question = new Alert(Alert.AlertType.CONFIRMATION);
        question.setHeaderText("Please confirm delete");
        question.setContentText("Are you sure you want to delete this inventory record?");
        question.getDialogPane().lookupButton(ButtonType.OK).requestFocus();
        Optional<ButtonType> result = question.showAndWait();

        if (result.isPresent() && result.get() == ButtonType.OK) {
            try {
                InventoryApi.getInstance().deleteInventory((long) selectedInventory.getInventoryId());
                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setHeaderText("Database Operation Confirmed");
                alert.setContentText("Successfully deleted inventory record");
                alert.showAndWait();
            } catch (Exception e) {
                ActivityLogger.getInstance().logException(
                    "InventoryController.btnDeleteClicked",
                    e,
                    "Deleting inventory");
                Alert alert = new Alert(Alert.AlertType.ERROR);
                alert.setHeaderText("Delete Operation Failed");
                alert.setContentText(e.getMessage());
                alert.showAndWait();
            }

            displayInventory();
            btnDelete.setDisable(true);
            btnEdit.setDisable(true);
            txtSearch.setText("");
        }
    }

    //Editing a record
    @FXML
    void btnEditClicked(ActionEvent event) {
        Inventory selectedInventory = tvInventory.getSelectionModel().getSelectedItem();

        if (selectedInventory != null) {
            mode = "Edit";
            openDialog(selectedInventory, mode);
        }
    }

    private void displayFilteredInventory(String filter) {
        if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) {
            displayInventory();
        } else {
            new Thread(() -> {
                try {
                    Long storeId = selectedStoreId();
                    List<InventoryResponse> inventories = InventoryApi.getInstance().listInventory(filter, storeId);
                    List<Inventory> inventoryList = inventories.stream()
                        .map(this::mapToInventory)
                        .collect(Collectors.toList());

                    Platform.runLater(() -> {
                        data.setAll(inventoryList);
                        tvInventory.setItems(data);
                    });
                } catch (Exception e) {
                    Platform.runLater(() -> {
                        System.out.println("Error while fetching table data: " + e.getMessage());
                        ActivityLogger.getInstance().logException(
                            "InventoryController.displayFilteredInventory",
                            e,
                            String.format("Filtering inventory with keyword: %s", filter));
                    });
                }
            }).start();
        }
    }

    private void displayInventory() {
        new Thread(() -> {
            try {
                Long storeId = selectedStoreId();
                List<InventoryResponse> inventories = InventoryApi.getInstance().listInventory(null, storeId);
                List<Inventory> inventoryList = inventories.stream()
                    .map(this::mapToInventory)
                    .collect(Collectors.toList());

                Platform.runLater(() -> {
                    data.setAll(inventoryList);
                    tvInventory.setItems(data);
                });
            } catch (Exception e) {
                Platform.runLater(() -> {
                    System.out.println("Error while fetching table data: " + e.getMessage());
                    ActivityLogger.getInstance().logException(
                        "InventoryController.displayInventory",
                        e,
                        "Fetching inventory data for table display");
                });
            }
        }).start();
    }

    private void openDialog(Inventory inventory, String mode) {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/inventory-dialog-view.fxml"));
        Scene scene = null;

        try {
            scene = new Scene(fxmlLoader.load());
        } catch (IOException e) {
            ActivityLogger.getInstance().logException(
                "InventoryController.openDialog",
                e,
                String.format("Loading inventory dialog view in %s mode", mode));
            throw new RuntimeException(e);
        }

        InventoryDialogController dialogController = fxmlLoader.getController();
        dialogController.setMode(mode);

        if (mode.equals("Edit")) {
            dialogController.displayInventoryDetails(inventory);
        }

        Stage dialogStage = new Stage();
        dialogStage.initModality(Modality.APPLICATION_MODAL);
        dialogStage.setTitle(mode.equals("Add") ? "Add Inventory" : "Edit Inventory");
        dialogStage.setScene(scene);
        dialogStage.showAndWait();

        displayInventory();
        btnDelete.setDisable(true);
        btnEdit.setDisable(true);
        txtSearch.setText("");
    }

    private void loadStoreFilter() {
        new Thread(() -> {
            try {
                List<DropdownOption> stores = DropdownApi.getInstance().getStores();
                DropdownOption allStores = new DropdownOption();
                allStores.setLabel("All Stores");
                Platform.runLater(() -> {
                    storeOptions.clear();
                    storeOptions.addAll(stores);
                    java.util.List<DropdownOption> items = new java.util.ArrayList<>();
                    items.add(allStores);
                    items.addAll(stores);
                    cbStoreFilter.setItems(FXCollections.observableArrayList(items));
                    cbStoreFilter.getSelectionModel().selectFirst();
                });
            } catch (Exception e) {
                ActivityLogger.getInstance().logException("InventoryController.loadStoreFilter", e, "Loading store filter");
            }
        }).start();
    }

    private Long selectedStoreId() {
        if (!UserSession.getInstance().isAdmin()) return UserSession.getInstance().getStoreId();
        DropdownOption selected = cbStoreFilter.getValue();
        return (selected != null && selected.getId() != null) ? selected.getId() : null;
    }

    private Inventory mapToInventory(InventoryResponse response) {
        return new Inventory(
            response.getInventoryId().intValue(),
            response.getProdId() != null ? response.getProdId().intValue() : 0,
            response.getProductName(),
            response.getCategoryName() != null ? response.getCategoryName() : "",
            response.getStoreId() != null ? response.getStoreId().intValue() : 0,
            response.getStoreName() != null ? response.getStoreName() : "",
            response.getQuantity() != null ? response.getQuantity() : 0,
            0
        );
    }
}
