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.scene.layout.VBox;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.example.petshopdesktop.api.dto.employee.EmployeeResponse;
import org.example.petshopdesktop.api.endpoints.EmployeeApi;
import org.example.petshopdesktop.auth.UserSession;
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 StaffAccountsController {

    @FXML private VBox staffSection;
    @FXML private TableView<EmployeeResponse> tvStaff;
    @FXML private TableColumn<EmployeeResponse, String> colStaffAvatar;
    @FXML private TableColumn<EmployeeResponse, String> colUsername;
    @FXML private TableColumn<EmployeeResponse, String> colName;
    @FXML private TableColumn<EmployeeResponse, String> colEmail;
    @FXML private TableColumn<EmployeeResponse, String> colPhone;
    @FXML private TableColumn<EmployeeResponse, String> colRole;
    @FXML private TableColumn<EmployeeResponse, String> colStatus;
    @FXML private TableColumn<EmployeeResponse, Object> colCreated;
    @FXML private TextField txtSearch;
    @FXML private ComboBox<String> cbRoleFilter;
    @FXML private ComboBox<String> cbStatusFilter;
    @FXML private Button btnRefresh;
    @FXML private Button btnCreateAccount;
    @FXML private Button btnEditAccount;
    @FXML private Label lblError;
    @FXML private Label lblStatus;

    private final ObservableList<EmployeeResponse> staffAccounts = FXCollections.observableArrayList();
    private FilteredList<EmployeeResponse> filteredStaff;

    @FXML
    public void initialize() {
        colStaffAvatar.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(colStaffAvatar);

        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 -> {
            String role = data.getValue().getRole() != null ? data.getValue().getRole() : "";
            String staffRole = data.getValue().getStaffRole() != null ? " (" + data.getValue().getStaffRole() + ")" : "";
            return new javafx.beans.property.SimpleStringProperty(role + staffRole);
        });
        colStatus.setCellValueFactory(data -> new javafx.beans.property.SimpleStringProperty(
                Boolean.TRUE.equals(data.getValue().getActive()) ? "Active" : "Inactive"));
        colCreated.setCellValueFactory(data -> new javafx.beans.property.SimpleObjectProperty<>(data.getValue().getCreatedAt()));

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

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

        cbRoleFilter.setItems(FXCollections.observableArrayList("All Roles", "Admin", "Staff"));
        cbRoleFilter.getSelectionModel().selectFirst();
        cbRoleFilter.valueProperty().addListener((obs, o, n) -> applyStaffFilter(txtSearch.getText()));

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

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

        refresh();
    }

    private void configureAvatarColumn(TableColumn<EmployeeResponse, 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) {
        txtSearch.clear();
        cbRoleFilter.getSelectionModel().selectFirst();
        cbStatusFilter.getSelectionModel().selectFirst();
        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("");
        openEditDialog(tvStaff.getSelectionModel().getSelectedItem());
    }

    private void openEditDialog(EmployeeResponse 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 Staff Account");
            dialog.setScene(new Scene(loader.load()));
            dialog.setResizable(false);
            var controller = (org.example.petshopdesktop.controllers.dialogcontrollers.StaffEditDialogController) loader.getController();
            controller.setEmployee(selected);
            dialog.showAndWait();
            refresh();
        } catch (Exception e) {
            ActivityLogger.getInstance().logException("StaffAccountsController.openEditDialog", e, "Opening employee edit dialog");
            lblError.setText("Could not open employee account editor.");
        }
    }

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

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

                List<EmployeeResponse> staff = EmployeeApi.getInstance().listEmployees(null).stream()
                        .sorted(byCreated)
                        .collect(Collectors.toList());

                Platform.runLater(() -> {
                    staffAccounts.setAll(staff);
                    tvStaff.setDisable(false);
                });
            } catch (Exception e) {
                ActivityLogger.getInstance().logException("StaffAccountsController.refresh", e, "Loading employee accounts");
                Platform.runLater(() -> {
                    lblError.setText("Could not load staff accounts.");
                    tvStaff.setDisable(false);
                });
            }
        }).start();
    }

    private void applyStaffFilter(String text) {
        String q = text == null ? "" : text.trim().toLowerCase();
        String selectedRole = cbRoleFilter.getValue();
        String selectedStatus = cbStatusFilter.getValue();
        filteredStaff.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)
                || safe(a.getRole()).contains(q)
                || safe(a.getStaffRole()).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);
            boolean roleMatch = selectedRole == null || selectedRole.equals("All Roles")
                || safe(a.getRole()).equals(selectedRole.toLowerCase());
            return textMatch && statusMatch && roleMatch;
        });
    }

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