package com.ecep.contract.controller.tab;

import java.io.File;
import java.time.LocalDate;
import java.util.ArrayList;
import java.util.List;
import java.util.NoSuchElementException;
import java.util.Objects;
import java.util.Optional;

import org.controlsfx.control.textfield.TextFields;
import org.controlsfx.glyphfont.Glyph;
import com.ecep.contract.util.ProxyUtils;
import org.springframework.util.StringUtils;

import com.ecep.contract.ContractPayWay;
import com.ecep.contract.SpringApp;
import com.ecep.contract.controller.contract.AbstContractBasedTabSkin;
import com.ecep.contract.controller.contract.ContractWindowController;
import com.ecep.contract.controller.customer.CompanyCustomerWindowController;
import com.ecep.contract.controller.project.ProjectWindowController;
import com.ecep.contract.controller.vendor.CompanyVendorWindowController;
import com.ecep.contract.converter.CompanyStringConverter;
import com.ecep.contract.converter.ContractStringConverter;
import com.ecep.contract.converter.EmployeeStringConverter;
import com.ecep.contract.converter.ProjectStringConverter;
import com.ecep.contract.model.Company;
import com.ecep.contract.model.CompanyCustomer;
import com.ecep.contract.model.CompanyVendor;
import com.ecep.contract.model.Contract;
import com.ecep.contract.model.ContractType;
import com.ecep.contract.model.Employee;
import com.ecep.contract.model.Project;
import com.ecep.contract.model.ProjectSaleType;
import com.ecep.contract.service.CompanyCustomerService;
import com.ecep.contract.service.CompanyVendorService;
import com.ecep.contract.service.ContractGroupService;
import com.ecep.contract.service.ContractKindService;
import com.ecep.contract.service.ContractService;
import com.ecep.contract.service.ContractTypeService;
import com.ecep.contract.service.ExtendVendorInfoService;
import com.ecep.contract.service.ProjectSaleTypeService;
import com.ecep.contract.service.ProjectService;
import com.ecep.contract.service.VendorGroupService;
import com.ecep.contract.util.UITools;

import javafx.beans.binding.Bindings;
import javafx.event.ActionEvent;
import javafx.scene.control.Tab;
import javafx.scene.control.TextField;
import javafx.scene.control.TextInputDialog;
import javafx.stage.DirectoryChooser;
import javafx.util.StringConverter;
import javafx.util.converter.LocalDateStringConverter;
import javafx.util.converter.NumberStringConverter;

/**
 * 合同基础信息标签页
 */
public class ContractTabSkinBase extends AbstContractBasedTabSkin {

    public ContractTabSkinBase(ContractWindowController controller) {
        super(controller);
    }

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

