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.auth.UserSession;
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;
import java.util.Objects;
import java.util.Optional;
import java.util.stream.Collectors;

public class PetDialogController {

    private static final String STATUS_AVAILABLE = "Available";
    private static final String STATUS_ADOPTED = "Adopted";
    private static final String STATUS_OWNED = "Owned";
    private static final String STATUS_PENDING = "Pending";

    @FXML private Button btnCancel;
    @FXML private Button btnSave;
    @FXML private Button btnChangeImage;
    @FXML private Button btnRemoveImage;
    @FXML private ComboBox<String> cbPetStatus;
    @FXML private ComboBox<String> cbPetSpecies;
    @FXML private ComboBox<String> cbPetBreed;
    @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 txtPetName;
    @FXML private TextField txtPetPrice;

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

    private Long pendingCustomerId = null;
    private Long pendingStoreId = null;
    private Long originalCustomerId = null;
    private boolean isOriginallyOwnedOrAdopted = false;
    private String pendingBreedValue = null;

    private final ObservableList<String> statusList = FXCollections.observableArrayList(
            STATUS_AVAILABLE, STATUS_ADOPTED, STATUS_OWNED, STATUS_PENDING
    );

    @FXML
    void initialize() {
        cbPetStatus.setItems(statusList);
        cbPetBreed.setDisable(true);

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

        applyStatusRules(STATUS_AVAILABLE, false);

        loadSpecies();
        loadCustomers();
        loadStores();

        cbPetSpecies.valueProperty().addListener((obs, oldVal, newVal) -> {
            if (newVal != null && !newVal.isBlank()) {
                if (!cbPetSpecies.isDisabled()) cbPetBreed.setDisable(false);
                loadBreeds(newVal);
            } else {
                cbPetBreed.setItems(FXCollections.observableArrayList());
                cbPetBreed.setValue(null);
                cbPetBreed.setPromptText("Select Species first");
                if (!cbPetSpecies.isDisabled()) cbPetBreed.setDisable(true);
            }
        });

        cbPetStatus.valueProperty().addListener((obs, oldVal, newVal) -> {
            if (newVal != null) applyStatusRules(newVal, true);
        });

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

    private void loadBreeds(String species) {
        cbPetBreed.setPromptText("Loading breeds...");
        new Thread(() -> {
            try {
                List<DropdownOption> options = DropdownApi.getInstance().getPetBreeds(species);
                List<String> breeds = options.stream().map(DropdownOption::getLabel).collect(Collectors.toList());
                Platform.runLater(() -> {
                    cbPetBreed.setItems(FXCollections.observableArrayList(breeds));
                    cbPetBreed.setPromptText("Select Breed");
                    if (pendingBreedValue != null) {
                        cbPetBreed.setValue(pendingBreedValue);
                        pendingBreedValue = null;
                    }
                });
            } catch (Exception e) {
                Platform.runLater(() -> {
                    ActivityLogger.getInstance().logException("PetDialogController.loadBreeds", e, "Loading breeds for species: " + species);
                    cbPetBreed.setPromptText("Unable to load breeds");
                });
            }
        }).start();
    }

    private void applyStatusRules(String status, boolean clearInvalidSelections) {
        if (STATUS_AVAILABLE.equalsIgnoreCase(status)) {
            vbCustomerField.setDisable(true);
            vbStoreField.setDisable(false);
            if (clearInvalidSelections) cbCustomer.setValue(null);
            return;
        }
        if (STATUS_OWNED.equalsIgnoreCase(status)) {
            vbCustomerField.setDisable(false);
            vbStoreField.setDisable(true);
            if (clearInvalidSelections) cbStore.setValue(null);
            return;
        }
        vbCustomerField.setDisable(false);
        vbStoreField.setDisable(false);
    }

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

        errorMsg += Validator.isPresent(txtPetName.getText(), "Pet Name");
        errorMsg += Validator.isPresent(txtPetAge.getText(), "Age");
        String speciesValue = cbPetSpecies.getValue() != null ? cbPetSpecies.getValue().trim() : "";
        if (speciesValue.isEmpty()) errorMsg += "Species is required\n";
        String breedValue = cbPetBreed.getValue() != null ? cbPetBreed.getValue().trim() : "";
        if (breedValue.isEmpty()) errorMsg += "Breed is required\n";
        if (cbPetStatus.getSelectionModel().getSelectedItem() == null) errorMsg += "Status is required\n";
        errorMsg += Validator.isPresent(txtPetPrice.getText(), "Price");

        String selectedStatus = cbPetStatus.getValue();
        if (STATUS_AVAILABLE.equalsIgnoreCase(selectedStatus) && cbStore.getValue() == null) {
            errorMsg += "Store is required for Available status\n";
        }
        if (STATUS_OWNED.equalsIgnoreCase(selectedStatus) && cbCustomer.getValue() == null) {
            errorMsg += "Customer is required for Owned status\n";
        }
        if (STATUS_ADOPTED.equalsIgnoreCase(selectedStatus)) {
            if (cbCustomer.getValue() == null) errorMsg += "Customer is required for Adopted status\n";
            if (cbStore.getValue() == null) errorMsg += "Store is required for Adopted status\n";
        }

        errorMsg += Validator.isLessThanVarChars(txtPetName.getText(), "Pet Name", 50);
        errorMsg += Validator.isLessThanVarChars(speciesValue, "Species", 50);
        errorMsg += Validator.isLessThanVarChars(breedValue, "Breed", 50);
        errorMsg += Validator.isLessThanVarChars(txtPetPrice.getText(), "Price", 12);
        errorMsg += Validator.isLessThanVarChars(txtPetAge.getText(), "Age", 11);
        errorMsg += Validator.isNonNegativeDouble(txtPetPrice.getText(), "Price");
        errorMsg += Validator.isPositiveInteger(txtPetAge.getText(), "Age");

        if (errorMsg.isEmpty()) {
            if ("Edit".equals(mode) && UserSession.getInstance().isAdmin()) {
                Long newCustomerId = cbCustomer.getValue() != null ? cbCustomer.getValue().getId() : null;
                if (!Objects.equals(originalCustomerId, newCustomerId)) {
                    Alert confirm = new Alert(Alert.AlertType.CONFIRMATION);
                    confirm.setHeaderText("Confirm Owner Change");
                    confirm.setContentText("Are you sure you want to reassign this pet to a different owner?");
                    Optional<ButtonType> result = confirm.showAndWait();
                    if (result.isEmpty() || result.get() != ButtonType.OK) return;
                }
            }
            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);
                }
                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(cbPetBreed.getValue() != null ? cbPetBreed.getValue().trim() : "");
        request.setPetStatus(cbPetStatus.getValue());

