package com.bidizhaobiao.data.bigdata.persistence.orgproject.entity;

import org.apache.commons.collections4.CollectionUtils;
import org.neo4j.ogm.annotation.GeneratedValue;
import org.neo4j.ogm.annotation.Id;
import org.neo4j.ogm.annotation.NodeEntity;
import org.neo4j.ogm.annotation.Property;

import java.lang.reflect.Field;
import java.lang.reflect.InvocationTargetException;
import java.lang.reflect.Method;
import java.util.*;

@NodeEntity(label = "Project")
public class Project {
    // -------------------------------------- 招中标共有的属性
    @Id
    @GeneratedValue
    private Long nodeId;
    // 项目名称，项目编号，专业分类，地区
    @Property(name = "project_name")
    private String projectName;
    @Property(name = "project_code")
    private String projectCode;
    @Property(name = "industry")
    private String industry;
    @Property(name = "info_type")
    private String infoType;
    @Property(name = "project_addr")
    private String projectAddr;
    // 项目归属地区
    @Property(name = "area")
    private String area;
    // 项目归属省份
    @Property(name = "province")
    private String province;
    // 项目归属城市
    @Property(name = "city")
    private String city;
    // 项目归属区县
    @Property(name = "district")
    private String district;
    @Property(name = "bidding_budget")
    // 招标预算价格
    private String biddingBudget;
    // 子项目编码、子项目名称、子项目名称集合
    @Property(name = "sub_project_code")
    private String subProjectCode;
    @Property(name = "sub_project_name")
    private String subProjectName;
    @Property(name = "sub_project_name_alias")
    private String subProjectNameAlias;

    private Integer upgradeStatus;      // 这个属性用于旧数据的升级(null和0：待升级、-1：升级中、1：已升级)



    // 招标公告特有属性 招标标题/招标uuid/招标公告id/招标发布时间(已经被统一成yyyy-MM-dd格式了)
    @Property(name = "zhao_biao_name")
    private String zhaoBiaoName;
    @Property(name = "zhao_biao_uuid")
    private String zhaoBiaoUuid;
    @Property(name = "zhao_biao_id")
    private String zhaoBiaoId;
    @Property(name = "zhao_biao_page_time")
    private String zhaoBiaoPageTime;


    // 中标公告特有属性 中标标题/中标uuid/中标公告id/中标发布时间(已经被统一成yyyy-MM-dd格式了)/中标价格/是否废标公告
    @Property(name = "zhong_biao_name")
    private String zhongBiaoName;
    @Property(name = "zhong_biao_uuid")
    private String zhongBiaoUuid;
    @Property(name = "zhong_biao_id")
    private String zhongBiaoId;
    @Property(name = "zhong_biao_page_time")
    private String zhongBiaoPageTime;
    @Property(name = "win_bid_price")
    private String winBidPrice;
    @Property(name = "is_fei_biao")
    private String isFeiBiao;

    /**
     * 调用 addAllByExclude 时需要排除的属性
     */
    public Project() {
        this.isFeiBiao = "false";
    }


    public Long getNodeId() {
        return nodeId;
    }

    public void setNodeId(Long nodeId) {
        this.nodeId = nodeId;
    }

    public String getProjectName() {
        return projectName;
    }

    public void setProjectName(String projectName) {
        this.projectName = projectName;
    }

    public String getIndustry() {
        return industry;
    }

    public void setIndustry(String industry) {
        this.industry = industry;
    }

    public String getProjectAddr() {
        return projectAddr;
    }

    public void setProjectAddr(String projectAddr) {
        this.projectAddr = projectAddr;
    }

    public String getZhaoBiaoName() {
        return zhaoBiaoName;
    }

    public void setZhaoBiaoName(String zhaoBiaoName) {
        this.zhaoBiaoName = zhaoBiaoName;
    }

    public String getZhaoBiaoPageTime() {
        return zhaoBiaoPageTime;
    }

    public void setZhaoBiaoPageTime(String zhaoBiaoPageTime) {
        this.zhaoBiaoPageTime = zhaoBiaoPageTime;
    }

    public String getBiddingBudget() {
        return biddingBudget;
    }

    public void setBiddingBudget(String biddingBudget) {
        this.biddingBudget = biddingBudget;
    }