    @Override
    public void initializeTab() {
        controller.openMainContractBtn.setOnAction(this::onContractOpenMainContractAction);
        controller.contractRenameBtn.setOnAction(this::onContractRenameAction);

        controller.contractPathCreateBtn.setOnAction(this::onContractCreatePathAction);
        controller.contractPathChangeBtn.setOnAction(this::onContractChangePathAction);
        controller.contractPathAsNameBtn.setOnAction(this::onContractPathSameAsNameAction);
        controller.contractPathAsCodeBtn.setOnAction(this::onContractPathSameAsCodeAction);
        controller.linkContractProjectBtn.setText(viewModel.getProject().get() == null ? "0" : "1");
        controller.linkContractProjectBtn.textProperty().bind(viewModel.getProject().map(v -> {
            return v == null ? "关联" : "打开";
        }));

        Glyph linkContractProjectBtnIcon = new Glyph("FontAwesome",
                viewModel.getProject().get() == null ? "UNLINK" : "LINK");
        controller.linkContractProjectBtn.graphicProperty().set(linkContractProjectBtnIcon);
        linkContractProjectBtnIcon.iconProperty().bind(viewModel.getProject().map(v -> {
            return v == null ? "UNLINK" : "LINK";
        }));
        controller.linkContractProjectBtn.setOnAction(this::onLinkContractProjectAction);

        controller.openMainContractBtn.disableProperty().bind(viewModel.getParentCode().isEmpty());

        // 与主合同编码是否为空绑定按钮可以
        controller.calcMainContractNoBtn.disableProperty().bind(viewModel.getParentCode().isNotEmpty());
        controller.calcMainContractNoBtn.setOnAction(this::calcMainContractNoAction);

        controller.payWayField.textProperty().bind(viewModel.getPayWay().map(ContractPayWay::getText));

        controller.nameField.textProperty().bind(viewModel.getName());
        controller.codeField.textProperty().bind(viewModel.getCode());

        controller.parentCodeField.textProperty().bindBidirectional(viewModel.getParentCode());
        parentCodeFieldAutoCompletion(controller.parentCodeField);

        controller.stateField.textProperty().bind(viewModel.getState());

        initializeBaseTabCompanyFieldAutoCompletion(controller.companyField);

        controller.groupField.textProperty().bind(viewModel.getGroup().map(group -> {
            ContractGroupService groupService = getContractGroupService();
            if (!ProxyUtils.isInitialized(group)) {
                group = groupService.findById(group.getId());
            }
            return group.getCode() + " " + group.getName() + " " + group.getTitle();
        }));

        controller.typeField.textProperty().bind(viewModel.getType().map(type -> {
            ContractTypeService typeService = controller.getCachedBean(ContractTypeService.class);
            if (!ProxyUtils.isInitialized(type)) {
                type = typeService.findById(type.getId());
            }
            return type.getCode() + " " + type.getCatalog() + " " + type.getName() + " " + type.getTitle() + "("
                    + type.getDirection() + ")";
        }));

        controller.kindField.textProperty().bind(viewModel.getKind().map(kind -> {
            ContractKindService kindService = controller.getCachedBean(ContractKindService.class);
            if (!ProxyUtils.isInitialized(kind)) {
                kind = kindService.findById(kind.getId());
            }
            return kind.getCode() + " " + kind.getName() + " " + kind.getTitle();
        }));

        // as customer
        controller.openRelativeCompanyCustomerBtn.setOnAction(this::onContractOpenRelativeCompanyCustomerAction);
        controller.openRelativeCompanyCustomerBtn.disableProperty().bind(Bindings.createBooleanBinding(() -> {

            ContractType type = viewModel.getType().get();
            if (type == null) {
                return true;
            }
            Company company = viewModel.getCompany().get();
            if (company == null) {
                return true;
            }
            if (!ProxyUtils.isInitialized(type)) {
                ContractTypeService typeService = controller.getCachedBean(ContractTypeService.class);
                type = typeService.findById(type.getId());
            }
            return !Objects.equals(type.getDirection(), "收");
        }, viewModel.getType()));
        controller.openRelativeCompanyCustomerBtn.managedProperty()
                .bind(controller.openRelativeCompanyCustomerBtn.disabledProperty().not());
        controller.openRelativeCompanyCustomerBtn.visibleProperty()
                .bind(controller.openRelativeCompanyCustomerBtn.managedProperty());

        // as vendor
        controller.openRelativeCompanyVendorBtn.setOnAction(this::onContractOpenRelativeCompanyVendorAction);
        controller.openRelativeCompanyVendorBtn.disableProperty().bind(Bindings.createBooleanBinding(() -> {
            ContractType type = viewModel.getType().get();
            if (type == null) {
                return true;
            }
            Company company = viewModel.getCompany().get();
            if (company == null) {
                return true;
            }
            if (!ProxyUtils.isInitialized(type)) {
                ContractTypeService typeService = controller.getCachedBean(ContractTypeService.class);
                type = typeService.findById(type.getId());
            }
            return !Objects.equals(type.getDirection(), "付");
        }, viewModel.getType()));
        controller.openRelativeCompanyVendorBtn.managedProperty()
                .bind(controller.openRelativeCompanyVendorBtn.disabledProperty().not());
        controller.openRelativeCompanyVendorBtn.visibleProperty()
                .bind(controller.openRelativeCompanyVendorBtn.managedProperty());

        LocalDateStringConverter localDateStringConverter = controller.getCurrentEmployee()
                .getLocalDateStringConverter();

        controller.setupDateField.setConverter(localDateStringConverter);
        controller.setupDateField.valueProperty().bindBidirectional(viewModel.getSetupDate());
        controller.startDateField.setConverter(localDateStringConverter);
        controller.startDateField.valueProperty().bindBidirectional(viewModel.getStartDate());
        controller.endDateField.setConverter(localDateStringConverter);
        controller.endDateField.valueProperty().bindBidirectional(viewModel.getEndDate());
        controller.orderDateField.setConverter(localDateStringConverter);
        controller.orderDateField.valueProperty().bindBidirectional(viewModel.getOrderDate());
        controller.inureDateField.setConverter(localDateStringConverter);
        controller.inureDateField.valueProperty().bindBidirectional(viewModel.getInureDate());
        controller.varyDateField.setConverter(localDateStringConverter);
        controller.varyDateField.valueProperty().bindBidirectional(viewModel.getVaryDate());

        EmployeeStringConverter employeeStringConverter = SpringApp.getBean(EmployeeStringConverter.class);
        UITools.autoCompletion(controller.setupPersonField, viewModel.getSetupPerson(),
                employeeStringConverter::suggest, employeeStringConverter);
        UITools.autoCompletion(controller.inurePersonField, viewModel.getInurePerson(),
                employeeStringConverter::suggest, employeeStringConverter);
        UITools.autoCompletion(controller.varyPersonField, viewModel.getVaryPerson(),
                employeeStringConverter::suggest, employeeStringConverter);
        UITools.autoCompletion(controller.employeeField, viewModel.getEmployee(),
                employeeStringConverter::suggest, employeeStringConverter);
        UITools.autoCompletion(controller.handlerField, viewModel.getHandler(),
                employeeStringConverter::suggest, employeeStringConverter);

        initializeBaseTabProjectFieldAutoCompletion(controller.projectField);

        controller.pathField.textProperty().bind(viewModel.getPath());
        controller.createdField.textProperty().bindBidirectional(viewModel.getCreated(),
                controller.getCurrentEmployee().getLocalDateTimeStringConverter());
        controller.guidField.textProperty().bind(viewModel.getGuid());
        controller.descriptionField.textProperty().bindBidirectional(viewModel.getDescription());

        NumberStringConverter numberStringConverter = controller.getCurrentEmployee().getNumberStringConverter();
        controller.amountField.textProperty().bindBidirectional(viewModel.getAmount(), numberStringConverter);
        controller.totalQuantityField.textProperty().bindBidirectional(viewModel.getTotalQuantity(),
                numberStringConverter);
        controller.totalAmountField.textProperty().bindBidirectional(viewModel.getTotalAmount(), numberStringConverter);
        controller.totalUnTaxAmountField.textProperty().bindBidirectional(viewModel.getTotalUnTaxAmount(),
                numberStringConverter);
        controller.execQuantityField.textProperty().bindBidirectional(viewModel.getExecQuantity(),
                numberStringConverter);
        controller.execAmountField.textProperty().bindBidirectional(viewModel.getExecAmount(), numberStringConverter);
        controller.execUnTaxAmountField.textProperty().bindBidirectional(viewModel.getExecUnTaxAmount(),
                numberStringConverter);

        controller.versionLabel.textProperty().bind(viewModel.getVersion().asString());
    }

