package org.example.petshopdesktop.controllers;

import javafx.application.Platform;
import org.example.petshopdesktop.auth.UserSession;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
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.control.cell.PropertyValueFactory;
import javafx.scene.image.ImageView;
import javafx.scene.layout.StackPane;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.example.petshopdesktop.api.dto.pet.PetResponse;
import org.example.petshopdesktop.api.dto.common.DropdownOption;
import org.example.petshopdesktop.api.endpoints.DropdownApi;
import org.example.petshopdesktop.api.endpoints.PetApi;
import org.example.petshopdesktop.controllers.dialogcontrollers.PetDialogController;
import org.example.petshopdesktop.models.Pet;
import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.DesktopImageSupport;
import org.example.petshopdesktop.util.TableViewSupport;

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

public class PetController {

    @FXML
    private Button btnAdd;

    @FXML
    private Button btnDelete;

    @FXML
    private Button btnEdit;

    @FXML
    private Button btnRefresh;

    @FXML
    private Label lblStatus;

    @FXML
    private TableColumn<Pet, Integer> colPetAge;

    @FXML
    private TableColumn<Pet, String> colPetBreed;

    @FXML
    private TableColumn<Pet, Integer> colPetId;

    @FXML
    private TableColumn<Pet, String> colPetImage;

    @FXML
    private TableColumn<Pet, String> colPetName;

    @FXML
    private TableColumn<Pet, Double> colPetPrice;

    @FXML
    private TableColumn<Pet, String> colPetSpecies;

    @FXML
    private TableColumn<Pet, String> colPetStatus;

    @FXML
    private TableColumn<Pet, String> colCustomerName;

    @FXML
    private TableColumn<Pet, String> colStoreName;

    @FXML
    private TableView<Pet> tvPets;

    @FXML
    private ComboBox<String> cbSpeciesFilter;

    @FXML
    private ComboBox<String> cbStatusFilter;

    @FXML
    private ComboBox<DropdownOption> cbStoreFilter;

    private final java.util.ArrayList<DropdownOption> storeOptions = new java.util.ArrayList<>();

    @FXML
    private TextField txtSearch;

    @FXML
    void btnRefresh(ActionEvent event) {
        txtSearch.clear();
        if (cbSpeciesFilter != null) cbSpeciesFilter.getSelectionModel().selectFirst();
        if (cbStatusFilter != null) cbStatusFilter.getSelectionModel().selectFirst();
        cbStoreFilter.getSelectionModel().selectFirst();
        tvPets.getSortOrder().clear();
        displayPets();
        TableViewSupport.flashStatus(lblStatus, "Refreshed");
    }

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

    @FXML
    void btnDeleteClicked(ActionEvent event) {
        //get selected pets
        var selectedPets = tvPets.getSelectionModel().getSelectedItems();
        if (selectedPets.isEmpty()) return;

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

        //if confirmed, start deletion
        if (result.isPresent() && result.get() == ButtonType.OK) {
            List<Long> ids = selectedPets.stream()
                .map(p -> (long) p.getPetId())
                .collect(Collectors.toList());

            try {
                PetApi.getInstance().deletePets(ids);
                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setHeaderText("Database Operation Confirmed");
                alert.setContentText("Successfully deleted " + ids.size() + " pet(s)");
                alert.showAndWait();
            } catch (Exception e) {
                ActivityLogger.getInstance().logException(
                    "PetController.btnDeleteClicked",
                    e,
                    "Deleting pets");
                Alert alert = new Alert(Alert.AlertType.ERROR);
                alert.setHeaderText("Delete Operation Failed");
                alert.setContentText(e.getMessage());
                alert.showAndWait();
            }

            //refresh display and reset inputs
            displayPets();
            btnDelete.setDisable(true);
            btnEdit.setDisable(true);
            txtSearch.setText("");
        }
    }