    public String getWinBidPrice() {
        return winBidPrice;
    }

    public void setWinBidPrice(String winBidPrice) {
        this.winBidPrice = winBidPrice;
    }

    public String getZhongBiaoName() {
        return zhongBiaoName;
    }

    public void setZhongBiaoName(String zhongBiaoName) {
        this.zhongBiaoName = zhongBiaoName;
    }

    public String getZhongBiaoPageTime() {
        return zhongBiaoPageTime;
    }

    public void setZhongBiaoPageTime(String zhongBiaoPageTime) {
        this.zhongBiaoPageTime = zhongBiaoPageTime;
    }

    public String getProjectCode() {
        return projectCode;
    }

    public void setProjectCode(String projectCode) {
        this.projectCode = projectCode;
    }

    public String getZhaoBiaoUuid() {
        return zhaoBiaoUuid;
    }

    public void setZhaoBiaoUuid(String zhaoBiaoUuid) {
        this.zhaoBiaoUuid = zhaoBiaoUuid;
    }

    public String getZhongBiaoUuid() {
        return zhongBiaoUuid;
    }

    public void setZhongBiaoUuid(String zhongBiaoUuid) {
        this.zhongBiaoUuid = zhongBiaoUuid;
    }

    public String getIsFeiBiao() {
        return isFeiBiao;
    }

    public void setIsFeiBiao(String isFeiBiao) {
        this.isFeiBiao = isFeiBiao;
    }

    public String getSubProjectName() {
        return subProjectName;
    }

    public void setSubProjectName(String subProjectName) {
        this.subProjectName = subProjectName;
    }

    public String getSubProjectNameAlias() {
        return subProjectNameAlias;
    }

    public void setSubProjectNameAlias(String subProjectNameAlias) {
        this.subProjectNameAlias = subProjectNameAlias;
    }

    public String getInfoType() {
        return infoType;
    }

    public void setInfoType(String infoType) {
        this.infoType = infoType;
    }

    public String getSubProjectCode() {
        return subProjectCode;
    }

    public void setSubProjectCode(String subProjectCode) {
        this.subProjectCode = subProjectCode;
    }

    public String getArea() {
        return area;
    }

    public void setArea(String area) {
        this.area = area;
    }

    public String getProvince() {
        return province;
    }

    public void setProvince(String province) {
        this.province = province;
    }

    public String getCity() {
        return city;
    }

    public void setCity(String city) {
        this.city = city;
    }

    public String getDistrict() {
        return district;
    }

    public void setDistrict(String district) {
        this.district = district;
    }

    public String getZhaoBiaoId() {
        return zhaoBiaoId;
    }

    public void setZhaoBiaoId(String zhaoBiaoId) {
        this.zhaoBiaoId = zhaoBiaoId;
    }

    public String getZhongBiaoId() {
        return zhongBiaoId;
    }

    public void setZhongBiaoId(String zhongBiaoId) {
        this.zhongBiaoId = zhongBiaoId;
    }

    public Integer getUpgradeStatus() {
        return upgradeStatus;
    }

    public void setUpgradeStatus(Integer upgradeStatus) {
        this.upgradeStatus = upgradeStatus;
    }

    /**
     * 获取文档的uuid(招标uuid或者中标uuid)
     * @return
     */
    public String getUuid() {
        return zhaoBiaoUuid != null ? zhaoBiaoUuid : zhongBiaoUuid;
    }

    /**
     * 加入招标公告特有的属性
     * @param project {@link Project}
     */
    public void addZhaoBiaoElement(Project project) {
        if (project != null) {
            try {
                addAllByExclude(project, null);
            } catch (Exception e) {
                e.printStackTrace();
            }
            this.setZhaoBiaoName(project.getZhaoBiaoName());
            this.setZhaoBiaoUuid(project.getZhaoBiaoUuid());
            this.setZhaoBiaoId(project.getZhaoBiaoId());
            this.setZhaoBiaoPageTime(project.getZhaoBiaoPageTime());
        }
    }



