package org.example.petshopdesktop.controllers;

import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import org.example.petshopdesktop.DTOs.PurchaseOrderDTO;
import org.example.petshopdesktop.auth.UserSession;
import org.example.petshopdesktop.api.dto.purchaseorder.PurchaseOrderResponse;
import org.example.petshopdesktop.api.endpoints.PurchaseOrderApi;
import org.example.petshopdesktop.controllers.dialogcontrollers.PurchaseOrderDetailsDialogController;
import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;

import javafx.stage.Modality;
import javafx.stage.Stage;

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

public class PurchaseOrderController {

    @FXML private Button btnRefresh;

    @FXML private Label lblStatus;

    @FXML
    private TextField txtSearch;

    @FXML private TableView<PurchaseOrderDTO> tvPurchaseOrders;

    @FXML private TableColumn<PurchaseOrderDTO,Long> colOrderId;
    @FXML private TableColumn<PurchaseOrderDTO,String> colSupplier;
    @FXML private TableColumn<PurchaseOrderDTO,String> colOrderDate;
    @FXML private TableColumn<PurchaseOrderDTO,String> colStatus;
    @FXML private TableColumn<PurchaseOrderDTO,String> colStoreName;

    private final ObservableList<PurchaseOrderDTO> purchaseOrders = FXCollections.observableArrayList();
    private FilteredList<PurchaseOrderDTO> filtered;

    @FXML
    public void initialize() {

        colOrderId.setCellValueFactory(
                new PropertyValueFactory<>("purchaseOrderId"));

        colSupplier.setCellValueFactory(
                new PropertyValueFactory<>("supplierName"));

        colOrderDate.setCellValueFactory(
                new PropertyValueFactory<>("orderDate"));

        colStoreName.setCellValueFactory(new javafx.scene.control.cell.PropertyValueFactory<>("storeName"));
        colStatus.setCellValueFactory(
                new PropertyValueFactory<>("status"));

        filtered = new FilteredList<>(purchaseOrders, p -> true);
        TableViewSupport.bindSortedItems(tvPurchaseOrders, filtered);
        TableViewSupport.installDoubleClickAction(tvPurchaseOrders, this::openDetailsDialog);

        if (txtSearch != null) {
            txtSearch.textProperty().addListener((obs, o, n) -> applyFilter(n));
        }

        loadPurchaseOrders();
    }

    private void loadPurchaseOrders() {
        new Thread(() -> {
            try {
                Long storeId = UserSession.getInstance().isAdmin() ? null : UserSession.getInstance().getStoreId();
                List<PurchaseOrderResponse> responses = PurchaseOrderApi.getInstance().listPurchaseOrders(null, storeId);
                List<PurchaseOrderDTO> dtos = responses.stream()
                    .map(this::mapToPurchaseOrderDTO)
                    .sorted(Comparator.comparing(PurchaseOrderDTO::getOrderDate).reversed())
                    .collect(Collectors.toList());

                Platform.runLater(() -> {
                    purchaseOrders.setAll(dtos);
                });
            } catch (Exception e) {
                Platform.runLater(() -> {
                    ActivityLogger.getInstance().logException(
                        "PurchaseOrderController.loadPurchaseOrders",
                        e,
                        "Loading purchase orders for table display");
                    new Alert(Alert.AlertType.ERROR,
                            "Unable to load purchase orders").showAndWait();
                });
            }
        }).start();
    }

    private void applyFilter(String text) {
        if (filtered == null) {
            return;
        }

        String q = text == null ? "" : text.trim().toLowerCase();
        if (q.isEmpty()) {
            filtered.setPredicate(p -> true);
            return;
        }

        filtered.setPredicate(p ->
            String.valueOf(p.getPurchaseOrderId()).contains(q)
                || safe(p.getSupplierName()).contains(q)
                || safe(p.getOrderDate()).contains(q)
                || safe(p.getStatus()).contains(q)
        );
    }

    private static String safe(String v) {
        return v == null ? "" : v.toLowerCase();
    }

    @FXML
    void btnRefresh() {
        if (txtSearch != null) {
            txtSearch.clear();
        }
        TableViewSupport.clearSort(tvPurchaseOrders);
        loadPurchaseOrders();
        TableViewSupport.flashStatus(lblStatus, "Refreshed");
    }

    private void openDetailsDialog(PurchaseOrderDTO selected) {
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/purchase-order-details-dialog-view.fxml"));
            Stage dialog = new Stage();
            dialog.initModality(Modality.APPLICATION_MODAL);
            dialog.setTitle("Purchase Order Details");
            dialog.setScene(new Scene(loader.load()));
            PurchaseOrderDetailsDialogController controller = loader.getController();
            controller.displayPurchaseOrder(selected);
            controller.setCloseAction(() -> dialog.close());
            dialog.initOwner(tvPurchaseOrders.getScene().getWindow());
            dialog.setResizable(false);
            dialog.showAndWait();
        } catch (IOException e) {
            ActivityLogger.getInstance().logException(
                "PurchaseOrderController.openDetailsDialog",
                e,
                "Opening purchase order details");
            new Alert(Alert.AlertType.ERROR, "Unable to open purchase order details").showAndWait();
        }
    }

    private PurchaseOrderDTO mapToPurchaseOrderDTO(PurchaseOrderResponse response) {
        return new PurchaseOrderDTO(
            response.getPurchaseOrderId(),
            response.getSupplierName(),
            response.getOrderDate() != null ? response.getOrderDate().toString() : "",
            response.getOrderStatus(),
            response.getStoreName()
        );
    }
}