    @FXML
    void btnEditClicked(ActionEvent event) {
        Pet selectedPet = tvPets.getSelectionModel().getSelectedItem();

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

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

    @FXML
    void initialize() {
        btnEdit.setDisable(true);
        btnDelete.setDisable(true);
        //Enable multiple selection
        tvPets.getSelectionModel().setSelectionMode(javafx.scene.control.SelectionMode.MULTIPLE);

        colPetId.setCellValueFactory(new PropertyValueFactory<Pet,Integer>("petId"));
        colPetImage.setCellValueFactory(new PropertyValueFactory<Pet, String>("imageUrl"));
        colPetName.setCellValueFactory(new PropertyValueFactory<Pet,String>("petName"));
        colPetSpecies.setCellValueFactory(new PropertyValueFactory<Pet,String>("petSpecies"));
        colPetBreed.setCellValueFactory(new PropertyValueFactory<Pet,String>("petBreed"));
        colPetAge.setCellValueFactory(new PropertyValueFactory<Pet,Integer>("petAge"));
        colPetStatus.setCellValueFactory(new PropertyValueFactory<Pet,String>("petStatus"));
        colPetPrice.setCellValueFactory(new PropertyValueFactory<Pet,Double>("petPrice"));
        TableViewSupport.applyCurrencyColumn(colPetPrice);
        colCustomerName.setCellValueFactory(new PropertyValueFactory<Pet,String>("customerName"));
        colStoreName.setCellValueFactory(new PropertyValueFactory<Pet,String>("storeName"));
        configureImageColumn(colPetImage);

        loadSpeciesFilter();

        cbStatusFilter.setItems(FXCollections.observableArrayList("All Statuses", "Available", "Adopted", "Owned", "Pending"));
        cbStatusFilter.getSelectionModel().selectFirst();

        if (UserSession.getInstance().isAdmin()) {
            cbStoreFilter.setVisible(true);
            cbStoreFilter.setManaged(true);
            loadStoreFilter();
        }
        cbStoreFilter.valueProperty().addListener((obs, o, n) -> applyFilters());

        displayPets();
        TableViewSupport.installDoubleClickAction(tvPets, selected -> openDialog(selected, "Edit"));

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

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

        cbSpeciesFilter.valueProperty().addListener((observable, oldValue, newValue) -> applyFilters());
        cbStatusFilter.valueProperty().addListener((observable, oldValue, newValue) -> applyFilters());

        //EventListener for DELETE key
        tvPets.setOnKeyPressed(event -> {
            if (event.getCode() == javafx.scene.input.KeyCode.DELETE) {
                if (tvPets.getSelectionModel().getSelectedItem() != null) {
                    btnDeleteClicked(null);
                }
            }
        });
    }

    private void displayFilteredPet(String filter) {
        String species = selectedSpecies();
        String status = selectedStatus();
        if ((filter == null || filter.isEmpty()) && species == null && status == null){
            displayPets();
        } else {
            new Thread(() -> {
                try {
                    Long storeId = selectedStoreId();
                    List<PetResponse> pets = PetApi.getInstance().listPets(filter, species, status, storeId);
                    List<Pet> petList = pets.stream()
                        .map(this::mapToPet)
                        .collect(Collectors.toList());

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

    private void displayPets() {
        new Thread(() -> {
            try {
                Long storeId = selectedStoreId();
                List<PetResponse> pets = PetApi.getInstance().listPets(null, selectedSpecies(), selectedStatus(), storeId);
                List<Pet> petList = pets.stream()
                    .map(this::mapToPet)
                    .collect(Collectors.toList());

                Platform.runLater(() -> {
                    data.setAll(petList);
                    tvPets.setItems(data);
                });
            } catch (Exception e) {
                Platform.runLater(() -> {
                    System.out.println("Error while fetching table data: " + e.getMessage());
                    ActivityLogger.getInstance().logException(
                        "PetController.displayPets",
                        e,
                        "Fetching pet data for table display");
                });
            }
        }).start();
    }

    private void applyFilters() {
        displayFilteredPet(txtSearch.getText());
    }

    private void loadStoreFilter() {
        new Thread(() -> {
            try {
                List<DropdownOption> stores = DropdownApi.getInstance().getStores();
                DropdownOption allStores = new DropdownOption();
                allStores.setLabel("All Stores");
                Platform.runLater(() -> {
                    storeOptions.clear();
                    storeOptions.addAll(stores);
                    java.util.List<DropdownOption> items = new java.util.ArrayList<>();
                    items.add(allStores);
                    items.addAll(stores);
                    cbStoreFilter.setItems(FXCollections.observableArrayList(items));
                    cbStoreFilter.getSelectionModel().selectFirst();
                });
            } catch (Exception e) {
                ActivityLogger.getInstance().logException("PetController.loadStoreFilter", e, "Loading store filter");
            }
        }).start();
    }

    private Long selectedStoreId() {
        if (!UserSession.getInstance().isAdmin()) return UserSession.getInstance().getStoreId();
        DropdownOption selected = cbStoreFilter.getValue();
        return (selected != null && selected.getId() != null) ? selected.getId() : null;
    }

    private void loadSpeciesFilter() {
        new Thread(() -> {
            try {
                List<String> values = DropdownApi.getInstance().getPetSpecies().stream()
                    .map(DropdownOption::getLabel)
                    .collect(Collectors.toList());
                values.add(0, "All Species");
                Platform.runLater(() -> {
                    cbSpeciesFilter.setItems(FXCollections.observableArrayList(values));
                    cbSpeciesFilter.getSelectionModel().selectFirst();
                });
            } catch (Exception e) {
                Platform.runLater(() -> ActivityLogger.getInstance().logException(
                    "PetController.loadSpeciesFilter",
                    e,
                    "Loading species filter options"));
            }
        }).start();
    }

    private String selectedSpecies() {
        String value = cbSpeciesFilter.getValue();
        return value == null || value.equals("All Species") ? null : value;
    }

    private String selectedStatus() {
        String value = cbStatusFilter.getValue();
        return value == null || value.equals("All Statuses") ? null : value;
    }

    private void openDialog(Pet pet, String mode){
        //Get new view
        FXMLLoader fxmlLoader = new FXMLLoader(getClass().getResource("/org/example/petshopdesktop/dialogviews/pet-dialog-view.fxml"));
        Scene scene = null;
        try{
            scene = new Scene(fxmlLoader.load());
        } catch (IOException e) {
            ActivityLogger.getInstance().logException(
                "PetController.openDialog",
                e,
                "Loading pet dialog in " + mode + " mode");
            throw new RuntimeException(e);
        }
        PetDialogController dialogController = fxmlLoader.getController(); //controller associated with this view
        dialogController.setMode(mode);

        //Open the dialog depending on the mode
        if(mode.equals("Edit")){
            //Make it display pet details in dialog
            dialogController.displayPetDetails(pet);
        }
        Stage dialogStage = new Stage();
        dialogStage.initModality(Modality.APPLICATION_MODAL); //make it modal
        if(mode.equals("Add")){
            dialogStage.setTitle("Add Pet");
        }
        else {
            dialogStage.setTitle("Edit Pet");
        }
        dialogStage.setScene(scene);
        dialogStage.showAndWait();

        //When dialog closes update table view and disable edit and delete buttons, and reset search bar
        displayPets();
        btnDelete.setDisable(true);
        btnEdit.setDisable(true);
        txtSearch.setText("");
    }

    private Pet mapToPet(PetResponse response) {
        Pet pet = new Pet(
            response.getPetId().intValue(),
            response.getPetName() != null ? response.getPetName() : "",
            response.getPetSpecies() != null ? response.getPetSpecies() : "",
            response.getPetBreed() != null ? response.getPetBreed() : "",
            response.getPetAge() != null ? response.getPetAge() : 0,
            response.getPetStatus() != null ? response.getPetStatus() : "",
            response.getPetPrice() != null ? response.getPetPrice().doubleValue() : 0.0,
            response.getImageUrl()
        );
        pet.setCustomerName(response.getCustomerName());
        pet.setStoreName(response.getStoreName());
        pet.setCustomerId(response.getCustomerId() != null ? response.getCustomerId() : 0L);
        pet.setStoreId(response.getStoreId() != null ? response.getStoreId() : 0L);
        return pet;
    }

    private void configureImageColumn(TableColumn<Pet, 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);
            }
        });
    }

}
