package com.sifang.modules.supply.stock.dao;

import cn.hutool.core.date.DateUtil;
import com.jfinal.kit.StrKit;
import com.jfinal.plugin.activerecord.Db;
import com.jfinal.plugin.activerecord.Record;
import com.sifang.modules.site.siteInfo.service.SiteEmployeeService;
import com.sifang.modules.sunshine.SystemSetting.dao.TraderWarehouseRelDao;
import com.sifang.modules.sunshine.SystemSetting.utils.BusinessException;
import com.sifang.modules.sunshine.SystemSetting.utils.StringUtil;
import com.sifang.modules.supply.order.entity.CrmSupplyMaterialDeliverOrderDetail;
import com.sifang.modules.supply.setting.entity.CrmSupplyWarehouse;
import com.sifang.modules.supply.stock.entity.MaterialWarehouseStocks;
import com.sifang.modules.supply.stock.entity.SupplyMaterial;
import com.sifang.modules.sys.common.UserUtils;
import com.sifang.modules.sys.common.entity.User;
import com.sifang.modules.sys.common.persistence.BaseDao;
import com.sifang.modules.sys.common.persistence.Parameter;
import com.sifang.modules.sys.common.utils.DateUtils;
import com.sifang.modules.sys.common.utils.IdGen;
import com.sifang.modules.sys.util.LayuiPage;
import com.sifang.modules.sys.util.SqlBuilder;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.stereotype.Repository;

import javax.annotation.Resource;
import java.math.BigDecimal;
import java.util.*;

/**
 * @author hongzq
 */
@Repository
public class MaterialStockDao extends BaseDao<MaterialWarehouseStocks> {

    @Autowired
    SupplyMaterialDao materialDao;


    @Autowired
    SiteEmployeeService siteEmployeeService;

    @Autowired
    private TraderWarehouseRelDao traderWarehouseRelDao;


    public List<Record> stockList(LayuiPage<Record> page, Map<String, String> map) {
        SqlBuilder sql = new SqlBuilder();
        sql.line("SELECT s.id, s.material_id, s.ascription_id, s.ascription_name, s.warehouse_id, w.name as warehouseName, m.code, m.remarks, m.unit_name,  m.new_update_time");
        sql.line(", t.name as typeName,s.warning, s.froze_out_num, s.froze_in_num, m.material_specs,m.material_brand,m.material_name as materialName,n.name as unitName");
        sql.line(",s.cost_price,s.bd_sale_price,m.qq_code ");
        sql.line("FROM crm_supply_material_warehouse_stocks s");
        sql.line("LEFT JOIN crm_supply_material m on s.material_id=m.id");
        sql.line("LEFT JOIN crm_supply_warehouse w on s.warehouse_id=w.id");
        sql.line("LEFT JOIN crm_supply_material_type t on m.material_type_id=t.id");
        sql.line("LEFT JOIN crm_supply_material_unit n on m.unit_code=n.unit_code ");
        sql.line("WHERE 1=1 and  s.type != '3' ");
        appendStockListCondition(sql, map);
        sql.line("order by s.create_time desc, s.material_id ");
        if (page != null) {
            sql.limit(page.getPage(), page.getLimit());
        }
        return Db.find(sql.build(), sql.params());
    }

    public long countStockList(Map<String, String> map) {
        SqlBuilder sql = new SqlBuilder();
        sql.line("SELECT COUNT(1)");
        sql.line("FROM crm_supply_material_warehouse_stocks s");
        sql.line("LEFT JOIN crm_supply_material m on s.material_id=m.id");
        sql.line("WHERE 1=1 and  s.type != '3' ");
        appendStockListCondition(sql, map);
        return Db.queryLong(sql.build(), sql.params());
    }

    public List<Record> stockListForTrader(LayuiPage<Record> page, Map<String, String> map) {
        SqlBuilder sql = commonSqlBuilder(map);
        if (page != null) {
            sql.limit(page.getPage(), page.getLimit());
        }
        return Db.find(sql.build(), sql.params());
    }

