package com.ecep.contract.controller.customer;

import java.awt.image.BufferedImage;
import java.io.File;
import java.util.Objects;
import java.util.concurrent.CompletableFuture;
import java.util.function.BiConsumer;

import org.apache.pdfbox.Loader;
import org.apache.pdfbox.pdmodel.PDDocument;
import org.apache.pdfbox.rendering.PDFRenderer;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.context.annotation.Lazy;
import org.springframework.context.annotation.Scope;
import org.springframework.stereotype.Component;
import org.springframework.util.StringUtils;

import com.ecep.contract.controller.BaseController;
import com.ecep.contract.model.CompanyCustomerEvaluationFormFile;
import com.ecep.contract.model.CompanyCustomerFile;
import com.ecep.contract.service.CompanyCustomerFileService;
import com.ecep.contract.util.FileUtils;
import com.ecep.contract.util.FxmlUtils;
import com.ecep.contract.vm.CompanyCustomerFileViewModel;

import javafx.application.Platform;
import javafx.beans.binding.Bindings;
import javafx.beans.property.SimpleIntegerProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import javafx.event.ActionEvent;
import javafx.geometry.Bounds;
import javafx.scene.control.CheckBox;
import javafx.scene.control.DatePicker;
import javafx.scene.control.Label;
import javafx.scene.control.ScrollPane;
import javafx.scene.control.SplitPane;
import javafx.scene.control.TextField;
import javafx.scene.control.Toggle;
import javafx.scene.control.ToggleGroup;
import javafx.scene.image.Image;
import javafx.scene.image.ImageView;
import javafx.scene.image.PixelWriter;
import javafx.scene.image.WritableImage;
import javafx.stage.Modality;
import javafx.stage.Stage;
import javafx.stage.Window;
import javafx.stage.WindowEvent;
@Lazy
@Scope("prototype")
@Component
public class CompanyCustomerEvaluationFormFileWindowController extends BaseController {
    private static final Logger logger = LoggerFactory.getLogger(CompanyCustomerEvaluationFormFileWindowController.class);

    public static void show(CompanyCustomerFile saved, Window window) {
        CompanyCustomerFileViewModel model = new CompanyCustomerFileViewModel();
        model.update(saved);
        show(model, window);
    }

    public static void show(CompanyCustomerFileViewModel viewModel, Window window) {
        String key = viewModel.getClass().getName() + "-" + viewModel.getId().get();
        if (toFront(key)) {
            return;
        }
        FxmlUtils.newLoaderAsyncWithRunLater("/ui/company/customer/customer_evaluation_form.fxml", null, loader -> {
            CompanyCustomerEvaluationFormFileWindowController controller = loader.getController();
            controller.viewModel = viewModel;
            controller.show(loader, window, Modality.NONE, key);
        });
    }


    public Label idField;
    public TextField filePathField;
    public CheckBox validField;
    public TextField editFilePathField;
    public DatePicker signDateField;
    public ToggleGroup catalog;
    public ToggleGroup level;
    public ToggleGroup score1;
    public ToggleGroup score2;
    public ToggleGroup score3;
    public ToggleGroup score4;
    public ToggleGroup score5;
    public ToggleGroup creditLevel;
    public ImageView imageView;
    public SplitPane splitPane;
    public ScrollPane leftPane;
    public Label totalCreditScoreLabel;

    private CompanyCustomerFileViewModel viewModel;

    private final SimpleStringProperty catalogProperty = new SimpleStringProperty("");
    private final SimpleStringProperty levelProperty = new SimpleStringProperty("");
    private final SimpleIntegerProperty score1Property = new SimpleIntegerProperty(-1);
    private final SimpleIntegerProperty score2Property = new SimpleIntegerProperty(-1);
    private final SimpleIntegerProperty score3Property = new SimpleIntegerProperty(-1);
    private final SimpleIntegerProperty score4Property = new SimpleIntegerProperty(-1);
    private final SimpleIntegerProperty score5Property = new SimpleIntegerProperty(-1);
    private final SimpleIntegerProperty creditLevelProperty = new SimpleIntegerProperty(-1);
    private final SimpleIntegerProperty totalCreditScoreProperty = new SimpleIntegerProperty(-1);

