package com.ecep.contract.controller.project;

import java.time.LocalDate;
import java.time.LocalDateTime;
import java.util.List;
import java.util.Objects;
import java.util.stream.Collectors;

import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.ecep.contract.ContractPayWay;
import com.ecep.contract.controller.tab.TabSkin;
import com.ecep.contract.controller.table.EditableEntityTableTabSkin;
import com.ecep.contract.controller.table.cell.NumberTableCell;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractPayPlan;
import com.ecep.contract.model.Project;
import com.ecep.contract.model.ProjectFundPlan;
import com.ecep.contract.service.ContractPayPlanService;
import com.ecep.contract.service.ContractService;
import com.ecep.contract.service.ProjectFundPlanService;
import com.ecep.contract.util.FxmlPath;
import com.ecep.contract.util.NumberUtils;
import com.ecep.contract.vm.ProjectFundPlanViewModel;

import javafx.event.ActionEvent;
import javafx.scene.control.Button;
import javafx.scene.control.Tab;
import javafx.scene.control.TableColumn;
import lombok.Setter;

/**
 * 项目资金计划
 * 工单 #2
 * fxml 文件在 /src/main/resources/ui/ 目录
 */
@FxmlPath("/ui/project/project-tab-fund-plan.fxml")
public class ProjectTabSkinFundPlan
        extends AbstProjectTableTabSkin<ProjectFundPlan, ProjectFundPlanViewModel>
        implements TabSkin, EditableEntityTableTabSkin<ProjectFundPlan, ProjectFundPlanViewModel> {
    private static final Logger logger = LoggerFactory.getLogger(ProjectTabSkinFundPlan.class);

    public TableColumn<ProjectFundPlanViewModel, Number> idColumn;
    public TableColumn<ProjectFundPlanViewModel, LocalDate> payDateColumn;
    public TableColumn<ProjectFundPlanViewModel, Number> payRatioColumn;
    public TableColumn<ProjectFundPlanViewModel, Number> payCurrencyColumn;
    public TableColumn<ProjectFundPlanViewModel, Number> balanceColumn;
    public TableColumn<ProjectFundPlanViewModel, String> payTermColumn;
    public TableColumn<ProjectFundPlanViewModel, LocalDateTime> updateDateColumn;
    public TableColumn<ProjectFundPlanViewModel, String> payWayColumn;
    public Button updatePlanBtn;

    @Setter
    private ProjectFundPlanService projectFundPlanService;

    public ProjectTabSkinFundPlan(ProjectWindowController controller) {
        super(controller);
    }

    @Override
    protected ProjectFundPlanService getViewModelService() {
        if (projectFundPlanService == null) {
            projectFundPlanService = getBean(ProjectFundPlanService.class);
        }
        return projectFundPlanService;
    }

    public ContractPayPlanService getContractPayPlanService() {
        return controller.getCachedBean(ContractPayPlanService.class);
    }

    private ContractService getContractService() {
        return controller.getCachedBean(ContractService.class);
    }

    @Override
    public Tab getTab() {
        return controller.fundPlanTab;
    }

    @Override
    public void initializeTable() {
        super.initializeTable();
        // 关闭所有的排序功能
        idColumn.setSortable(false);
        payDateColumn.setSortable(false);
        payRatioColumn.setSortable(false);
        payCurrencyColumn.setSortable(false);
        payTermColumn.setSortable(false);
        updateDateColumn.setSortable(false);
        payWayColumn.setSortable(false);
        balanceColumn.setSortable(false);

        bindNumberColumn(idColumn, ProjectFundPlanViewModel::getId);
        bindLocalDateColumn(payDateColumn, ProjectFundPlanViewModel::getPayDate);
        bindColumn(payWayColumn, model -> {
            javafx.beans.property.SimpleStringProperty property = new javafx.beans.property.SimpleStringProperty();
            property.set(model.getPayWay().get() != null ? model.getPayWay().get().getText() : "");
            return property;
        });
        bindNumberColumn(payRatioColumn, ProjectFundPlanViewModel::getPayRatio);
        bindNumberColumn(payCurrencyColumn, ProjectFundPlanViewModel::getPayCurrency);
        payCurrencyColumn.setCellFactory(
                NumberTableCell.forTableColumn(controller.getCurrentEmployee().getNumberStringConverter()));
        bindNumberColumn(balanceColumn, ProjectFundPlanViewModel::getBalance);
        balanceColumn.setCellFactory(
                NumberTableCell.forTableColumn(controller.getCurrentEmployee().getNumberStringConverter()));
        bindColumn(payTermColumn, ProjectFundPlanViewModel::getPayTerm);
        bindLocalDateTimeColumn(updateDateColumn, ProjectFundPlanViewModel::getUpdateDate);
        updatePlanBtn.setOnAction(this::onUpdatePlanAction);
    }

    @Override
    public List<ProjectFundPlanViewModel> loadTableData(Project parent) {
        List<ProjectFundPlanViewModel> rows = super.loadTableData(parent);
        if (rows == null) {
            return null;
        }
        // TODO 按付款日期排序
        rows = rows.stream().sorted(java.util.Comparator.comparing(
                model -> model.getPayDate().get(),
                java.util.Comparator.nullsFirst(java.util.Comparator.naturalOrder()))).collect(Collectors.toList());

        double balance = 0;
        for (ProjectFundPlanViewModel row : rows) {
            if (row.getPayWay().get() == ContractPayWay.RECEIVE) {
                balance += row.getPayCurrency().get();
            } else if (row.getPayWay().get() == ContractPayWay.PAY) {
                balance -= row.getPayCurrency().get();
            }
            row.getBalance().set(balance);
        }

        return rows;

    }

    /**
     * 从合同的付款计划中更新项目的资金计划
     * 1. 从项目相关的合同中获取付款计划
     * 2. 更新项目的资金计划
     */
    private void onUpdatePlanAction(ActionEvent event) {
        try {
            // 获取当前项目
            Project project = getParent();
            if (project == null || project.getId() == null) {
                setStatus("提示, 无法获取项目信息");
                return;
            }

            List<ProjectFundPlan> fundPlans = getViewModelService().findAllByProject(project);
            // 将现有的项目资金计划转为以 ContractPayPlan 的id为key的map
            java.util.Map<Number, ProjectFundPlan> fundPlansMap = fundPlans.stream()
                    .filter(plan -> plan.getContractPayPlan() != null && plan.getContractPayPlan().getId() != null)
                    .collect(Collectors.toMap(
                            plan -> plan.getContractPayPlan().getId(),
                            plan -> plan));

            // 获取项目关联的所有合同
            List<Contract> contracts = getContractService().findAllByProject(project);
            if (contracts == null || contracts.isEmpty()) {
                setStatus("提示, 未找到与项目关联的合同");
                return;
            }

            // 遍历所有合同
            for (Contract contract : contracts) {
                // 获取合同的付款计划
                List<ContractPayPlan> payPlans = getContractPayPlanService().findAllByContract(contract);

                // 遍历每个付款计划
                for (ContractPayPlan payPlan : payPlans) {
                    // 检查是否已存在相同的合同付款计划
                    if (fundPlansMap.containsKey(payPlan.getId())) {
                        // 更新
                        ProjectFundPlan fundPlan = fundPlansMap.remove(payPlan.getId());
                        // 检查是否需要更新
                        boolean needsUpdate = false;
                        if (!Objects.equals(fundPlan.getPayWay(), contract.getPayWay())) {
                            fundPlan.setPayWay(contract.getPayWay());
                            needsUpdate = true;
                        }
                        if (!Objects.equals(fundPlan.getPayDate(), payPlan.getPayDate())) {
                            fundPlan.setPayDate(payPlan.getPayDate());
                            needsUpdate = true;
                        }
                        if (!NumberUtils.equals(fundPlan.getPayRatio(), payPlan.getPayRatio())) {
                            fundPlan.setPayRatio(payPlan.getPayRatio());
                            needsUpdate = true;
                        }
                        if (!Objects.equals(fundPlan.getPayTerm(), payPlan.getPayTerm())) {
                            fundPlan.setPayTerm(payPlan.getPayTerm());
                            needsUpdate = true;
                        }
                        if (!NumberUtils.equals(fundPlan.getPayCurrency(), payPlan.getPayCurrency())) {
                            fundPlan.setPayCurrency(payPlan.getPayCurrency());
                            needsUpdate = true;
                        }
                        if (needsUpdate) {
                            fundPlan.setContractPayPlan(payPlan);
                            fundPlan.setUpdateDate(LocalDateTime.now());
                            saveRowData(fundPlan);
                        }
                        continue;
                    }

                    // 创建新的项目资金计划
                    ProjectFundPlan fundPlan = getViewModelService().newInstanceByProject(project);
                    // 设置资金计划的属性
                    fundPlan.setPayDate(payPlan.getPayDate());
                    fundPlan.setPayWay(contract.getPayWay());
                    fundPlan.setPayRatio(payPlan.getPayRatio());
                    fundPlan.setPayTerm(payPlan.getPayTerm());
                    fundPlan.setPayCurrency(payPlan.getPayCurrency());
                    fundPlan.setContractPayPlan(payPlan);
                    fundPlan.setUpdateDate(LocalDateTime.now());
                    saveRowData(fundPlan);
                }
            }

            // 删除
            if (!fundPlansMap.isEmpty()) {
                for (ProjectFundPlan fundPlan : fundPlansMap.values()) {
                    getViewModelService().delete(fundPlan);
                }
            }
            // 刷新表格数据
            refresh();
        } catch (Exception e) {
            logger.error("更新项目资金计划失败", e);
        }
    }

    @Override
    protected ProjectFundPlanViewModel createNewViewModel() {
        ProjectFundPlanViewModel model = new ProjectFundPlanViewModel();
        Project project = getParent();
        model.getProject().set(project);
        model.getUpdateDate().set(LocalDateTime.now());
        saveRow(model);
        return model;
    }

    @Override
    protected void onTableRowDoubleClickedAction(ProjectFundPlanViewModel item) {
        // 可以在这里实现双击打开详情窗口的逻辑
        // 目前暂不实现具体的窗口
    }

    private ProjectFundPlanService getProjectFundPlanService() {
        if (projectFundPlanService == null) {
            projectFundPlanService = getBean(ProjectFundPlanService.class);
        }
        return projectFundPlanService;
    }

    @Override
    public void deleteRowData(ProjectFundPlan entity) {
        getProjectFundPlanService().delete(entity);
    }

    @Override
    public ProjectFundPlan loadRowData(ProjectFundPlanViewModel row) {
        return getProjectFundPlanService().findById(row.getId().get());
    }

    @Override
    public ProjectFundPlan saveRowData(ProjectFundPlan entity) {
        return getProjectFundPlanService().save(entity);
    }
}
