package org.example.petshopdesktop.controllers;

import javafx.application.Platform;
import javafx.collections.FXCollections;
import javafx.collections.ObservableList;
import javafx.event.ActionEvent;
import javafx.fxml.FXML;
import javafx.fxml.FXMLLoader;
import javafx.scene.Scene;
import javafx.scene.control.*;
import javafx.scene.control.cell.PropertyValueFactory;
import javafx.stage.Modality;
import javafx.stage.Stage;
import org.example.petshopdesktop.api.dto.coupon.CouponResponse;
import org.example.petshopdesktop.api.endpoints.CouponApi;
import org.example.petshopdesktop.controllers.dialogcontrollers.CouponDialogController;
import org.example.petshopdesktop.util.ActivityLogger;
import org.example.petshopdesktop.util.TableViewSupport;

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

public class CouponController {

    @FXML private Button btnAdd;
    @FXML private Button btnEdit;
    @FXML private Button btnDelete;
    @FXML private Button btnRefresh;
    @FXML private Label lblStatus;
    @FXML private TextField txtSearch;
    @FXML private ComboBox<String> cbStatusFilter;
    @FXML private ComboBox<String> cbTypeFilter;
    @FXML private TableView<CouponResponse> tvCoupons;
    @FXML private TableColumn<CouponResponse, Long> colId;
    @FXML private TableColumn<CouponResponse, String> colCode;
    @FXML private TableColumn<CouponResponse, String> colDiscount;
    @FXML private TableColumn<CouponResponse, String> colMinOrder;
    @FXML private TableColumn<CouponResponse, String> colStatus;
    @FXML private TableColumn<CouponResponse, String> colStartsAt;
    @FXML private TableColumn<CouponResponse, String> colEndsAt;
    @FXML private TableColumn<CouponResponse, String> colUsageLimit;

    private final ObservableList<CouponResponse> allCoupons = FXCollections.observableArrayList();

    @FXML
    void initialize() {
        btnEdit.setDisable(true);
        btnDelete.setDisable(true);

        tvCoupons.getSelectionModel().setSelectionMode(SelectionMode.MULTIPLE);

        colId.setCellValueFactory(new PropertyValueFactory<>("couponId"));
        colCode.setCellValueFactory(new PropertyValueFactory<>("couponCode"));

        colDiscount.setCellValueFactory(data -> {
            CouponResponse c = data.getValue();
            String formatted = formatDiscount(c);
            return new javafx.beans.property.SimpleStringProperty(formatted);
        });

        colMinOrder.setCellValueFactory(data -> {
            BigDecimal min = data.getValue().getMinOrderAmount();
            return new javafx.beans.property.SimpleStringProperty(
                    min != null ? "$" + min.toPlainString() : "—");
        });

        colStatus.setCellValueFactory(data -> {
            Boolean active = data.getValue().getActive();
            return new javafx.beans.property.SimpleStringProperty(
                    Boolean.TRUE.equals(active) ? "Active" : "Inactive");
        });

        colStartsAt.setCellValueFactory(data ->
                new javafx.beans.property.SimpleStringProperty(formatDate(data.getValue().getStartsAt())));

        colEndsAt.setCellValueFactory(data ->
                new javafx.beans.property.SimpleStringProperty(formatDate(data.getValue().getEndsAt())));

        colUsageLimit.setCellValueFactory(data -> {
            Integer limit = data.getValue().getUsageLimit();
            return new javafx.beans.property.SimpleStringProperty(limit != null ? limit.toString() : "Unlimited");
        });

        cbStatusFilter.setItems(FXCollections.observableArrayList("All", "Active", "Inactive"));
        cbStatusFilter.setValue("All");
        cbTypeFilter.setItems(FXCollections.observableArrayList("All", "FIXED", "PERCENT"));
        cbTypeFilter.setValue("All");

        tvCoupons.getSelectionModel().selectedItemProperty().addListener((obs, oldVal, newVal) -> {
            boolean hasSelection = newVal != null;
            btnEdit.setDisable(!hasSelection);
            btnDelete.setDisable(!hasSelection);
        });

        txtSearch.textProperty().addListener((obs, oldVal, newVal) -> applyFilters());
        cbStatusFilter.valueProperty().addListener((obs, oldVal, newVal) -> applyFilters());
        cbTypeFilter.valueProperty().addListener((obs, oldVal, newVal) -> applyFilters());

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

        tvCoupons.setOnKeyPressed(event -> {
            if (event.getCode() == javafx.scene.input.KeyCode.DELETE
                    && tvCoupons.getSelectionModel().getSelectedItem() != null) {
                btnDeleteClicked(null);
            }
        });

        loadCoupons();
    }

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

    @FXML
    void btnEditClicked(ActionEvent event) {
        CouponResponse selected = tvCoupons.getSelectionModel().getSelectedItem();
        if (selected != null) {
            openDialog(selected, "Edit");
        }
    }