    private SimpleObjectProperty<Image> imageProperty = new SimpleObjectProperty<>();

    private CompletableFuture<CompanyCustomerEvaluationFormFile> loadedFuture;
    @Lazy
    @Autowired
    private CompanyCustomerFileService companyCustomerFileService;


    @Override
    public void show(Stage stage) {
        super.show(stage);
        stage.setFullScreen(false);
//        Rectangle2D screenBounds = Screen.getPrimary().getVisualBounds();
//
//        stage.setX(screenBounds.getMinX());
//        stage.setY(screenBounds.getMinY());
//        stage.setWidth(screenBounds.getWidth());
//        stage.setHeight(screenBounds.getHeight());
//
//        stage.isMaximized();
        stage.setMaximized(true);
        getTitle().set("客户评估表单");
    }

    @Override
    public void onShown(WindowEvent windowEvent) {
        super.onShown(windowEvent);
        if (logger.isDebugEnabled()) {
            logger.debug("onShown");
        }

        initializePane();

        loadedFuture = CompletableFuture.supplyAsync(() -> {
            int id = viewModel.getId().get();
            CompanyCustomerFile customerFile = companyCustomerFileService.findById(id);
            CompanyCustomerEvaluationFormFile formFile = companyCustomerFileService.findCustomerEvaluationFormFileByCustomerFile(customerFile);
            Platform.runLater(() -> update(formFile));
            return formFile;
        });
    }

    BiConsumer<ToggleGroup, String> stringRadioGroupUpdater = (group, newValue) -> {
        if (newValue != null) {
            for (Toggle toggle : group.getToggles()) {
                String data = (String) toggle.getUserData();
                if (data == null) {
                    if (logger.isWarnEnabled()) {
                        logger.warn("toggle unset userData: {}", toggle);
                    }
                    continue;
                }
                if (newValue.equals(data)) {
                    toggle.setSelected(true);
                    return;
                }
            }
        }
        Platform.runLater(() -> {
            group.selectToggle(null);
//                Toggle first = group.getToggles().getFirst();
//                first.setSelected(true);
//                first.setSelected(false);
//                RadioButton btn = (RadioButton) first;
//                btn.setText(newValue);
        });
    };

    BiConsumer<SimpleStringProperty, Toggle> stringPropertyUpdater = (property, toggle) -> {
        if (toggle == null) {
            property.set("");
            return;
        }
        String data = (String) toggle.getUserData();
        property.set(data);
    };

    BiConsumer<ToggleGroup, Number> numberRadioGroupUpdater = (group, newValue) -> {
        String value = String.valueOf(newValue);
        for (Toggle toggle : group.getToggles()) {
            String data = (String) toggle.getUserData();
            if (value.equals(data)) {
                toggle.setSelected(true);
                return;
            }
        }
        Platform.runLater(() -> {
            group.selectToggle(null);
//                Toggle first = group.getToggles().getFirst();
//                first.setSelected(true);
//                first.setSelected(false);
//                RadioButton btn = (RadioButton) first;
//                btn.setText(String.valueOf(newValue));
        });
    };

    BiConsumer<SimpleIntegerProperty, Toggle> numberPropertyUpdater = (property, toggle) -> {
        if (toggle == null) {
            property.set(0);
            return;
        }
        String data = (String) toggle.getUserData();
        property.set(Integer.parseInt(data));
    };


    int totalScoreToLevel(int score) {
        if (score >= 200) {
            return 4;
        } else if (score >= 150) {
            return 3;
        } else if (score >= 100) {
            return 2;
        } else if (score >= 60) {
            return 1;
        }
        return 0;
    }

