package com.ecep.contract.vm;

import java.time.LocalDateTime;
import java.util.Objects;

import com.ecep.contract.model.Employee;
import com.ecep.contract.model.Inventory;
import com.ecep.contract.model.ProjectCost;
import com.ecep.contract.model.ProjectCostItem;

import javafx.beans.property.SimpleBooleanProperty;
import javafx.beans.property.SimpleDoubleProperty;
import javafx.beans.property.SimpleObjectProperty;
import javafx.beans.property.SimpleStringProperty;
import lombok.Data;
import lombok.EqualsAndHashCode;

/**
 * 合同成本内容
 */
@Data
@EqualsAndHashCode(callSuper = false)
public class ProjectCostItemViewModel extends IdentityViewModel<ProjectCostItem> {
    /**
     * 关联的合同成本对象
     */
    SimpleObjectProperty<ProjectCost> cost = new SimpleObjectProperty<>();

    SimpleStringProperty title = new SimpleStringProperty();
    SimpleStringProperty specification = new SimpleStringProperty();
    SimpleStringProperty unit = new SimpleStringProperty();

    /**
     * 存货
     */
    SimpleObjectProperty<Inventory> inventory = new SimpleObjectProperty<>();

    SimpleDoubleProperty inQuantity = new SimpleDoubleProperty();
    SimpleDoubleProperty inTaxRate = new SimpleDoubleProperty();
    SimpleDoubleProperty inTaxPrice = new SimpleDoubleProperty();
    SimpleDoubleProperty inTaxAmount = new SimpleDoubleProperty();
    SimpleDoubleProperty inExclusiveTaxPrice = new SimpleDoubleProperty();
    SimpleDoubleProperty inExclusiveTaxAmount = new SimpleDoubleProperty();

    SimpleDoubleProperty outQuantity = new SimpleDoubleProperty();
    SimpleDoubleProperty outTaxRate = new SimpleDoubleProperty();
    SimpleDoubleProperty outTaxPrice = new SimpleDoubleProperty();
    SimpleDoubleProperty outTaxAmount = new SimpleDoubleProperty();
    SimpleDoubleProperty outExclusiveTaxPrice = new SimpleDoubleProperty();
    SimpleDoubleProperty outExclusiveTaxAmount = new SimpleDoubleProperty();
    /**
     * 毛利，单位为元，计算结果
     */
    SimpleDoubleProperty grossProfit = new SimpleDoubleProperty();
    /**
     * 毛利率，%，计算结果
     */
    SimpleDoubleProperty grossProfitMargin = new SimpleDoubleProperty();

    SimpleObjectProperty<LocalDateTime> createDate = new SimpleObjectProperty<>();
    SimpleObjectProperty<LocalDateTime> updateDate = new SimpleObjectProperty<>();
    SimpleObjectProperty<Employee> creator = new SimpleObjectProperty<>();
    SimpleObjectProperty<Employee> updater = new SimpleObjectProperty<>();

    SimpleBooleanProperty updatePriceWay = new SimpleBooleanProperty(false);

    SimpleStringProperty remark = new SimpleStringProperty();

    @Override
    protected void updateFrom(ProjectCostItem v) {
        super.updateFrom(v);
        getCost().set(v.getCost());
        getTitle().set(v.getTitle());
        getSpecification().set(v.getSpecification());
        getUnit().set(v.getUnit());
        getInventory().set(v.getInventory());

        getInQuantity().set(v.getInQuantity());
        getInTaxRate().set(v.getInTaxRate());
        getInExclusiveTaxPrice().set(v.getInExclusiveTaxPrice());
        getInTaxPrice().set(v.getInExclusiveTaxPrice() * (100 + v.getInTaxRate()) / 100.0);
        updateIn();

        getOutQuantity().set(v.getOutQuantity());
        getOutTaxRate().set(v.getOutTaxRate());
        getOutExclusiveTaxPrice().set(v.getOutExclusiveTaxPrice());
        getOutTaxPrice().set(v.getOutExclusiveTaxPrice() * (100 + v.getOutTaxRate()) / 100.0);
        updateOut();

        getCreateDate().set(v.getCreateDate());
        getUpdateDate().set(v.getUpdateDate());
        getCreator().set(v.getCreator());
        getUpdater().set(v.getUpdater());
        getRemark().set(v.getRemark());
    }

    public void updateIn() {
        double quantity = getInQuantity().get();

        getInTaxAmount().set(getInTaxPrice().get() * quantity);
        getInExclusiveTaxAmount().set(getInExclusiveTaxPrice().get() * quantity);

        updateGrossProfitMargin();
    }

    public void updateOut() {
        double quantity = getOutQuantity().get();

        getOutTaxAmount().set(getOutTaxPrice().get() * quantity);
        getOutExclusiveTaxAmount().set(getOutExclusiveTaxPrice().get() * quantity);

        updateGrossProfitMargin();
    }

    public void updateGrossProfitMargin() {
        double amount = getInExclusiveTaxAmount().get();
        getGrossProfit().set(amount - getOutExclusiveTaxAmount().get());
        if (amount == 0) {
            getGrossProfitMargin().set(0);
            return;
        }
        getGrossProfitMargin().set(getGrossProfit().get() / amount);
    }