    private void parentCodeFieldAutoCompletion(TextField textField) {
        ContractStringConverter converter = SpringApp.getBean(ContractStringConverter.class);
        converter.setFormater(Contract::getCode);
        TextFields.bindAutoCompletion(textField, converter::suggest, converter);
    }

    private void calcMainContractNoAction(ActionEvent event) {
        try {
            Contract contract = controller.getEntity();
            if (getContractService().updateParentCode(contract)) {
                save(contract);
            }
        } catch (NoSuchElementException e) {
            viewModel.getParentCode().set(e.getMessage());
        }
    }

    public void onLinkContractProjectAction(ActionEvent event) {
        Project project = viewModel.getProject().get();
        if (project != null) {
            ProjectWindowController.show(project, null);
            return;
        }

        String code = viewModel.getParentCode().get();
        if (!StringUtils.hasText(code)) {
            code = viewModel.getCode().get();
            if (code.contains("-")) {
                code = code.substring(0, code.indexOf("-"));
            }
            if (!StringUtils.hasText(code)) {
                setStatus("未设置合同编号, 无法关联项目");
                return;
            }
        }

        project = getProjectService().findByCode(code);
        if (project == null) {
            if (code.contains("-")) {
                setStatus("未找到关联项目");
                return;
            }

            project = new Project();

            String name = viewModel.getName().get();
            if (StringUtils.hasText(name)) {
                project.setName(name);
            }

            getProjectService().applyCode(project, code);

            // 设置项目的开始创建时间，从合同的创建时间、提交日期、开始日期中取最早的日期
            List<LocalDate> dates = new ArrayList<>();
            if (viewModel.getCreated().get() != null) {
                dates.add(viewModel.getCreated().get().toLocalDate());
            }
            if (viewModel.getSetupDate().get() != null) {
                dates.add(viewModel.getSetupDate().get());
            }
            if (viewModel.getStartDate().get() != null) {
                dates.add(viewModel.getStartDate().get());
            }
            dates.stream().min(LocalDate::compareTo).ifPresent(project::setCreated);

            Employee applicant = viewModel.getEmployee().get();
            if (applicant != null) {
                project.setApplicant(applicant);
            }
            if (viewModel.getAmount().get() > 0) {
                project.setAmount((int) viewModel.getAmount().get());
            }

            project = getProjectService().save(project);
        }
        viewModel.getProject().set(project);

        save();
    }