    boolean calcValid() {
        if (creditLevelProperty.get() <= 0) {
            return false;
        }
        if (!StringUtils.hasText(catalogProperty.get())) {
            return false;
        }
        if (!StringUtils.hasText(levelProperty.get())) {
            return false;
        }
        if (score1Property.get() <= 0) {
            return false;
        }
        if (score2Property.get() <= 0) {
            return false;
        }
        if (score3Property.get() <= 0) {
            return false;
        }
        if (score4Property.get() <= 0) {
            return false;
        }
        if (score5Property.get() <= 0) {
            return false;
        }
        if (creditLevelProperty.get() <= 0) {
            return false;
        }
        return true;
    }

    private void initializePane() {
        idField.textProperty().bind(viewModel.getId().asString());
        filePathField.textProperty().bind(viewModel.getFilePath());
        editFilePathField.textProperty().bind(viewModel.getEditFilePath());
        signDateField.valueProperty().bindBidirectional(viewModel.getSignDate());
        validField.selectedProperty().bindBidirectional(viewModel.getValid());

        initializeRadioGroup(catalog, catalogProperty);
        initializeRadioGroup(level, levelProperty);

        initializeRadioGroup(score1, score1Property);
        initializeRadioGroup(score2, score2Property);
        initializeRadioGroup(score3, score3Property);
        initializeRadioGroup(score4, score4Property);
        initializeRadioGroup(score5, score5Property);

        creditLevelProperty.addListener((observable, oldValue, newValue) -> {
            numberRadioGroupUpdater.accept(creditLevel, newValue);
        });

        SimpleIntegerProperty[] scores = new SimpleIntegerProperty[]{score1Property, score2Property, score3Property, score4Property, score5Property};
        totalCreditScoreProperty.bind(Bindings.createIntegerBinding(() -> {
            int total = 0;
            for (SimpleIntegerProperty score : scores) {
                total += score.get();
            }
            creditLevelProperty.set(totalScoreToLevel(total));
            return total;
        }, scores));

        totalCreditScoreLabel.textProperty().bind(totalCreditScoreProperty.map(score -> {
            return "合计总分：" + score;
        }));

        Bindings.createBooleanBinding(() -> {
            boolean valid = calcValid();
            viewModel.getValid().set(valid);
            return valid;
        }, catalogProperty, levelProperty, score1Property, score2Property, score3Property, score4Property, score5Property, creditLevelProperty).addListener(((observable, oldValue, newValue) -> {
            logger.info("valid:{}", newValue);
        }));


        imageView.imageProperty().bind(viewModel.getFilePath().map(path -> {
            if (FileUtils.withExtensions(path, FileUtils.PDF)) {
                File pdfFile = new File(path);
                try (PDDocument pdDocument = Loader.loadPDF(pdfFile)) {
                    PDFRenderer pdfRenderer = new PDFRenderer(pdDocument);
                    BufferedImage bufferedImage = pdfRenderer.renderImageWithDPI(0, 300);

                    // 获取 BufferedImage 的宽度和高度
                    int width = bufferedImage.getWidth();
                    int height = bufferedImage.getHeight();
                    WritableImage writableImage = new WritableImage(width, height);
                    PixelWriter pixelWriter = writableImage.getPixelWriter();
                    // 将 BufferedImage 的像素数据复制到 WritableImage
                    for (int y = 0; y < height; y++) {
                        for (int x = 0; x < width; x++) {
                            int argb = bufferedImage.getRGB(x, y);
                            pixelWriter.setArgb(x, y, argb);
                        }
                    }
                    return writableImage;
                } catch (Exception e) {
                    setStatus(e.getMessage());
                }
                return null;
            } else {
                File file = new File(path);
                Image image = new Image(file.toURI().toString());
                return image;
            }
        }));


        leftPane.widthProperty().addListener((observable, oldValue, newValue) -> {
            Platform.runLater(() -> {
                imageView.setFitWidth(leftPane.getWidth());
                imageView.setFitHeight(leftPane.getHeight());
            });
        });

        imageView.setFitWidth(leftPane.getWidth());
        imageView.setFitHeight(leftPane.getHeight());

        imageView.setOnScroll(event -> {
            System.out.println("event = " + event);
            System.out.println("event.getDeltaY() = " + event.getDeltaY());
            Bounds bounds = imageView.getBoundsInLocal();
//            Bounds latestBounds = (Bounds) imageView.getProperties().get("latestBounds");
//            if (latestBounds != null) {
//                double latestBoundsWidth = latestBounds.getWidth();
//            }
//            if (bounds.getWidth() < leftPane.getWidth()) {
            imageView.setFitWidth(bounds.getWidth() + event.getDeltaY());
//            } else {
            imageView.setFitHeight(bounds.getHeight() + event.getDeltaY());
//            }
        });
    }

