package org.example.petshopdesktop.controllers;

import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.collections.transformation.FilteredList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.geometry.Pos;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.example.petshopdesktop.api.dto.user.UserResponse;
import org.example.petshopdesktop.api.endpoints.CustomerApi;
import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.DesktopImageSupport;
import org.example.petshopdesktop.util.TableViewSupport;

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

public class CustomerAccountsController {

    @FXML
    private TableView<UserResponse> tvCustomers;

    @FXML
    private TableColumn<UserResponse, String> colCustomerAvatar;

    @FXML
    private TableColumn<UserResponse, String> colCustomerUsername;

    @FXML
    private TableColumn<UserResponse, String> colCustomerName;

    @FXML
    private TableColumn<UserResponse, String> colCustomerEmail;

    @FXML
    private TableColumn<UserResponse, String> colCustomerPhone;

    @FXML
    private TableColumn<UserResponse, Object> colCustomerLoyaltyPoints;

    @FXML
    private TableColumn<UserResponse, String> colCustomerStatus;

    @FXML
    private TableColumn<UserResponse, Object> colCustomerCreated;

    @FXML
    private TextField txtSearchCustomer;

    @FXML
    private ComboBox<String> cbStatusFilter;

    @FXML
    private Button btnEditCustomer;

    @FXML
    private Button btnRefresh;

    @FXML
    private Label lblError;

    @FXML
    private Label lblStatus;

    private final ObservableList<UserResponse> customerAccounts = FXCollections.observableArrayList();
    private FilteredList<UserResponse> filteredCustomers;

    @FXML
    public void initialize() {
        colCustomerAvatar.setCellValueFactory(data -> {
            Long id = data.getValue().getId();
            if (id == null) return new javafx.beans.property.SimpleStringProperty("");
            return new javafx.beans.property.SimpleStringProperty("/api/v1/users/" + id + "/avatar/file");
        });
        configureAvatarColumn(colCustomerAvatar);

        colCustomerUsername.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getUsername()));
        colCustomerName.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getFullName()));
        colCustomerEmail.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getEmail()));
        colCustomerPhone.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getPhone()));
        colCustomerLoyaltyPoints.setCellValueFactory(data -> new javafx.beans.property.SimpleObjectProperty<>(data.getValue().getLoyaltyPoints()));
        colCustomerStatus.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getActive() != null && data.getValue().getActive() ? "Active" : "Inactive"));
        colCustomerCreated.setCellValueFactory(data -> new javafx.beans.property.SimpleObjectProperty<>(data.getValue().getCreatedAt()));

        filteredCustomers = new FilteredList<>(customerAccounts, a -> true);
        TableViewSupport.bindSortedItems(tvCustomers, filteredCustomers);
        TableViewSupport.installDoubleClickAction(tvCustomers, this::openEditDialog);

        tvCustomers.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal) ->
                btnEditCustomer.setDisable(newVal == null));
        btnEditCustomer.setDisable(true);

        cbStatusFilter.setItems(FXCollections.observableArrayList("All Statuses", "Active", "Inactive"));
        cbStatusFilter.getSelectionModel().selectFirst();
        cbStatusFilter.valueProperty().addListener((obs, o, n) -> applyCustomerFilter(txtSearchCustomer.getText()));

        txtSearchCustomer.textProperty().addListener((obs, o, n) -> applyCustomerFilter(n));

        refresh();
    }

    private void configureAvatarColumn(TableColumn<UserResponse, String> column) {
        column.setCellFactory(col -> new TableCell<>() {
            private final ImageView imageView = new ImageView();
            private final StackPane container = new StackPane(imageView);
            {
                container.setAlignment(Pos.CENTER);
            }

            @Override
            protected void updateItem(String item, boolean empty) {
                super.updateItem(item, empty);
                if (empty || item == null || item.isBlank()) {
                    setGraphic(null);
                    return;
                }
                DesktopImageSupport.loadImageInto(imageView, item, 48, 48);
                setGraphic(container);
            }
        });
    }

    @FXML
    void btnRefreshClicked(ActionEvent event) {
        txtSearchCustomer.clear();
        cbStatusFilter.getSelectionModel().selectFirst();
        TableViewSupport.clearSort(tvCustomers);
        refresh();
        TableViewSupport.flashStatus(lblStatus, "Refreshed");
    }

    @FXML
    void btnEditCustomerClicked(ActionEvent event) {
        lblError.setText("");
        openEditDialog(tvCustomers.getSelectionModel().getSelectedItem());
    }

    private void openEditDialog(UserResponse selected) {
        if (selected == null) {
            lblError.setText("Select a customer to edit.");
            return;
        }

        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/customer-edit-dialog-view.fxml"));
            Stage dialog = new Stage();
            dialog.initOwner(tvCustomers.getScene().getWindow());
            dialog.initModality(Modality.APPLICATION_MODAL);
            dialog.setTitle("Edit Customer Account");
            dialog.setScene(new Scene(loader.load()));
            dialog.setResizable(false);
            var controller = (org.example.petshopdesktop.controllers.dialogcontrollers.CustomerEditDialogController) loader.getController();
            controller.setCustomer(selected);
            dialog.showAndWait();
            refresh();
        } catch (Exception e) {
            ActivityLogger.getInstance().logException("CustomerAccountsController.openEditDialog", e, "Opening customer edit dialog");
            lblError.setText("Could not open customer account editor.");
        }
    }

    private void refresh() {
        lblError.setText("");
        tvCustomers.setDisable(true);

        new Thread(() -> {
            try {
                Comparator<UserResponse> byCreated = Comparator.comparing(
                        UserResponse::getCreatedAt, Comparator.nullsLast(Comparator.reverseOrder()));

                List<UserResponse> customers = CustomerApi.getInstance().listCustomers(null).stream()
                        .sorted(byCreated)
                        .collect(Collectors.toList());

                Platform.runLater(() -> {
                    customerAccounts.setAll(customers);
                    tvCustomers.setDisable(false);
                });
            } catch (Exception e) {
                ActivityLogger.getInstance().logException("CustomerAccountsController.refresh", e, "Loading customer accounts");
                Platform.runLater(() -> {
                    lblError.setText("Could not load customer accounts.");
                    tvCustomers.setDisable(false);
                });
            }
        }).start();
    }

    private void applyCustomerFilter(String text) {
        String q = text == null ? "" : text.trim().toLowerCase();
        String selectedStatus = cbStatusFilter.getValue();
        filteredCustomers.setPredicate(a -> {
            boolean textMatch = q.isEmpty()
                || safe(a.getUsername()).contains(q)
                || safe(a.getFullName()).contains(q)
                || safe(a.getEmail()).contains(q)
                || safe(a.getPhone()).contains(q);
            boolean active = Boolean.TRUE.equals(a.getActive());
            boolean statusMatch = selectedStatus == null || selectedStatus.equals("All Statuses")
                || (selectedStatus.equals("Active") && active)
                || (selectedStatus.equals("Inactive") && !active);
            return textMatch && statusMatch;
        });
    }

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