package org.example.petshopdesktop.controllers.dialogcontrollers;

import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.EventHandler;
import javafx.fxml.FXML;
import javafx.scene.Node;
import javafx.scene.control.*;
import javafx.scene.image.ImageView;
import javafx.scene.input.MouseEvent;
import javafx.stage.Stage;
import org.example.petshopdesktop.DTOs.ProductDTO;
import org.example.petshopdesktop.Validator;
import org.example.petshopdesktop.api.dto.common.DropdownOption;
import org.example.petshopdesktop.api.dto.product.ProductRequest;
import org.example.petshopdesktop.api.dto.product.ProductResponse;
import org.example.petshopdesktop.api.endpoints.DropdownApi;
import org.example.petshopdesktop.api.endpoints.ProductApi;
import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.DesktopImageSupport;
import org.example.petshopdesktop.util.FilePickerSupport;

import java.io.File;
import java.math.BigDecimal;
import java.util.List;

public class ProductDialogController {

    @FXML
    private Button btnCancel;

    @FXML
    private Button btnSave;

    @FXML
    private Button btnChangeImage;

    @FXML
    private Button btnRemoveImage;

    @FXML
    private ComboBox<DropdownOption> cbProdCategory;

    @FXML
    private Label lblMode;

    @FXML
    private Label lblProdId;

    @FXML
    private Label lblImageStatus;

    @FXML
    private ImageView imgProductPreview;

    @FXML
    private TextField txtProdDesc;

    @FXML
    private TextField txtProdName;

    @FXML
    private TextField txtProdPrice;

    private String mode = null;
    private File selectedImageFile;
    private String currentImageUrl;
    private boolean removeImageRequested;

