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.Stage;
import org.example.petshopdesktop.DTOs.ServiceDTO;
import org.example.petshopdesktop.api.dto.service.ServiceResponse;
import org.example.petshopdesktop.api.endpoints.ServiceApi;
import org.example.petshopdesktop.controllers.dialogcontrollers.ServiceDialogController;
import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;
import javafx.stage.Modality;

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


public class ServiceController {

    @FXML private Button btnAdd;
    @FXML private Button btnDelete;
    @FXML private Button btnEdit;
    @FXML private Button btnRefresh;

    @FXML private Label lblStatus;

    @FXML private TableColumn<ServiceDTO, Integer> colServiceId;
    @FXML private TableColumn<ServiceDTO, String> colServiceName;
    @FXML private TableColumn<ServiceDTO, String> colServiceDesc;
    @FXML private TableColumn<ServiceDTO, Integer> colServiceDuration;
    @FXML private TableColumn<ServiceDTO, Double> colServicePrice;

    @FXML private TableView<ServiceDTO> tvServices;

    @FXML private TextField txtSearch;

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

    @FXML
    public void initialize() {
        btnEdit.setDisable(true);
        btnDelete.setDisable(true);
        tvServices.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE);

        colServiceId.setCellValueFactory(new PropertyValueFactory<>("serviceId"));
        colServiceName.setCellValueFactory(new PropertyValueFactory<>("serviceName"));
        colServiceDesc.setCellValueFactory(new PropertyValueFactory<>("serviceDesc"));
        colServiceDuration.setCellValueFactory(new PropertyValueFactory<>("serviceDuration"));
        colServicePrice.setCellValueFactory(new PropertyValueFactory<>("servicePrice"));
        TableViewSupport.applyCurrencyColumn(colServicePrice);

        displayServices();
        TableViewSupport.installDoubleClickAction(tvServices, selected -> openDialog(selected, "Edit"));

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

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

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

    private void displayServices() {
        new Thread(() -> {
            try {
                List<ServiceResponse> services = ServiceApi.getInstance().listServices(null);
                List<ServiceDTO> serviceDTOs = services.stream()
                    .map(this::mapToServiceDTO)
                    .collect(Collectors.toList());

                Platform.runLater(() -> {
                    data.setAll(serviceDTOs);
                    tvServices.setItems(data);
                });
            } catch (Exception e) {
                Platform.runLater(() -> {
                    System.out.println("Error while fetching table data: " + e.getMessage());
                    ActivityLogger.getInstance().logException(
                        "ServiceController.displayServices",
                        e,
                        "Fetching service data for table display");
                });
            }
        }).start();
    }

    private void displayFilteredServices(String filter) {
        if (txtSearch.getText() == null || txtSearch.getText().isEmpty()) {
            displayServices();
        } else {
            new Thread(() -> {
                try {
                    List<ServiceResponse> services = ServiceApi.getInstance().listServices(filter);
                    List<ServiceDTO> serviceDTOs = services.stream()
                        .map(this::mapToServiceDTO)
                        .collect(Collectors.toList());

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


    @FXML
    void btnRefresh(ActionEvent event) {
        txtSearch.clear();
        tvServices.getSortOrder().clear();
        displayServices();
        TableViewSupport.flashStatus(lblStatus, "Refreshed");
    }

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

    @FXML
    void btnEditClicked(ActionEvent event) {
        ServiceDTO selected = tvServices.getSelectionModel().getSelectedItem();

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

    @FXML
    void btnDeleteClicked(ActionEvent event) {
        var selectedServices = tvServices.getSelectionModel().getSelectedItems();
        if (selectedServices.isEmpty()) return;

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

        if (result.isPresent() && result.get() == ButtonType.OK) {
            List<Long> ids = selectedServices.stream()
                .map(s -> (long) s.getServiceId())
                .collect(Collectors.toList());

            try {
                ServiceApi.getInstance().deleteServices(ids);
                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setHeaderText("Database Operation Confirmed");
                alert.setContentText("Successfully deleted " + ids.size() + " service(s)");
                alert.showAndWait();
            } catch (Exception e) {
                ActivityLogger.getInstance().logException(
                    "ServiceController.btnDeleteClicked",
                    e,
                    "Deleting services");
                Alert alert = new Alert(Alert.AlertType.ERROR);
                alert.setHeaderText("Delete Operation Failed");
                alert.setContentText(e.getMessage());
                alert.showAndWait();
            }

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

    private void openDialog(ServiceDTO service, String mode) {
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/service-dialog-view.fxml"));
        Scene scene = null;
        try {
            scene = new Scene(fxmlLoader.load());
        } catch (Exception e) {
            ActivityLogger.getInstance().logException(
                "ServiceController.openDialog",
                e,
                String.format("Loading service dialog view in %s mode", mode));
            throw new RuntimeException(e);
        }
        ServiceDialogController dialogController = fxmlLoader.getController();
        dialogController.setMode(mode);

        if (mode.equals("Edit")) {
            dialogController.setService(service);
        }
        Stage dialogStage = new Stage();
        dialogStage.initModality(Modality.APPLICATION_MODAL);
        if (mode.equals("Add")) {
            dialogStage.setTitle("Add Service");
        } else {
            dialogStage.setTitle("Edit Service");
        }
        dialogStage.setScene(scene);
        dialogStage.showAndWait();

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

    private ServiceDTO mapToServiceDTO(ServiceResponse response) {
        return new ServiceDTO(
            response.getServiceId().intValue(),
            response.getServiceName(),
            response.getServiceDesc(),
            response.getServiceDuration() != null ? response.getServiceDuration() : 0,
            response.getServicePrice().doubleValue()
        );
    }
}