    public long countStockListForTrader(Map<String, String> map) {
        SqlBuilder sql = new SqlBuilder();
        sql.line("SELECT COUNT(1)");
        sql.line("FROM crm_supply_material_warehouse_stocks s");
        sql.line("LEFT JOIN crm_supply_material m on s.material_id=m.id");
        sql.line("LEFT JOIN crm_trader tr on tr.id = s.ascription_id ");
        sql.line("WHERE 1=1 and s.type = '3'  ");
        appendStockListConditionForTrader(sql, map);
        return Db.queryLong(sql.build(), sql.params());
    }

    public SqlBuilder commonSqlBuilder(Map<String, String> map) {
        String time1 = DateUtils.dateChangeDays(new Date(), -30, "yyyy-MM-dd");
        String time2 = DateUtils.dateChangeDays(new Date(), -60, "yyyy-MM-dd");
        String time3 = DateUtils.dateChangeDays(new Date(), -90, "yyyy-MM-dd");
        SqlBuilder sql = new SqlBuilder();
        sql.line("SELECT s.id, s.material_id, s.ascription_id, s.ascription_name, s.warehouse_id, w.name as warehouseName, m.code, m.remarks, m.unit_name,  m.new_update_time");
        sql.line(", t.name as typeName,s.warning, s.froze_out_num, s.froze_in_num, m.material_specs,m.material_brand,m.material_name as materialName,n.name as unitName");
        sql.line(",s.cost_price,s.bd_sale_price,m.qq_code ,IFNULL(s.yk_yfh_amount,0) as yk_yfh_amount ,IFNULL(s.yk_yaz_amount,0) as yk_yaz_amount ");
        sql.line(" ,IFNULL(s.yk_yfd_amount,0) as  yk_yfd_amount , IFNULL(s.yk_th_amount,0) as yk_th_amount, IFNULL(s.yk_md_amount,0) as  yk_md_amount ");
        //yfhTotalCapacity 累计已发货 不统计盘点单
        sql.line(", sum(case when b.biz_type = '3' then 0 else b.amount end) as yfhTotalCapacity ");//,sum(b.sold_num) as  yazTotalCapacity
        sql.line(",sum(case when b.input_time > ? then b.remaining else 0 end) as num1 ",time1);
        sql.line(", sum(case when b.input_time > ? and  b.input_time <= ?  then b.remaining else 0 end) as num2 ",time2,time1);
        sql.line(", sum(case when b.input_time > ? and  b.input_time <= ?  then b.remaining else 0 end) as num3 ",time3,time2);
        sql.line(", sum(case when b.input_time <= ? then b.remaining else 0 end) as num4 ",time3);
        sql.line(",sum(case when b.input_time > ? then b.remaining * b.bd_sale_price else 0 end) as price1 ",time1);
        sql.line(", sum(case when b.input_time > ? and  b.input_time <= ?  then b.remaining  * b.bd_sale_price else 0 end) as price2 ",time2,time1);
        sql.line(", sum(case when b.input_time > ? and  b.input_time <= ?  then b.remaining  * b.bd_sale_price else 0 end) as price3 ",time3,time2);
        sql.line(", sum(case when b.input_time <= ? then b.remaining  * b.bd_sale_price else 0 end) as price4 ",time3);
        sql.line("FROM crm_supply_material_warehouse_stocks s");
        sql.line("LEFT JOIN crm_supply_material m on s.material_id=m.id");
        sql.line("LEFT JOIN crm_supply_warehouse w on s.warehouse_id=w.id");
        sql.line("LEFT JOIN crm_supply_material_type t on m.material_type_id=t.id");
        sql.line("LEFT JOIN crm_supply_material_unit n on m.unit_code=n.unit_code ");
        sql.line("LEFT JOIN crm_trader tr on tr.id = s.ascription_id ");
        sql.line(" LEFT JOIN crm_supply_material_batch b on b.belong_id = s.ascription_id  and b.material_id = s.material_id and  s.warehouse_id = b.warehouse_id ");
        sql.line("WHERE 1=1 and s.type = '3' ");
        appendStockListConditionForTrader(sql, map);
        sql.line(" group by  s.material_id, s.warehouse_id ");
        sql.line("order by s.create_time desc, s.material_id ");
        return sql;
    }

    public List<Record> getStockListForTrader(Map<String, String> map) {
        SqlBuilder sql = commonSqlBuilder(map);
        return Db.find(sql.build(), sql.params());
    }

