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.scene.Scene;
import javafx.scene.control.Button;
import javafx.scene.control.Label;
import javafx.scene.control.TableColumn;
import javafx.scene.control.TableView;
import javafx.scene.control.TextField;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.example.petshopdesktop.api.dto.user.UserResponse;
import org.example.petshopdesktop.api.endpoints.UserApi;
import org.example.petshopdesktop.api.endpoints.CustomerApi;
import org.example.petshopdesktop.auth.UserSession;
import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;

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

public class StaffAccountsController {

    @FXML
    private TableView<UserResponse> tvStaff;

    @FXML
    private TableColumn<UserResponse, String> colUsername;

    @FXML
    private TableColumn<UserResponse, String> colName;

    @FXML
    private TableColumn<UserResponse, String> colEmail;

    @FXML
    private TableColumn<UserResponse, String> colPhone;

    @FXML
    private TableColumn<UserResponse, String> colRole;

    @FXML
    private TableColumn<UserResponse, String> colStatus;

    @FXML
    private TableColumn<UserResponse, Object> colCreated;

    @FXML
    private TextField txtSearch;

    @FXML
    private Label lblError;

    @FXML
    private Label lblStatus;

    @FXML
    private Button btnRefresh;

    @FXML
    private Button btnCreateAccount;

    @FXML
    private Button btnEditAccount;

    private final ObservableList<UserResponse> staffAccounts = FXCollections.observableArrayList();
    private FilteredList<UserResponse> filtered;

    @FXML
    public void initialize() {
        colUsername.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getUsername()));
        colName.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getFullName()));
        colEmail.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getEmail()));
        colPhone.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getPhone()));
        colRole.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getRole()));
        colStatus.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(data.getValue().getActive() != null && data.getValue().getActive() ? "Active" : "Inactive"));
        colCreated.setCellValueFactory(data -> new javafx.beans.property.SimpleObjectProperty<>(data.getValue().getCreatedAt()));

        filtered = new FilteredList<>(staffAccounts, a -> true);
        TableViewSupport.bindSortedItems(tvStaff, filtered);
        TableViewSupport.installDoubleClickAction(tvStaff, this::openEditDialog);

        txtSearch.textProperty().addListener((obs, o, n) -> applyFilter(n));

        tvStaff.getSelectionModel().selectedItemProperty().addListener((obs, oldValue, newValue) -> {
            if (btnEditAccount != null) {
                btnEditAccount.setDisable(newValue == null);
            }
        });

        if (btnEditAccount != null) {
            btnEditAccount.setDisable(true);
        }

        refresh();
    }

    @FXML
    void btnRefreshClicked(ActionEvent event) {
        txtSearch.clear();
        TableViewSupport.clearSort(tvStaff);
        refresh();
        TableViewSupport.flashStatus(lblStatus, "Refreshed");
    }

    @FXML
    void btnCreateAccountClicked(ActionEvent event) {
        lblError.setText("");
        try {
            FXMLLoader loader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/staff-register-dialog-view.fxml"));
            Stage dialog = new Stage();
            dialog.initOwner(tvStaff.getScene().getWindow());
            dialog.initModality(Modality.APPLICATION_MODAL);
            dialog.setTitle("Create Staff Account");
            dialog.setScene(new Scene(loader.load()));
            dialog.setResizable(false);
            dialog.showAndWait();
            refresh();
        } catch (Exception e) {
            ActivityLogger.getInstance().logException("StaffAccountsController.btnCreateAccountClicked", e, "Opening staff register dialog");
            lblError.setText("Could not open staff account creation.");
        }
    }

    @FXML
    void btnEditAccountClicked(ActionEvent event) {
        lblError.setText("");
        UserResponse selected = tvStaff.getSelectionModel().getSelectedItem();
        openEditDialog(selected);
    }

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

        UserSession session = UserSession.getInstance();
        boolean isAdmin = session.isAdmin();
        boolean targetIsAdmin = "ADMIN".equalsIgnoreCase(selected.getRole());

        if (isAdmin && targetIsAdmin && !selected.getId().equals(session.getUserId())) {
            lblError.setText("Admins cannot edit other admin accounts.");
            return;
        }

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

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

        new Thread(() -> {
            try {
                UserSession session = UserSession.getInstance();
                List<UserResponse> users;
                if (session.isAdmin()) {
                    users = UserApi.getInstance().listUsers(null);
                } else {
                    users = CustomerApi.getInstance().listCustomers(null);
                }

                List<UserResponse> sortedUsers = users.stream()
                    .sorted(Comparator.comparing(UserResponse::getCreatedAt, Comparator.nullsLast(Comparator.reverseOrder())))
                    .collect(Collectors.toList());

                Platform.runLater(() -> {
                    staffAccounts.setAll(sortedUsers);
                    tvStaff.setDisable(false);
                });
            } catch (Exception e) {
                ActivityLogger.getInstance().logException("StaffAccountsController.refresh", e, "Loading user accounts");
                Platform.runLater(() -> {
                    String message = e.getMessage();
                    lblError.setText(message == null || message.isBlank()
                        ? "Could not load user accounts."
                        : "Could not load user accounts: " + message);
                    tvStaff.setDisable(false);
                });
            }
        }).start();
    }

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

        filtered.setPredicate(a ->
            safe(a.getUsername()).contains(q)
                || safe(a.getFullName()).contains(q)
                || safe(a.getEmail()).contains(q)
                || safe(a.getPhone()).contains(q)
                || safe(a.getRole()).contains(q)
        );
    }

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