    public void onContractRenameAction(ActionEvent event) {
        TextInputDialog dialog = new TextInputDialog();
        dialog.setTitle("合同名称变更");
        dialog.setHeaderText("请输入变更的合同名称");
        dialog.setContentText(controller.nameField.getText());

        Optional<String> result = dialog.showAndWait();
        if (result.isPresent()) {
            System.out.println("You entered: " + result.get());
        } else {
            System.out.println("No input provided.");
        }
    }

    public void onContractOpenMainContractAction(ActionEvent event) {
        String parentCode = viewModel.getParentCode().get();

        Contract parent = getContractService().findByCode(parentCode);
        if (parent == null) {
            UITools.showAlertAndWait("没有找到上级合同:" + parentCode);
            return;
        }
        ContractWindowController.show(parent, controller.root.getScene().getWindow());
    }

    /**
     * 创建合同存储目录
     */
    public void onContractCreatePathAction(ActionEvent event) {
        Contract contract = getEntity();
        ContractService contractService = getContractService();
        if (contractService.existsContractPath(contract)) {
            File dir = new File(contract.getPath());
            if (!dir.exists()) {
                if (contractService.makePathAbsent(contract)) {
                    // update ?
                }
            }
        } else {
            if (contractService.makePathAbsent(contract)) {
                // update ?
            } else {
                setStatus("目录存在或创建失败");
            }
        }
    }

    public void onContractChangePathAction(ActionEvent event) {
        DirectoryChooser chooser = new DirectoryChooser();
        Contract entity = getEntity();
        String path = entity.getPath();
        File initialDirectory = null;
        // 如果当前已经设置了目录并且路径有效，则设置初始目录为该目录
        if (StringUtils.hasText(path)) {
            File dir = new File(path);
            if (dir.exists()) {
                initialDirectory = dir;
            }
        }
        if (initialDirectory == null) {
            if (entity.getPayWay() == ContractPayWay.RECEIVE) {
                // 根据项目设置初始目录
                Project project = entity.getProject();
                if (project != null) {
                    if (!ProxyUtils.isInitialized(project)) {
                        project = getProjectService().findById(project.getId());
                    }
                    // 根据项目销售方式设置初始目录
                    ProjectSaleType saleType = project.getSaleType();
                    if (saleType != null) {
                        if (!ProxyUtils.isInitialized(saleType)) {
                            saleType = getSaleTypeService().findById(saleType.getId());
                        }
                        File dir = new File(saleType.getPath());
                        if (saleType.isStoreByYear()) {
                            dir = new File(dir, "20" + project.getCodeYear());
                        }
                        initialDirectory = dir;
                    }
                }
            } else if (entity.getPayWay() == ContractPayWay.PAY) {
                // 根据上级合同设置初始目录
                String parentCode = entity.getParentCode();
                if (StringUtils.hasText(parentCode)) {
                    Contract parent = getContractService().findByCode(parentCode);
                    if (parent != null) {
                        if (StringUtils.hasText(parent.getPath())) {
                            File dir = new File(parent.getPath());
                            if (dir.exists()) {
                                initialDirectory = dir;
                            }
                        }
                    }
                }
            }
            if (initialDirectory == null) {
                initialDirectory = getContractService().getBasePath();
            }
        }

        if (initialDirectory != null) {
            chooser.setInitialDirectory(initialDirectory);
        }
        File newDirectory = chooser.showDialog(getTab().getContent().getScene().getWindow());
        if (newDirectory != null) {
            entity.setPath(newDirectory.getAbsolutePath());
            save(entity);
        }
    }