    @Override
    public boolean copyTo(ProjectCostItem v) {
        boolean modified = super.copyTo(v);
        if (!Objects.equals(cost.get(), v.getCost())) {
            v.setCost(cost.get());
            modified = true;
        }
        if (!Objects.equals(title.get(), v.getTitle())) {
            v.setTitle(title.get());
            modified = true;
        }
        if (!Objects.equals(specification.get(), v.getSpecification())) {
            v.setSpecification(specification.get());
            modified = true;
        }
        if (!Objects.equals(unit.get(), v.getUnit())) {
            v.setUnit(unit.get());
            modified = true;
        }
        if (!Objects.equals(inventory.get(), v.getInventory())) {
            v.setInventory(inventory.get());
            modified = true;
        }

        if (!doubleEquals(inQuantity.get(), v.getInQuantity())) {
            v.setInQuantity(inQuantity.get());
            modified = true;
        }
        if (!doubleEquals(inTaxRate.get(), v.getInTaxRate())) {
            v.setInTaxRate(inTaxRate.get());
            modified = true;
        }
        if (!doubleEquals(inExclusiveTaxPrice.get(), v.getInExclusiveTaxPrice())) {
            v.setInExclusiveTaxPrice(inExclusiveTaxPrice.get());
            modified = true;
        }

        if (!doubleEquals(outQuantity.get(), v.getOutQuantity())) {
            v.setOutQuantity(outQuantity.get());
            modified = true;
        }
        if (!doubleEquals(outTaxRate.get(), v.getOutTaxRate())) {
            v.setOutTaxRate(outTaxRate.get());
            modified = true;
        }
        if (!doubleEquals(outExclusiveTaxPrice.get(), v.getOutExclusiveTaxPrice())) {
            v.setOutExclusiveTaxPrice(outExclusiveTaxPrice.get());
            modified = true;
        }

        if (!Objects.equals(createDate.get(), v.getCreateDate())) {
            v.setCreateDate(createDate.get());
            modified = true;
        }
        if (!Objects.equals(updateDate.get(), v.getUpdateDate())) {
            v.setUpdateDate(updateDate.get());
            modified = true;
        }
        if (!Objects.equals(creator.get(), v.getCreator())) {
            v.setCreator(creator.get());
            modified = true;
        }
        if (!Objects.equals(updater.get(), v.getUpdater())) {
            v.setUpdater(updater.get());
            modified = true;
        }
        if (!Objects.equals(remark.get(), v.getRemark())) {
            v.setRemark(remark.get());
            modified = true;
        }
        return modified;
    }

    /**
     * 判断两个 double 值是否相等
     *
     * @param a a
     * @param b b
     * @return 在误差范围内是否相同
     */
    private boolean doubleEquals(double a, double b) {
        return Math.abs(a - b) < 0.0001;
    }

    public static ProjectCostItemViewModel from(ProjectCostItem v) {
        ProjectCostItemViewModel viewModel = new ProjectCostItemViewModel();
        viewModel.update(v);
        return viewModel;
    }

    public void updateInQuantity(double value) {
        getInQuantity().setValue(value);
        updateIn();
    }

    public void updateInTaxRate(double value) {
        getInTaxRate().setValue(value);
        if (getUpdatePriceWay().get()) {
            exclusiveTaxPrice2TaxPrice(getInExclusiveTaxPrice(), getInTaxPrice(), getInTaxRate());
        } else {
            taxPrice2ExclusiveTaxPrice(getInTaxPrice(), getInExclusiveTaxPrice(), getInTaxRate());
        }
        updateIn();
    }

    public void updateInTaxPrice(double value) {
        getInTaxPrice().setValue(value);
        taxPrice2ExclusiveTaxPrice(getInTaxPrice(), getInExclusiveTaxPrice(), getInTaxRate());
        updateIn();
    }

    void taxPrice2ExclusiveTaxPrice(SimpleDoubleProperty taxPrice, SimpleDoubleProperty exclusiveTaxPrice,
            SimpleDoubleProperty taxRate) {
        double value = taxPrice.get();
        exclusiveTaxPrice.setValue(value / ((100 + taxRate.get()) / 100));
    }

    void exclusiveTaxPrice2TaxPrice(SimpleDoubleProperty exclusiveTaxPrice, SimpleDoubleProperty taxPrice,
            SimpleDoubleProperty taxRate) {
        double value = exclusiveTaxPrice.get();
        taxPrice.setValue(value * ((100 + taxRate.get()) / 100.0));
    }

    public void updateInExclusiveTaxPrice(double value) {
        getInExclusiveTaxPrice().setValue(value);
        exclusiveTaxPrice2TaxPrice(getInExclusiveTaxPrice(), getInTaxPrice(), getInTaxRate());
        updateIn();
    }

    public void updateOutQuantity(double value) {
        getOutQuantity().setValue(value);
        updateOut();
    }

    public void updateOutTaxRate(double value) {
        getOutTaxRate().setValue(value);
        if (getUpdatePriceWay().get()) {
            exclusiveTaxPrice2TaxPrice(getOutExclusiveTaxPrice(), getOutTaxPrice(), getOutTaxRate());
        } else {
            taxPrice2ExclusiveTaxPrice(getOutTaxPrice(), getOutExclusiveTaxPrice(), getOutTaxRate());
        }
        updateOut();
    }

    public void updateOutTaxPrice(double value) {
        getOutTaxPrice().setValue(value);
        taxPrice2ExclusiveTaxPrice(getOutTaxPrice(), getOutExclusiveTaxPrice(), getOutTaxRate());
        updateOut();
    }

    public void updateOutExclusiveTaxPrice(double value) {
        getOutExclusiveTaxPrice().setValue(value);
        exclusiveTaxPrice2TaxPrice(getOutExclusiveTaxPrice(), getOutTaxPrice(), getOutTaxRate());
        updateOut();
    }
}