    private List<String> appendColumns(List<Record> records, String column) {
        List<String> ret = new ArrayList<>();
        for (Record record : records) {
            String value = record.getStr(column);
            if (StrKit.notBlank(value)) {
                ret.addAll(Arrays.asList(value.split(",")));
            }
        }
        return ret;
    }
    private void appendStockListCondition(SqlBuilder sql, Map<String, String> map) {
        User user = UserUtils.getUser();
        if(User.USER_TYPE_WXG.equals(user.getUserType())){

            List<Record> employeeRole = siteEmployeeService.findEmployeeByUserId(user.getId());
            List<String> traderList = appendColumns(employeeRole, "trader_id");
            if (!traderList.isEmpty()) {
                sql.inst("and s.ascription_id in ", traderList);
            }
        }
        if (Objects.equals("2", user.getTraderType())) {
            List<String> warehouseList = traderWarehouseRelDao.findByTraderId(user.getTraderId());
            sql.inst("and s.warehouse_id in", warehouseList);
        }else   if (StringUtil.checkParamsValid(map.get("ascriptionId"))) {
            sql.inst("and s.ascription_id in ", map.get("ascriptionId").split(","));
        }

        if (StringUtil.checkParamsValid(map.get("ascriptionIds"))) {
            sql.inst("and s.ascription_id in ", map.get("ascriptionIds").split(","));
        }
        if (StringUtil.checkParamsValid(map.get("types"))) {
            sql.inst("and s.type in ", map.get("types").split(","));
        }
        if (StringUtil.checkParamsValid(map.get("code"))) {
            sql.like("and m.code like ?", map.get("code").trim());
        }
        if (StringUtil.checkParamsValid(map.get("excludeWarehouseIds"))) {
            sql.inst("and s.warehouse_id not in ", map.get("excludeWarehouseIds"));
        }
        if (StringUtil.checkParamsValid(map.get("materialTypeId"))) {
            sql.line("and m.material_type_id=?", map.get("materialTypeId"));
        }
        if (StringUtil.checkParamsValid(map.get("materialGroupId"))) {
            sql.line("and m.material_group_id=?", map.get("materialGroupId"));
        }
        if (StringUtil.checkParamsValid(map.get("remarks"))) {
            sql.like("and m.remarks like ?", map.get("remarks").trim());
        }
        if (StringUtil.checkParamsValid(map.get("warehouseIds"))) {
            sql.inst("and s.warehouse_id in", map.get("warehouseIds").split(","));
        }
        if (!StringUtil.checkParamsValid(map.get("showZeroStock"))) {
            sql.line("and s.warning > 0");
        }
        if (StringUtil.checkParamsValid(map.get("id"))) {
            sql.line("and s.id=?", map.get("id"));
        }
        if (StringUtil.checkParamsValid(map.get("lastModifyTimeMin"))) {
            sql.line("and m.new_update_time >= ?", map.get("lastModifyTimeMin"));
        }
        if (StringUtil.checkParamsValid(map.get("lastModifyTimeMax"))) {
            sql.line("and m.new_update_time <= ?", map.get("lastModifyTimeMax"));
        }
        if (StringUtil.checkParamsValid(map.get("unitId"))) {
            sql.line("and m.unit_id=?", map.get("unitId"));
        }
        if (StringUtil.checkParamsValid(map.get("qq_code"))) {
            sql.line("and m.qq_code=?", map.get("qq_code"));
        }



        if (StringUtil.checkParamsValid(map.get("materialIds"))) {
            sql.inst("and s.material_id in ", map.get("materialIds").split(","));
        }
    }


