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 javafx.stage.Stage;
import org.example.petshopdesktop.api.dto.supplier.SupplierResponse;
import org.example.petshopdesktop.api.endpoints.SupplierApi;
import org.example.petshopdesktop.controllers.dialogcontrollers.SupplierDialogController;
import org.example.petshopdesktop.models.Supplier;
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;

/**
 * The controller for any operations in the supplier view
 */
public class SupplierController {

    @FXML
    private Button btnAdd;

    @FXML
    private Button btnDelete;

    @FXML
    private Button btnEdit;

    @FXML
    private Button btnRefresh;

    @FXML
    private Label lblStatus;

    @FXML
    private TableColumn<Supplier, String> colContactPerson;

    @FXML
    private TableColumn<Supplier, String> colSupplierEmail;

    @FXML
    private TableColumn<Supplier, Integer> colSupplierId;

    @FXML
    private TableColumn<Supplier, String> colSupplierName;

    @FXML
    private TableColumn<Supplier, String> colSupplierPhone;

    @FXML
    private TableView<Supplier> tvSuppliers;

    @FXML
    private TextField txtSearch;

    private ObservableList<Supplier> data = FXCollections.observableArrayList();
    private String mode = null;

    /**
     * Set up the table view for suppliers and display it when starting up
     */
    @FXML
    void initialize(){
        //Disable buttons until a row is selected
        btnEdit.setDisable(true);
        btnDelete.setDisable(true);
        //Enable multiple selection
        tvSuppliers.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE);
        //set columns for table view
        colSupplierId.setCellValueFactory(new PropertyValueFactory<Supplier, Integer>("supId"));
        colSupplierName.setCellValueFactory(new PropertyValueFactory<Supplier, String>("supCompany"));
        colContactPerson.setCellValueFactory(new PropertyValueFactory<Supplier, String>("supFullName"));
        colSupplierEmail.setCellValueFactory(new PropertyValueFactory<Supplier, String>("supEmail"));
        colSupplierPhone.setCellValueFactory(new PropertyValueFactory<Supplier, String>("supPhone"));

        displaySupplier();
        TableViewSupport.installDoubleClickAction(tvSuppliers, selected -> openDialog(selected, "Edit"));

        //EventListener to Enable buttons when a row is selected
        tvSuppliers.getSelectionModel().selectedItemProperty().addListener(
                (observable, oldValue, newValue) -> {
                    boolean hasSelection = newValue != null;
                    btnEdit.setDisable(!hasSelection);
                    btnDelete.setDisable(!hasSelection);
                }
        );

        //EventListener to search when text is changed on searchbar
        txtSearch.textProperty().addListener((observable, oldValue, newValue) -> {
            displayFilteredSupplier(newValue);
        });