    private void initializeRadioGroup(ToggleGroup toggleGroup, SimpleStringProperty property) {
        property.addListener((observable, oldValue, newValue) -> {
            stringRadioGroupUpdater.accept(toggleGroup, newValue);
        });
        toggleGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
            stringPropertyUpdater.accept(property, newValue);
        });
    }

    private void initializeRadioGroup(ToggleGroup toggleGroup, SimpleIntegerProperty property) {
        property.addListener((observable, oldValue, newValue) -> {
            numberRadioGroupUpdater.accept(toggleGroup, newValue);
        });

        toggleGroup.selectedToggleProperty().addListener((observable, oldValue, newValue) -> {
            numberPropertyUpdater.accept(property, newValue);
        });
    }

    private void update(CompanyCustomerEvaluationFormFile formFile) {


        viewModel.update(formFile.getCustomerFile());

//        formFile.getScoreTemplateVersion();

        catalogProperty.set(formFile.getCatalog());
        levelProperty.set(formFile.getLevel());
        score1Property.set(formFile.getScore1());
        score2Property.set(formFile.getScore2());
        score3Property.set(formFile.getScore3());
        score4Property.set(formFile.getScore4());
        score5Property.set(formFile.getScore5());
        creditLevelProperty.set(formFile.getCreditLevel());
    }

    public void onSaveAction(ActionEvent event) {
        boolean modified = false;

        int id = viewModel.getId().get();
        CompanyCustomerEvaluationFormFile formFile = companyCustomerFileService.findCustomerEvaluationFormFileById(id);
        CompanyCustomerFile customerFile = formFile.getCustomerFile();

        if (!Objects.equals(catalogProperty.get(), formFile.getCatalog())) {
            formFile.setCatalog(catalogProperty.get());
            modified = true;
        }
        if (!Objects.equals(levelProperty.get(), formFile.getLevel())) {
            formFile.setLevel(levelProperty.get());
            modified = true;
        }
        if (!Objects.equals(score1Property.get(), formFile.getScore1())) {
            formFile.setScore1(score1Property.get());
            modified = true;
        }
        if (!Objects.equals(score2Property.get(), formFile.getScore2())) {
            formFile.setScore2(score2Property.get());
            modified = true;
        }
        if (!Objects.equals(score3Property.get(), formFile.getScore3())) {
            formFile.setScore3(score3Property.get());
            modified = true;
        }
        if (!Objects.equals(score4Property.get(), formFile.getScore4())) {
            formFile.setScore4(score4Property.get());
            modified = true;
        }
        if (!Objects.equals(score5Property.get(), formFile.getScore5())) {
            formFile.setScore5(score5Property.get());
            modified = true;
        }
        if (!Objects.equals(creditLevelProperty.get(), formFile.getCreditLevel())) {
            formFile.setCreditLevel(creditLevelProperty.get());
            modified = true;
        }


        if (viewModel.copyTo(customerFile)) {
            modified = true;
        }

        if (modified) {
            companyCustomerFileService.save(formFile);
        }

    }
}