    /**
     * 加入中标公告特有的属性
     * @param project {@link Project}
     */
    public void addZhongBiaoElement(Project project) {
        if (project != null) {
            try {
                addAllByExclude(project, null);
            } catch (Exception e) {
                e.printStackTrace();
            }
            this.setZhongBiaoName(project.getZhongBiaoName());
            this.setZhongBiaoUuid(project.getZhongBiaoUuid());
            this.setZhongBiaoId(project.getZhongBiaoId());
            this.setZhongBiaoPageTime(project.getZhongBiaoPageTime());
            this.setWinBidPrice(project.getWinBidPrice());
            this.setIsFeiBiao(project.getIsFeiBiao());
        }
    }

    /**
     * 加入招中标共有的属性
     * @param project {@link Project}
     */
    private void addCommonElement(Project project) {
        if (project != null) {
            this.setProjectName(project.getProjectName());
            this.setProjectCode(project.getProjectCode());
            this.setIndustry(project.getIndustry());
            this.setInfoType(project.getInfoType());
            this.setProjectAddr(project.getProjectAddr());
            this.setArea(project.getArea());
            this.setProvince(project.getProvince());
            this.setCity(project.getCity());
            this.setDistrict(project.getDistrict());
            this.setBiddingBudget(project.getBiddingBudget());
            this.setSubProjectCode(project.getSubProjectCode());
            this.setSubProjectName(project.getSubProjectName());
            this.setSubProjectNameAlias(project.getSubProjectNameAlias());
            this.setUpgradeStatus(project.getUpgradeStatus());
        }
    }

    private List<String> defaultExcludeFields() {
        List<String> excludeFields = new LinkedList<>();
        excludeFields.add("nodeId");

        // 招标属性
        excludeFields.add("zhaoBiaoName");
        excludeFields.add("zhaoBiaoUuid");
        excludeFields.add("zhaoBiaoId");
        excludeFields.add("zhaoBiaoPageTime");

        // 中标属性
        excludeFields.add("zhongBiaoName");
        excludeFields.add("zhongBiaoUuid");
        excludeFields.add("zhongBiaoId");
        excludeFields.add("zhongBiaoPageTime");
        excludeFields.add("winBidPrice");
        excludeFields.add("isFeiBiao");
        return excludeFields;
    }

    /**
     * 把 project 不为空的属性(excludeFields的属性除外除外)赋值给当前对象的对应属性
     * @param project   目标项目
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     */
    public void addAllByExclude(Project project, List<String> excludeFields) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        if (CollectionUtils.isEmpty(excludeFields)) {
            excludeFields = defaultExcludeFields();
        }

        Field[] projectFields = project.getClass().getDeclaredFields();
        Field[] thisFields = this.getClass().getDeclaredFields();

        Map<String, Field> thisFieldMap = new HashMap<>();
        for (Field thisField : thisFields) {
            thisFieldMap.put(thisField.getName(), thisField);
        }

        for (Field projectField : projectFields) {
            String projectFieldName = projectField.getName();
            if (excludeFields.contains(projectFieldName)) {
                continue;
            }
            Field thisField = thisFieldMap.get(projectFieldName);
            thisField.setAccessible(true);
            projectField.setAccessible(true);
            if (thisField != null && projectField.get(project) != null) {
                Method thisMethod = this.getClass().getMethod("set" + projectFieldName.substring(0, 1).toUpperCase() + projectFieldName.substring(1), projectField.getType());
                thisMethod.invoke(this, projectField.get(project));
            }
        }
    }

    /**
     * 更新此项目的所有属性（全部以project为准，除了nodeId属性）
     * @param project
     * @throws InvocationTargetException
     * @throws IllegalAccessException
     * @throws NoSuchMethodException
     */
    public void updateAll(Project project) throws InvocationTargetException, IllegalAccessException, NoSuchMethodException {
        Field[] newFields = project.getClass().getDeclaredFields();
        Field[] thisFields = this.getClass().getDeclaredFields();
        for (Field newField : newFields) {
            String newFieldName = newField.getName();
            if (newFieldName.equals("nodeId")) {
                continue;
            }
            for (Field thisField : thisFields) {
                String thisFieldName = thisField.getName();
                if (thisFieldName.equals(newFieldName)) {
                    thisField.setAccessible(true);
                    newField.setAccessible(true);
                    Method thisMethod = this.getClass().getMethod("set" + thisFieldName.substring(0, 1).toUpperCase() + thisFieldName.substring(1), newField.getType());
                    thisMethod.invoke(this, newField.get(project));
                }
            }
        }
    }
}