        //EventListener for DELETE key
        tvSuppliers.setOnKeyPressed(event -> {
            if (event.getCode() == javafx.scene.input.KeyCode.DELETE) {
                if (tvSuppliers.getSelectionModel().getSelectedItem() != null) {
                    btnDeleteClicked(null);
                }
            }
        });

    }

    /**
     * Display the suppliers to table view
     */
    private void displaySupplier(){
        new Thread(() -> {
            try {
                List<SupplierResponse> suppliers = SupplierApi.getInstance().listSuppliers(null);
                List<Supplier> supplierList = suppliers.stream()
                    .map(this::mapToSupplier)
                    .collect(Collectors.toList());

                Platform.runLater(() -> {
                    data.setAll(supplierList);
                    tvSuppliers.setItems(data);
                });
            } catch (Exception e) {
                Platform.runLater(() -> {
                    System.out.println("Error while fetching table data: " + e.getMessage());
                    ActivityLogger.getInstance().logException(
                        "SupplierController.displaySupplier",
                        e,
                        "Fetching supplier data for table display");
                });
            }
        }).start();
    }

    /**
     * Filter the table given the string from the searchbar
     * @param filter word to filter table
     */
    private void displayFilteredSupplier(String filter){
        if (txtSearch.getText() == null || txtSearch.getText().isEmpty()){
            displaySupplier();
        } else {
            new Thread(() -> {
                try {
                    List<SupplierResponse> suppliers = SupplierApi.getInstance().listSuppliers(filter);
                    List<Supplier> supplierList = suppliers.stream()
                        .map(this::mapToSupplier)
                        .collect(Collectors.toList());

                    Platform.runLater(() -> {
                        data.setAll(supplierList);
                        tvSuppliers.setItems(data);
                    });
                } catch (Exception e) {
                    Platform.runLater(() -> {
                        System.out.println("Error while fetching table data: " + e.getMessage());
                        ActivityLogger.getInstance().logException(
                            "SupplierController.displayFilteredSupplier",
                            e,
                            "Filtering suppliers with filter: " + filter);
                    });
                }
            }).start();
        }
    }


    /**
     * open a new dialog for adding a supplier
     * @param event click event for button
     */
    @FXML
    void btnRefresh(ActionEvent event) {
        txtSearch.clear();
        tvSuppliers.getSortOrder().clear();
        displaySupplier();
        TableViewSupport.flashStatus(lblStatus, "Refreshed");
    }

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

    /**
     * Delete selected supplier(s) when delete is clicked
     * @param event click event for button
     */
    @FXML
    void btnDeleteClicked(ActionEvent event) {
        //get selected suppliers
        var selectedSuppliers = tvSuppliers.getSelectionModel().getSelectedItems();
        if (selectedSuppliers.isEmpty()) return;

        //ask user to confirm
        Alert question = new Alert(Alert.AlertType.CONFIRMATION);
        question.setHeaderText("Please confirm delete");
        String message = selectedSuppliers.size() == 1
            ? "Are you sure you want to delete this supplier?"
            : "Are you sure you want to delete " + selectedSuppliers.size() + " suppliers?";
        question.setContentText(message);
        question.getDialogPane().lookupButton(ButtonType.OK).requestFocus();
        Optional<ButtonType> result = question.showAndWait();

        //if confirmed, start deletion
        if (result.isPresent() && result.get() == ButtonType.OK) {
            List<Long> ids = selectedSuppliers.stream()
                .map(s -> (long) s.getSupId())
                .collect(Collectors.toList());

            try {
                SupplierApi.getInstance().deleteSuppliers(ids);
                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setHeaderText("Database Operation Confirmed");
                alert.setContentText("Successfully deleted " + ids.size() + " supplier(s)");
                alert.showAndWait();
            } catch (Exception e) {
                ActivityLogger.getInstance().logException(
                    "SupplierController.btnDeleteClicked",
                    e,
                    "Deleting suppliers");
                Alert alert = new Alert(Alert.AlertType.ERROR);
                alert.setHeaderText("Delete Operation Failed");
                alert.setContentText(e.getMessage());
                alert.showAndWait();
            }

            //refresh display and reset inputs
            displaySupplier();
            btnDelete.setDisable(true);
            btnEdit.setDisable(true);
            txtSearch.setText("");
        }
    }

    /**
     * Open a new dialog for editing a supplier
     * @param event click event for button
     */
    @FXML
    void btnEditClicked(ActionEvent event) {
        //set selected supplier
        Supplier selectedSupplier = tvSuppliers.getSelectionModel().getSelectedItem();

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

    /**
     * Function to open the new Dialog for edit or adding
     * depending on the mode given
     * @param supplier the supplier entity for editing, null if adding
     * @param mode the mode the dialog should be in
     */
    private void openDialog(Supplier supplier, String mode){
        //Get new view
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/supplier-dialog-view.fxml"));
        Scene scene = null;
        try{
            scene = new Scene(fxmlLoader.load());
        } catch (IOException e) {
            ActivityLogger.getInstance().logException(
                "SupplierController.openDialog",
                e,
                "Loading supplier dialog in " + mode + " mode");
            throw new RuntimeException(e);
        }
        SupplierDialogController dialogController = fxmlLoader.getController(); //controller associated with this view
        dialogController.setMode(mode);

        //Open the dialog depending on the mode
        if(mode.equals("Edit")){
            //Make it display suppliers details in dialog
            dialogController.displaySupplierDetails(supplier);
        }
        Stage dialogStage = new Stage();
        dialogStage.initModality(Modality.APPLICATION_MODAL); //make it modal
        if(mode.equals("Add")){
            dialogStage.setTitle("Add Supplier");
        }
        else {
            dialogStage.setTitle("Edit Supplier");
        }
        dialogStage.setScene(scene);
        dialogStage.showAndWait();

        //When dialog closes update table view and disable edit and delete buttons, and reset search bar
        displaySupplier();
        btnDelete.setDisable(true);
        btnEdit.setDisable(true);
        txtSearch.setText("");
    }

    private Supplier mapToSupplier(SupplierResponse response) {
        String firstName = response.getSupContactFirstName() != null ? response.getSupContactFirstName().trim() : "";
        String lastName = response.getSupContactLastName() != null ? response.getSupContactLastName().trim() : "";
        String contactPerson = (firstName + " " + lastName).trim();
        String[] nameParts = contactPerson.split(" ", 2);
        String mappedFirstName = nameParts.length > 0 ? nameParts[0] : "";
        String mappedLastName = nameParts.length > 1 ? nameParts[1] : "";

        return new Supplier(
            response.getSupId().intValue(),
            response.getSupCompany(),
            mappedFirstName,
            mappedLastName,
            response.getSupEmail(),
            response.getSupPhone()
        );
    }

}