    private void appendStockListConditionForTrader(SqlBuilder sql, Map<String, String> map) {
        User user = UserUtils.getUser();
        if(User.USER_TYPE_WXG.equals(user.getUserType())){
            List<Record> employeeRole = siteEmployeeService.findEmployeeByUserId(user.getId());
            List<String> traderList = appendColumns(employeeRole, "trader_id");
            if (!traderList.isEmpty()) {
                sql.inst("and s.ascription_id in ", traderList);
            }
        }
        if (Objects.equals("2", user.getTraderType())) {
            List<String> warehouseList = traderWarehouseRelDao.findByTraderId(user.getTraderId());
            sql.inst("and s.warehouse_id in", warehouseList);
        }else   if (StringUtil.checkParamsValid(map.get("ascriptionId"))) {
            sql.inst("and s.ascription_id in ", map.get("ascriptionId").split(","));
        }

        if (StringUtil.checkParamsValid(map.get("ascriptionIds"))) {
            sql.inst("and s.ascription_id in ", map.get("ascriptionIds").split(","));
        }
        if (StringUtil.checkParamsValid(map.get("code"))) {
            sql.like("and m.code like ?", map.get("code").trim());
        }
        if (StringUtil.checkParamsValid(map.get("materialTypeId"))) {
            sql.line("and m.material_type_id=?", map.get("materialTypeId"));
        }
        if (StringUtil.checkParamsValid(map.get("province"))) {
            sql.line("and tr.province=?", map.get("province"));
        }
        if (StringUtil.checkParamsValid(map.get("warehouseIds"))) {
            sql.inst("and s.warehouse_id in", map.get("warehouseIds").split(","));
        }
        if (StringUtil.isNotBlank(map.get("availableStock"))){
            String availableStock = map.get("availableStock");
            if( "1".equals(availableStock)){
                sql.line(" and s.warning > 0 ");
            }else if( "2".equals(availableStock)){
                sql.line(" and s.warning = 0 ");
            }
        }

    }

    /**
     * 根据物料id 获取供应链的物料库存
     */
    public BigDecimal findSupplyWarning(String materielId) {
        return Db.queryBigDecimal("select sum(warning) from crm_supply_material_warehouse_stocks where type = '1' and material_id = ?", materielId);
    }

    /**
     * 根据物料id和归属id 查询物料当前库存
     */
    public BigDecimal findWarningByAscriptionId(String materialId, String ascriptionId) {
        return Db.queryBigDecimal("select sum(s.`warning`) from crm_supply_material_warehouse_stocks s where s.`ascription_id` = ? and s.`material_id` = ?", ascriptionId, materialId);
    }

    /**
     * 占用库存 减少可用数量 增加待出库数量
     */
    public void frozeStock(String materialId, String warehouseId, BigDecimal amount) {
        int row = update("update MaterialWarehouseStocks set warning=warning-:p1, " +
                "frozeOutNum=frozeOutNum+:p2 where materialId=:p3 and warehouseId=:p4 and warning-:p5 >= 0",
                new Parameter(amount, amount, materialId, warehouseId, amount));
        if (row <= 0) {
            SupplyMaterial material = materialDao.get(materialId);
            throw new BusinessException("物料代码【" + material.getCode() + "】可用库存不足");
        }
    }

    /**
     * 仓库打回重新占用库存
     */
    public void reFrozeStock(String materialId, String warehouseId, BigDecimal amount) {
        update("update MaterialWarehouseStocks set warning=warning-:p1, " +
                        "frozeOutNum=frozeOutNum+:p2 where materialId=:p3 and warehouseId=:p4",
                new Parameter(amount, amount, materialId, warehouseId));
    }

    /**
     * 解冻库存 增加可用数量 减少待出库数量
     */
    public void unFrozeStock(String materialId, String warehouseId, BigDecimal amount) {
        int row = update("update MaterialWarehouseStocks set warning=warning+:p1, " +
                        "frozeOutNum=frozeOutNum-:p2 where materialId=:p3 and warehouseId=:p4",
                new Parameter(amount, amount, materialId, warehouseId));
        if (row <= 0) {
            throw new BusinessException("库存释放失败");
        }
    }


    public MaterialWarehouseStocks getByWarehouseId(String warehouseId,String materialId){
        return getByHql("from MaterialWarehouseStocks where materialId = :p1 and warehouseId= :p2 ", new Parameter(materialId,warehouseId));
    }

    /**
     * 物料 在某个仓库的库存信息
     * @return
     */
    public MaterialWarehouseStocks findByWarehouse(String materialId, String warehouseId) {
        return getByHql(" from MaterialWarehouseStocks where materialId=:p1 and warehouseId=:p2", new Parameter(materialId, warehouseId));
    }

    /**
     * 获取库存
     * 根据归属id 仓库id 物料id 获取库存信息
     */
    public MaterialWarehouseStocks getStock(String ascriptionId, String warehouseId, String materialId) {
        return getByHql(" from MaterialWarehouseStocks where ascriptionId=:p1 and warehouseId=:p2 and materialId=:p3", new Parameter(ascriptionId, warehouseId, materialId));
    }