    @FXML
    void btnDeleteClicked(ActionEvent event) {
        List<CouponResponse> selected = tvCoupons.getSelectionModel().getSelectedItems();
        if (selected.isEmpty()) return;

        Alert question = new Alert(Alert.AlertType.CONFIRMATION);
        question.setHeaderText("Confirm Delete");
        question.setContentText(selected.size() == 1
                ? "Are you sure you want to delete this coupon?"
                : "Are you sure you want to delete " + selected.size() + " coupons?");
        question.getDialogPane().lookupButton(ButtonType.OK).requestFocus();
        Optional<ButtonType> result = question.showAndWait();

        if (result.isPresent() && result.get() == ButtonType.OK) {
            List<Long> ids = selected.stream().map(CouponResponse::getCouponId).collect(Collectors.toList());
            try {
                for (Long id : ids) {
                    CouponApi.getInstance().deleteCoupon(id);
                }
                Alert alert = new Alert(Alert.AlertType.INFORMATION);
                alert.setHeaderText("Deleted");
                alert.setContentText("Successfully deleted " + ids.size() + " coupon(s)");
                alert.showAndWait();
            } catch (Exception e) {
                ActivityLogger.getInstance().logException("CouponController.btnDeleteClicked", e, "Deleting coupons");
                Alert alert = new Alert(Alert.AlertType.ERROR);
                alert.setHeaderText("Delete Failed");
                alert.setContentText(e.getMessage());
                alert.showAndWait();
            }
            loadCoupons();
            btnEdit.setDisable(true);
            btnDelete.setDisable(true);
        }
    }

    @FXML
    void btnRefreshClicked(ActionEvent event) {
        txtSearch.clear();
        cbStatusFilter.setValue("All");
        cbTypeFilter.setValue("All");
        tvCoupons.getSortOrder().clear();
        loadCoupons();
        TableViewSupport.flashStatus(lblStatus, "Refreshed");
    }

    private void loadCoupons() {
        new Thread(() -> {
            try {
                List<CouponResponse> coupons = CouponApi.getInstance().listCoupons();
                Platform.runLater(() -> {
                    allCoupons.setAll(coupons != null ? coupons : java.util.Collections.emptyList());
                    applyFilters();
                });
            } catch (Exception e) {
                ActivityLogger.getInstance().logException("CouponController.loadCoupons", e, "Loading coupons");
                Platform.runLater(() -> {
                    lblStatus.setText("Failed to load coupons: " + e.getMessage());
                    lblStatus.setVisible(true);
                    lblStatus.setManaged(true);
                });
            }
        }).start();
    }

    private void applyFilters() {
        String search = txtSearch.getText() == null ? "" : txtSearch.getText().trim().toLowerCase();
        String status = cbStatusFilter.getValue();
        String type = cbTypeFilter.getValue();

        List<CouponResponse> filtered = allCoupons.stream()
                .filter(c -> search.isEmpty() || (c.getCouponCode() != null
                        && c.getCouponCode().toLowerCase().contains(search)))
                .filter(c -> "All".equals(status)
                        || ("Active".equals(status) && Boolean.TRUE.equals(c.getActive()))
                        || ("Inactive".equals(status) && !Boolean.TRUE.equals(c.getActive())))
                .filter(c -> "All".equals(type) || type.equals(c.getDiscountType()))
                .collect(Collectors.toList());

        tvCoupons.setItems(FXCollections.observableArrayList(filtered));
    }

    private void openDialog(CouponResponse coupon, String mode) {
        FXMLLoader loader = new FXMLLoader(getClass().getResource(
                "/org/example/petshopdesktop/dialogviews/coupon-dialog-view.fxml"));
        Scene scene;
        try {
            scene = new Scene(loader.load());
        } catch (IOException e) {
            ActivityLogger.getInstance().logException("CouponController.openDialog", e, "Loading coupon dialog");
            throw new RuntimeException(e);
        }
        CouponDialogController controller = loader.getController();
        controller.setMode(mode);
        if ("Edit".equals(mode)) {
            controller.displayCouponDetails(coupon);
        }
        Stage stage = new Stage();
        stage.initModality(Modality.APPLICATION_MODAL);
        stage.setTitle("Add".equals(mode) ? "Add Coupon" : "Edit Coupon");
        stage.setScene(scene);
        stage.showAndWait();
        loadCoupons();
        btnEdit.setDisable(true);
        btnDelete.setDisable(true);
    }

    private String formatDiscount(CouponResponse c) {
        if (c.getDiscountValue() == null) return "—";
        if ("PERCENT".equals(c.getDiscountType())) {
            return c.getDiscountValue().stripTrailingZeros().toPlainString() + "% OFF";
        }
        return "$" + c.getDiscountValue().toPlainString() + " OFF";
    }

    private String formatDate(String isoDate) {
        if (isoDate == null || isoDate.isBlank()) return "—";
        return isoDate.length() >= 10 ? isoDate.substring(0, 10) : isoDate;
    }
}