        if (txtPetPrice.getText() != null && !txtPetPrice.getText().isBlank()) {
            try {
                request.setPetPrice(new BigDecimal(txtPetPrice.getText()));
            } catch (NumberFormatException e) {
                throw new IllegalArgumentException("Invalid price format");
            }
        }

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

        if (cbCustomer.getValue() != null) request.setCustomerId(cbCustomer.getValue().getId());
        if (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(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) return;

        lblPetId.setText("ID: " + pet.getPetId());
        txtPetName.setText(pet.getPetName());
        txtPetAge.setText(String.valueOf(pet.getPetAge()));
        txtPetPrice.setText(String.valueOf(pet.getPetPrice()));
        currentImageUrl = pet.getImageUrl();
        selectedImageFile = null;
        removeImageRequested = false;
        refreshImagePreview();

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

        isOriginallyOwnedOrAdopted = STATUS_OWNED.equalsIgnoreCase(pet.getPetStatus())
                || STATUS_ADOPTED.equalsIgnoreCase(pet.getPetStatus());

        pendingBreedValue = pet.getPetBreed();
        cbPetSpecies.setValue(pet.getPetSpecies());

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

        applyStatusRules(cbPetStatus.getValue(), false);
        applyEditModeLock();
    }

    private void applyEditModeLock() {
        cbPetSpecies.setDisable(true);
        cbPetBreed.setDisable(true);

        boolean isStaff = !UserSession.getInstance().isAdmin();
        if (isStaff && isOriginallyOwnedOrAdopted) {
            cbPetStatus.setDisable(true);
            vbCustomerField.setDisable(true);
            vbStoreField.setDisable(true);
        }
    }

    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;
            cbPetSpecies.setDisable(false);
            cbPetBreed.setDisable(true);
            cbPetBreed.setItems(FXCollections.observableArrayList());
            cbPetBreed.setValue(null);
            cbPetBreed.setPromptText("Select Species first");
            cbPetStatus.setDisable(false);
            cbPetStatus.getSelectionModel().select(STATUS_AVAILABLE);
            applyStatusRules(STATUS_AVAILABLE, false);
            refreshImagePreview();
        } else if (mode.equals("Edit")) {
            lblPetId.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(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);
    }
}