    public BigDecimal getWarning(String warehouseId, String materialId) {
        return Db.queryBigDecimal("SELECT warning FROM crm_supply_material_warehouse_stocks WHERE material_id=? AND warehouse_id=?",materialId,warehouseId);
    }

    /**
     * 电站物料退回仓库库存
     */
    public boolean backStock(String materialId, String warehouseId, BigDecimal amount) {
        StringBuilder sql=new StringBuilder();
        sql.append(" update MaterialWarehouseStocks ")
                .append(" set warning=warning+:p1 ,realNum=realNum+:p2")
                .append(" where warehouseId=:p3 and materialId=:p4");
        int result=  update(sql.toString(),
                new Parameter(amount, amount, warehouseId,materialId));
        return result > 0;
    }

    /**
     * 修改仓库库存信息
     */
    public boolean updateStock(CrmSupplyMaterialDeliverOrderDetail detail, CrmSupplyWarehouse warehouse,SupplyMaterial material) {
        StringBuilder sql=new StringBuilder();
        Date now = new Date();
        sql.append(" update MaterialWarehouseStocks ")
           .append(" set warning=warning+:p1 ,realNum=realNum+:p2,total=total+:p3, newestStorageTime=:p4,costPrice=:p5 ")
           .append("where ascriptionId=:p6 and warehouseId=:p7 and materialId=:p8");
      int result=  update(sql.toString(),
                new Parameter(detail.getInAmount(), detail.getInAmount(), detail.getInAmount(), now,detail.getPurchasePrice(),warehouse.getAscriptionId(), warehouse.getId(),material.getId()));
        return result>0?true:false;
    }

    /**
     * 新增仓库库存
     * @param detail
     * @param warehouse
     * @param material
     * @return
     */
    public MaterialWarehouseStocks saveStock(CrmSupplyMaterialDeliverOrderDetail detail, CrmSupplyWarehouse warehouse,SupplyMaterial material) {
        Date now = new Date();
        // 仓库归属 1.供应链(平台) 2.经销商 3.供应商
        String sType = ("1".equals(warehouse.getType())) ? "1" : ("2".equals(warehouse.getType())?"3":"2");
        MaterialWarehouseStocks stock=new MaterialWarehouseStocks();
        //stock.setId(IdGen.uuid());
        stock.setMaterialId(material.getId());
        stock.setWarehouseId(warehouse.getId());
        stock.setType(sType);
        stock.setAscriptionId(warehouse.getAscriptionId());
        stock.setAscriptionName(warehouse.getAscriptionName());
        stock.setWarning(detail.getInAmount());
        stock.setFrozeOutNum(BigDecimal.ZERO);
        stock.setFrozeInNum(BigDecimal.ZERO);
        stock.setRealNum(detail.getInAmount());
        stock.setTotal(detail.getInAmount());
        stock.setCreateTime(now);
        stock.setNewestStorageTime(now);
        stock.setCostPrice(detail.getPurchasePrice());
        stock.setBdSalePrice(detail.getSalesPrice());
        save(stock);
        return stock;
    }
    public int editAmount(String id,String type,String amount){
        SqlBuilder sqlBuilder=new SqlBuilder();
        sqlBuilder.line("update crm_supply_material_warehouse_stocks ");
        //修改历史数据类型  type 1.累计已发货  2.累计已安装 3.累计已发电 4.累计退货 5.累计买断
        if (type.equals("1")){
            sqlBuilder.line(" set yk_yfh_amount = ?",amount);
        }else if (type.equals("2")){
            sqlBuilder.line(" set yk_yaz_amount = ?",amount);
        }else if (type.equals("3")){
            sqlBuilder.line(" set yk_yfd_amount = ?",amount);
        }else if (type.equals("4")){
            sqlBuilder.line(" set yk_th_amount = ?",amount);
        }else if (type.equals("5")){
            sqlBuilder.line(" set yk_md_amount = ?",amount);
        }
        sqlBuilder.line("where id = ?",id);
        return Db.update(sqlBuilder.build(),sqlBuilder.params());
    }




}
