package org.example.petshopdesktop.controllers.dialogcontrollers;

import javafx.application.Platform;
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.scene.layout.VBox;
import javafx.stage.Stage;
import org.example.petshopdesktop.Validator;
import org.example.petshopdesktop.api.dto.common.DropdownOption;
import org.example.petshopdesktop.api.dto.pet.PetRequest;
import org.example.petshopdesktop.api.dto.pet.PetResponse;
import org.example.petshopdesktop.api.endpoints.DropdownApi;
import org.example.petshopdesktop.api.endpoints.PetApi;
import org.example.petshopdesktop.models.Pet;
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 PetDialogController {

    @FXML
    private Button btnCancel;

    @FXML
    private Button btnSave;

    @FXML
    private Button btnChangeImage;

    @FXML
    private Button btnRemoveImage;

    @FXML
    private ComboBox<String> cbPetStatus;

    @FXML
    private ComboBox<DropdownOption> cbCustomer;

    @FXML
    private ComboBox<DropdownOption> cbStore;

    @FXML
    private VBox vbCustomerField;

    @FXML
    private VBox vbStoreField;

    @FXML
    private VBox vbPriceField;

    @FXML
    private Label lblMode;

    @FXML
    private Label lblPetId;

    @FXML
    private Label lblImageStatus;

    @FXML
    private ImageView imgPetPreview;

    @FXML
    private TextField txtPetAge;

    @FXML
    private TextField txtPetBreed;

    @FXML
    private TextField txtPetName;

    @FXML
    private TextField txtPetPrice;

    @FXML
    private ComboBox<String> cbPetSpecies;

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

    private Long pendingCustomerId = null;
    private Long pendingStoreId = null;

    private ObservableList<String> statusList =  FXCollections.observableArrayList(
            "Available", "Adopted", "Owned", "Pending"
    );

    @FXML
    void initialize() {

        cbPetStatus.setItems(statusList);

        cbCustomer.setCellFactory(param -> new ListCell<>() {
            @Override protected void updateItem(DropdownOption o, boolean empty) {
                super.updateItem(o, empty);
                setText(empty || o == null ? null : o.getLabel());
            }
        });
        cbCustomer.setButtonCell(new ListCell<>() {
            @Override protected void updateItem(DropdownOption o, boolean empty) {
                super.updateItem(o, empty);
                setText(empty || o == null ? null : o.getLabel());
            }
        });

        cbStore.setCellFactory(param -> new ListCell<>() {
            @Override protected void updateItem(DropdownOption o, boolean empty) {
                super.updateItem(o, empty);
                setText(empty || o == null ? null : o.getLabel());
            }
        });
        cbStore.setButtonCell(new ListCell<>() {
            @Override protected void updateItem(DropdownOption o, boolean empty) {
                super.updateItem(o, empty);
                setText(empty || o == null ? null : o.getLabel());
            }
        });

        setFieldVisibility(vbCustomerField, false);
        setFieldVisibility(vbStoreField, false);
        setFieldVisibility(vbPriceField, true);

        loadSpecies();

        cbPetStatus.valueProperty().addListener((obs, oldVal, newVal) -> {
            updateStatusFieldVisibility(newVal);
        });

        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);
            }
        });

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

        loadCustomers();
        loadStores();
    }

    private void buttonSaveClicked(MouseEvent mouseEvent) {
        String errorMsg = "";

        //Check validation (input required)
        errorMsg += Validator.isPresent(txtPetName.getText(), "Pet Name");
        errorMsg += Validator.isPresent(txtPetAge.getText(), "Age");
        errorMsg += Validator.isPresent(txtPetBreed.getText(), "Breed");
        String speciesValue = cbPetSpecies.getValue() != null ? cbPetSpecies.getValue().trim() : "";
        if (speciesValue.isEmpty()) errorMsg += "Species is required\n";
        String selectedStatus = cbPetStatus.getValue();
        boolean needsPrice = !("Owned".equalsIgnoreCase(selectedStatus) || "Adopted".equalsIgnoreCase(selectedStatus));
        if (needsPrice) {
            errorMsg += Validator.isPresent(txtPetPrice.getText(), "Price");
        }
        if (cbPetStatus.getSelectionModel().getSelectedItem() == null){
            errorMsg += "Status is required";
        }
        if ("Owned".equalsIgnoreCase(selectedStatus) && cbCustomer.getValue() == null) {
            errorMsg += "Customer is required for Owned status\n";
        }
        boolean storeRequired = requiresStore(selectedStatus) && !"Adopted".equalsIgnoreCase(selectedStatus);
        if (storeRequired && cbStore.getValue() == null) {
            errorMsg += "Store is required for " + selectedStatus + " status\n";
        }

        //Check validation (length size)
        errorMsg += Validator.isLessThanVarChars(txtPetName.getText(), "Pet Name", 50);
        errorMsg += Validator.isLessThanVarChars(speciesValue, "Species", 50);
        errorMsg += Validator.isLessThanVarChars(txtPetBreed.getText(), "Breed", 50);
        if (needsPrice) {
            errorMsg += Validator.isLessThanVarChars(txtPetPrice.getText(), "Price", 12);
        }
        errorMsg += Validator.isLessThanVarChars(txtPetAge.getText(), "Age", 11);

        //Check validation (format)
        if (needsPrice) {
            errorMsg += Validator.isNonNegativeDouble(txtPetPrice.getText(), "Price");
        }
        errorMsg += Validator.isPositiveInteger(txtPetAge.getText(), "Age");

        if(errorMsg.isEmpty()){
            PetRequest request = buildPetRequest();
            try {
                if(mode.equals("Add")) {
                    PetResponse response = PetApi.getInstance().createPet(request);
                    applyImageChanges(response.getPetId());
                } else {
                    String[] parts = lblPetId.getText().split(": ");
                    if (parts.length < 2) {
                        throw new IllegalStateException("Invalid pet ID format");
                    }
                    Long petId = Long.parseLong(parts[1]);
                    PetApi.getInstance().updatePet(petId, request);
                    applyImageChanges(petId);
                }

                //tell the user operation was successful
                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setHeaderText("Saved");
                alert.setContentText(mode + " succeeded");
                alert.showAndWait();
                closeStage(mouseEvent);
            } catch (Exception e) {
                ActivityLogger.getInstance().logException(
                    "PetDialogController.buttonSaveClicked",
                    e,
                    mode + " pet record");
                Alert alert = new Alert(Alert.AlertType.ERROR);
                alert.setHeaderText("Operation Error");
                alert.setContentText(mode + " failed: " + e.getMessage());
                alert.showAndWait();
            }
        }
        else{
            Alert alert = new Alert(Alert.AlertType.ERROR);
            alert.setHeaderText("Input Error");
            alert.setContentText(errorMsg);
            alert.showAndWait();
        }
    }

    private PetRequest buildPetRequest() {
        PetRequest request = new PetRequest();
        request.setPetName(txtPetName.getText());
        request.setPetSpecies(cbPetSpecies.getValue() != null ? cbPetSpecies.getValue().trim() : "");
        request.setPetBreed(txtPetBreed.getText());
        request.setPetStatus(cbPetStatus.getValue());
        String buildStatus = cbPetStatus.getValue();
        boolean buildNeedsPrice = !("Owned".equalsIgnoreCase(buildStatus) || "Adopted".equalsIgnoreCase(buildStatus));
        if (buildNeedsPrice && txtPetPrice.getText() != null && !txtPetPrice.getText().isBlank()) {
            try {
                request.setPetPrice(new BigDecimal(txtPetPrice.getText()));
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Invalid price format");
            }
        }

        int age;
        try {
            age = Integer.parseInt(txtPetAge.getText());
        } catch (NumberFormatException e) {
            throw new IllegalArgumentException("Invalid age format");
        }
        request.setPetAge(age);

        String status = cbPetStatus.getValue();
        if (("Owned".equalsIgnoreCase(status) || "Adopted".equalsIgnoreCase(status)) && cbCustomer.getValue() != null) {
            request.setCustomerId(cbCustomer.getValue().getId());
        }
        if (requiresStore(status) && cbStore.getValue() != null) {
            request.setStoreId(cbStore.getValue().getId());
        }

        return request;
    }

    private void loadSpecies() {
        new Thread(() -> {
            try {
                List<DropdownOption> options = DropdownApi.getInstance().getPetSpecies();
                List<String> species = options.stream()
                        .map(DropdownOption::getLabel)
                        .collect(java.util.stream.Collectors.toList());
                Platform.runLater(() -> {
                    String current = cbPetSpecies.getValue();
                    cbPetSpecies.setItems(FXCollections.observableArrayList(species));
                    if (current != null && !current.isBlank()) {
                        cbPetSpecies.setValue(current);
                    }
                });
            } catch (Exception e) {
                Platform.runLater(() -> ActivityLogger.getInstance().logException(
                        "PetDialogController.loadSpecies", e, "Loading species dropdown"));
            }
        }).start();
    }

    private void loadCustomers() {
        new Thread(() -> {
            try {
                List<DropdownOption> customers = DropdownApi.getInstance().getCustomers();
                Platform.runLater(() -> {
                    cbCustomer.setItems(FXCollections.observableArrayList(customers));
                    applySelectedCustomer();
                });
            } catch (Exception e) {
                Platform.runLater(() -> {
                    ActivityLogger.getInstance().logException(
                        "PetDialogController.loadCustomers", e, "Loading customers");
                    cbCustomer.setDisable(true);
                    cbCustomer.setPromptText("Unable to load customers");
                });
            }
        }).start();
    }

    private void loadStores() {
        new Thread(() -> {
            try {
                List<DropdownOption> stores = DropdownApi.getInstance().getStores();
                Platform.runLater(() -> {
                    cbStore.setItems(FXCollections.observableArrayList(stores));
                    applySelectedStore();
                });
            } catch (Exception e) {
                Platform.runLater(() -> {
                    ActivityLogger.getInstance().logException(
                        "PetDialogController.loadStores", e, "Loading stores");
                    cbStore.setDisable(true);
                    cbStore.setPromptText("Unable to load stores");
                });
            }
        }).start();
    }

    private void applySelectedCustomer() {
        if (pendingCustomerId == null) return;
        DropdownOption selected = findOptionById(cbCustomer.getItems(), pendingCustomerId);
        if (selected != null) {
            cbCustomer.setValue(selected);
            pendingCustomerId = null;
        }
    }

    private void applySelectedStore() {
        if (pendingStoreId == null) return;
        DropdownOption selected = findOptionById(cbStore.getItems(), pendingStoreId);
        if (selected != null) {
            cbStore.setValue(selected);
            pendingStoreId = null;
        }
    }

    private DropdownOption findOptionById(List<DropdownOption> options, Long id) {
        if (id == null || options == null) return null;
        for (DropdownOption option : options) {
            if (option.getId() != null && option.getId().equals(id)) return option;
        }
        return null;
    }

    private void closeStage(MouseEvent mouseEvent) {
        Node node = (Node) mouseEvent.getSource();
        Stage stage = (Stage) node.getScene().getWindow();
        stage.close();
    }

    public void displayPetDetails(Pet pet){
        if (pet!=null){
            lblPetId.setText("ID: " + pet.getPetId());
            txtPetName.setText(pet.getPetName());
            cbPetSpecies.setValue(pet.getPetSpecies());
            txtPetBreed.setText(pet.getPetBreed());
            txtPetAge.setText(pet.getPetAge() + "");
            txtPetPrice.setText(pet.getPetPrice() + "");
            currentImageUrl = pet.getImageUrl();
            selectedImageFile = null;
            removeImageRequested = false;
            refreshImagePreview();

            pendingCustomerId = pet.getCustomerId() > 0 ? pet.getCustomerId() : null;
            pendingStoreId = pet.getStoreId() > 0 ? pet.getStoreId() : null;

            for (String status : cbPetStatus.getItems()) {
                if(status.equals(pet.getPetStatus())){
                    cbPetStatus.getSelectionModel().select(status);
                    break;
                }
            }
            updateStatusFieldVisibility(cbPetStatus.getValue());
        }
    }

    public void setMode(String mode) {
        this.mode = mode;
        lblMode.setText(mode + " Pet");
        if(mode.equals("Add")) {
            lblPetId.setVisible(false);
            currentImageUrl = null;
            selectedImageFile = null;
            removeImageRequested = false;
            refreshImagePreview();
        }
        else if(mode.equals("Edit")) {
            lblPetId.setVisible(true);
            refreshImagePreview();
        }
        updateStatusFieldVisibility(cbPetStatus.getValue());
    }

    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(imgPetPreview, file.toURI().toString(), 120, 120);
        btnRemoveImage.setDisable(false);
    }

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

    private void applyImageChanges(Long petId) throws Exception {
        String previousImageUrl = currentImageUrl;
        if (removeImageRequested) {
            try {
                PetApi.getInstance().deletePetImage(petId);
            } catch (Exception ignored) {
            }
        }
        if (selectedImageFile != null) {
            PetApi.getInstance().uploadPetImage(petId, selectedImageFile.toPath());
            currentImageUrl = "/api/v1/pets/" + petId + "/image";
        } else if (removeImageRequested) {
            currentImageUrl = null;
        }
        DesktopImageSupport.evict(previousImageUrl);
        DesktopImageSupport.evict(currentImageUrl);
        selectedImageFile = null;
        removeImageRequested = false;
        refreshImagePreview();
    }

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

    private void updateStatusFieldVisibility(String status) {
        boolean needsCustomer = "Owned".equalsIgnoreCase(status) || "Adopted".equalsIgnoreCase(status);
        boolean storeBased = requiresStore(status);
        boolean needsPrice = !needsCustomer;
        setFieldVisibility(vbCustomerField, needsCustomer);
        setFieldVisibility(vbStoreField, storeBased);
        setFieldVisibility(vbPriceField, needsPrice);
    }

    private boolean requiresStore(String status) {
        return "Available".equalsIgnoreCase(status)
            || "Pending".equalsIgnoreCase(status)
            || "Unadopted".equalsIgnoreCase(status)
            || "Adopted".equalsIgnoreCase(status);
    }

    private void setFieldVisibility(VBox field, boolean visible) {
        if (field == null) {
            return;
        }
        field.setVisible(visible);
        field.setManaged(visible);
    }

}