    /**
     * Add event listeners to buttons when dialog loads
     */
    @FXML
    void initialize() {
        //Set up mouse handlers for buttons
        btnSave.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                buttonSaveClicked(mouseEvent);
            }
        });

        btnCancel.setOnMouseClicked(new EventHandler<MouseEvent>() {
            @Override
            public void handle(MouseEvent mouseEvent) {
                closeStage(mouseEvent);
            }
        });

        //Set up combobox for selecting category
        try {
            List<DropdownOption> categories = DropdownApi.getInstance().getProductCategories();
            if (categories != null) {
                ObservableList<DropdownOption> categoriesObs = FXCollections.observableArrayList(categories);
                cbProdCategory.setItems(categoriesObs);
            }
        } catch (Exception e) {
            ActivityLogger.getInstance().logException(
                "ProductDialogController.initialize",
                e,
                "Loading categories for combo box");
            System.out.println("Error loading categories: " + e.getMessage());
        }

        btnChangeImage.setOnMouseClicked(mouseEvent -> handleChangeImage());
        btnRemoveImage.setOnMouseClicked(mouseEvent -> handleRemoveImage());
        refreshImagePreview();

    }

    /**
     * Validates the inputs, then add or update the database depending
     * on the mode
     * @param mouseEvent click event for save button
     */
    private void buttonSaveClicked(MouseEvent mouseEvent) {
        int numRow = 0; //how many rows affected
        String errorMsg = ""; //error message for validation

        //Check Validation (input required)
        errorMsg += Validator.isPresent(txtProdName.getText(), "Product Name");
        errorMsg += Validator.isPresent(txtProdPrice.getText(), "Product Price");
        if (cbProdCategory.getSelectionModel().getSelectedItem() == null) {
            errorMsg += "Category is required \n";
        }

        //Check validation (length size)
        errorMsg += Validator.isLessThanVarChars(txtProdName.getText(), "Product Name", 100);
        errorMsg += Validator.isLessThanVarChars(txtProdDesc.getText(), "Description", 100);
        errorMsg += Validator.isLessThanVarChars(txtProdPrice.getText(), "Product Price", 12);

        //Check Validation (format)
        errorMsg += Validator.isPositiveDouble(txtProdPrice.getText(), "Product Price");

        if (errorMsg.isEmpty()) {
            try {
                ProductRequest request = new ProductRequest();
                request.setProdName(txtProdName.getText());
                BigDecimal price;
                try {
                    price = new BigDecimal(txtProdPrice.getText());
                } catch (NumberFormatException e) {
                    throw new IllegalArgumentException("Invalid price format");
                }
                request.setProdPrice(price);
                request.setCategoryId(cbProdCategory.getSelectionModel().getSelectedItem().getId());
                request.setProdDesc(txtProdDesc.getText());

                if (mode.equals("Add")) {
                    ProductResponse response = ProductApi.getInstance().createProduct(request);
                    applyImageChanges(response.getProdId());
                } else {
                    String[] parts = lblProdId.getText().split(": ");
                    if (parts.length < 2) {
                        throw new IllegalStateException("Invalid product ID format");
                    }
                    Long productId = Long.parseLong(parts[1]);
                    ProductApi.getInstance().updateProduct(productId, request);
                    applyImageChanges(productId);
                }

                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setHeaderText("Saved");
                alert.setContentText(mode + " succeeded");
                alert.showAndWait();
                closeStage(mouseEvent);
            } catch (Exception e) {
                ActivityLogger.getInstance().logException(
                    "ProductDialogController.buttonSaveClicked",
                    e,
                    mode + " product");
                Alert alert = new Alert(Alert.AlertType.ERROR);
                alert.setHeaderText("Database Operation Error");
                alert.setContentText(e.getMessage());
                alert.showAndWait();
            }
        }
        else{ //Display validation errors
            Alert alert = new Alert(Alert.AlertType.ERROR);
            alert.setHeaderText("Input Error");
            alert.setContentText(errorMsg);
            alert.showAndWait();
        }
    }

    /**
     * Display the product data in text fields and combobox
     * @param product the product entity containing data to display
     */
    public void displayProductDetails(ProductDTO product){
        if (product!=null){
            lblProdId.setText("ID: " + product.getProdId());
            txtProdName.setText(product.getProdName());
            txtProdDesc.setText(product.getProdDesc());
            txtProdPrice.setText(product.getProdPrice() + "");
            currentImageUrl = product.getImageUrl();
            selectedImageFile = null;
            removeImageRequested = false;
            refreshImagePreview();

            for (DropdownOption category : cbProdCategory.getItems()) {
                if(category.getLabel().equals(product.getCategoryName())){
                    cbProdCategory.getSelectionModel().select(category);
                    break;
                }
            }

        }
    }

    /**
     * Close the window
     * @param mouseEvent mouse event to close
     */
    private void closeStage(MouseEvent mouseEvent) {
        Node node = (Node) mouseEvent.getSource();
        Stage stage = (Stage) node.getScene().getWindow();
        stage.close();
    }

    /**
     * Set the mode of the dialog
     * @param mode the mode to for the dialog
     */
    public void setMode(String mode) {
        this.mode = mode;
        lblMode.setText(mode + " Product");
        if(mode.equals("Add")) {
            lblProdId.setVisible(false);
            currentImageUrl = null;
            selectedImageFile = null;
            removeImageRequested = false;
            refreshImagePreview();
        }
        else if(mode.equals("Edit")) {
            lblProdId.setVisible(true);
            refreshImagePreview();
        }
    }

    private void handleChangeImage() {
        File file = FilePickerSupport.pickImageFile(btnSave.getScene().getWindow());
        if (file == null) {
            return;
        }
        selectedImageFile = file;
        removeImageRequested = false;
        lblImageStatus.setText("Selected: " + file.getName());
        DesktopImageSupport.loadImageInto(imgProductPreview, file.toURI().toString(), 120, 120);
        btnRemoveImage.setDisable(false);
    }

    private void handleRemoveImage() {
        selectedImageFile = null;
        removeImageRequested = true;
        currentImageUrl = null;
        refreshImagePreview();
    }

    private void applyImageChanges(Long productId) throws Exception {
        String previousImageUrl = currentImageUrl;
        if (removeImageRequested) {
            try {
                ProductApi.getInstance().deleteProductImage(productId);
            } catch (Exception ignored) {
            }
        }
        if (selectedImageFile != null) {
            ProductApi.getInstance().uploadProductImage(productId, selectedImageFile.toPath());
            currentImageUrl = "/api/v1/products/" + productId + "/image";
        } else if (removeImageRequested) {
            currentImageUrl = null;
        }
        DesktopImageSupport.evict(previousImageUrl);
        DesktopImageSupport.evict(currentImageUrl);
        selectedImageFile = null;
        removeImageRequested = false;
        refreshImagePreview();
    }

    private void refreshImagePreview() {
        if (imgProductPreview == null || lblImageStatus == null || btnRemoveImage == null) {
            return;
        }
        imgProductPreview.setImage(null);
        if (selectedImageFile != null) {
            lblImageStatus.setText("Selected: " + selectedImageFile.getName());
            DesktopImageSupport.loadImageInto(imgProductPreview, selectedImageFile.toURI().toString(), 120, 120);
            btnRemoveImage.setDisable(false);
            return;
        }
        if (currentImageUrl != null && !currentImageUrl.isBlank()) {
            lblImageStatus.setText("Current image loaded");
            DesktopImageSupport.loadImageInto(imgProductPreview, currentImageUrl, 120, 120);
            btnRemoveImage.setDisable(false);
            return;
        }
        lblImageStatus.setText("No image selected");
        btnRemoveImage.setDisable(true);
    }

}