    public void onContractPathSameAsNameAction(ActionEvent event) {
        Contract contract = getEntity();
        String path = contract.getPath();
        if (!StringUtils.hasText(path)) {
            return;
        }
        File file = new File(path);
        if (!file.exists()) {
            return;
        }

        if (file.getName().equals(contract.getName())) {
            return;
        }
        File dest = new File(file.getParent(), contract.getName());
        if (file.renameTo(dest)) {
            contract.setPath(dest.getAbsolutePath());
            save(contract);
            controller.setStatus("目录变更为" + dest.getName());
        }
    }

    public void onContractPathSameAsCodeAction(ActionEvent event) {
        Contract contract = getEntity();
        String path = contract.getPath();
        if (!StringUtils.hasText(path)) {
            return;
        }
        File file = new File(path);
        if (!file.exists()) {
            return;
        }
        if (file.getName().equals(contract.getCode())) {
            return;
        }
        File dest = new File(file.getParent(), contract.getCode());
        if (file.renameTo(dest)) {
            contract.setPath(dest.getAbsolutePath());
            save(contract);
            controller.setStatus("目录变更为" + dest.getName());
        }
    }

    public void onContractOpenRelativeCompanyCustomerAction(ActionEvent event) {
        Contract contract = getEntity();
        Company company = contract.getCompany();
        CompanyCustomer companyCustomer = getCompanyCustomerService().findByCompany(company);
        CompanyCustomerWindowController.show(companyCustomer, null);
    }

    public void onContractOpenRelativeCompanyVendorAction(ActionEvent event) {
        Contract contract = getEntity();
        Company company = contract.getCompany();
        CompanyVendorService service = SpringApp.getBean(CompanyVendorService.class);
        CompanyVendor companyVendor = service.findByCompany(company);
        CompanyVendorWindowController.show(companyVendor, null);
    }

    private void initializeBaseTabCompanyFieldAutoCompletion(TextField textField) {
        CompanyStringConverter converter = SpringApp.getBean(CompanyStringConverter.class);
        UITools.autoCompletion(textField, viewModel.getCompany(), converter);
    }

    private void initializeBaseTabProjectFieldAutoCompletion(TextField textField) {
        ProjectStringConverter converter = SpringApp.getBean(ProjectStringConverter.class);
        StringConverter<Project> stringConverter = new StringConverter<>() {
            @Override
            public String toString(Project object) {
                Project project = converter.prefixObject(object);
                if (project == null) {
                    return "";
                }
                return project.getCode();
            }

            @Override
            public Project fromString(String string) {
                return converter.fromString(string);
            }
        };

        converter.setFormater(Project::getCode);
        UITools.autoCompletion(textField, viewModel.getProject(), converter::suggest, stringConverter);
    }

    public CompanyCustomerService getCompanyCustomerService() {
        return getCachedBean(CompanyCustomerService.class);
    }

    public ProjectService getProjectService() {
        return getCachedBean(ProjectService.class);
    }

    public ProjectSaleTypeService getSaleTypeService() {
        return getCachedBean(ProjectSaleTypeService.class);
    }

    public ExtendVendorInfoService getExtendVendorInfoService() {
        return getCachedBean(ExtendVendorInfoService.class);
    }

    public ContractGroupService getContractGroupService() {
        return getCachedBean(ContractGroupService.class);
    }

    public VendorGroupService getVendorGroupService() {
        return getCachedBean(VendorGroupService.class);
    }
}
