/*
 * Copyright (c) 京北方信息技术股份有限公司 Corporation 2021 . All rights reserved.
 *
 */
package net.northking.cctp.common.db.tree;

import net.northking.cctp.common.db.OrderBy;
import net.northking.cctp.common.db.SqlOrderBy;
import net.northking.cctp.common.db.entity.EntityService;
import net.northking.cctp.common.exception.ErrorEnum;
import net.northking.cctp.common.exception.PlatformRuntimeException;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;
import org.springframework.util.StringUtils;

import java.util.List;

/**
 * 数据库实体对象服务抽象类
 *
 * @author : xiusong.xie
 * @version : 1.0
 */
public abstract class EntityTreeService<T> extends EntityService<T>
{
  /**
   * 日志
   */
  private final static Logger logger = LoggerFactory.getLogger(EntityTreeService.class);

  public static final int INSERT = 1;
  public static final int UPDATE = 2;

  /**
   * 树根的默认ID
   */
  public static final String TOP_ID = "TOP";

  /**
   * PATH分隔符
   */
  public static final String pathSeparator = "/";

  /**
   * 字段名称：level_no
   */
  private static final String KEY_LevelNo = "level_no";
  /**
   * 字段名称：idx
   */
  private static final String KEY_Idx = "idx";

  @Override
  protected OrderBy defaultOrderBy()
  {
    OrderBy orderBy = new SqlOrderBy();
    orderBy.asc(KEY_LevelNo);
    orderBy.asc(KEY_Idx);
    return orderBy;
  }

  protected void beforeBatchInsert(List<T> list)
  {
    for (T record : list)
    {
      super.beforeInsert(record);
    }
  }

  @Override
  protected void beforeInsert(T record)
  {
    super.beforeInsert(record);
    beforeChange(record, INSERT);
  }

  @Override
  protected void beforeUpdate(T record)
  {
    super.beforeUpdate(record);
    beforeChange(record, UPDATE);
  }

  private void beforeChange(T record, int type)
  {
    if (record instanceof EntityTree)
    {
      _beforeChange((EntityTree) record, type);
    } else
    {
      String err = record.getClass() + " is not implements EntityTree";
      throw new ClassCastException(err);
    }
  }

  private void _beforeChange(EntityTree entity, int type)
  {
    if (INSERT == type)
    {
      beforeAddTreeNode(entity);
    } else if (UPDATE == type)
    {
      beforeUpdateTree(entity);
    }
  }

  private void beforeAddTreeNode(EntityTree entity)
  {
    entity.setLeaf(true);
    if (entity.getIdx() == null)
    {
      entity.setIdx(100);
    }
    String parentId = entity.getParentId();
    if (StringUtils.hasText(parentId) && !TOP_ID.equals(parentId))
    {
      EntityTree parent = (EntityTree) findByPrimaryKey(parentId);
      if (parent == null)
      {
        throw new PlatformRuntimeException(ErrorEnum.TREE_PARENT_NOT_EXIST, entity.getId(), entity.getParentId());
      }
      entity.setLevelNo(parent.getLevelNo() + 1);
      entity.setPath(parent.getPath() + pathSeparator + entity.getId());
      updateLeafFalse(parent.getId());
    } else
    {
      entity.setParentId(TOP_ID);
      entity.setLevelNo(1);
      entity.setPath(pathSeparator + entity.getId());
    }
  }

  /**
   * 更新、插入操作时，把上级节点的是否叶子属性改为 true
   *
   * @param pk 上级节点ID
   */
  private void updateLeafFalse(String pk)
  {
    EntityTree updateLeaf = createEntityTree();
    updateLeaf.setLeaf(false);
    updateLeaf.setId(pk);
    int count = getDao().updateByPrimaryKey((T) updateLeaf);
    if (count != 1)
    {
      StringBuilder err = new StringBuilder();
      err.append("更新 树形关系实体：").append(updateLeaf.getClass()).append(" ");
      err.append("设置 leaf=false , 主键ID=").append(pk).append("   失败！");
      logger.error("");
    }
  }

  /**
   * 迁移（更新上级节点）操作时，更新原上级节点的是否叶子属性
   *
   * @param entity 当前节点
   */
  private void beforeUpdateTree(EntityTree entity)
  {
    if (StringUtils.hasText(entity.getParentId()))
    {
      T old = getDao().findByPrimaryKey(entity.getId());
      String oldParentId = ((EntityTree) old).getParentId();
      if (!oldParentId.equals(entity.getParentId()))
      {// 上级节点发生变化，迁移操作
        migrate(entity, (EntityTree) old);
      }
    }
  }

  /**
   * 节点迁移，更新所有子孙节点
   *
   * @param entity 新节点
   * @param old    原节点
   */
  private void migrate(EntityTree entity, EntityTree old)
  {
    if (TOP_ID.equals(entity.getParentId()))
    {// 迁移至顶级节点
      entity.setLevelNo(1);
      entity.setPath(pathSeparator + entity.getId());
    } else
    {
      T newParent = getDao().findByPrimaryKey(entity.getParentId());
      if (newParent == null)
      {
        throw new PlatformRuntimeException(ErrorEnum.TREE_PARENT_NOT_EXIST);
      }
      entity.setLevelNo(((EntityTree) newParent).getLevelNo() + 1);
      entity.setPath(((EntityTree) newParent).getPath() + pathSeparator + entity.getId());
    }
    // 递归迁移下级节点
    this.migrateChildren(entity);
  }

  /**
   * 迁移下级节点
   *
   * @param entity 节点
   */
  private void migrateChildren(EntityTree entity)
  {
    EntityTree example = createEntityTree();
    example.setParentId(entity.getId());
    List<T> children = this.query((T) example);
    for (T child : children)
    {
      EntityTree childNode = (EntityTree) child;
      EntityTree childUpdateExam = createEntityTree();
      childUpdateExam.setId(childNode.getId());
      childUpdateExam.setLevelNo(entity.getLevelNo() + 1);
      childUpdateExam.setPath(entity.getParentId() + pathSeparator + childNode.getId());
      this.updateByPrimaryKey((T) childUpdateExam);
      migrateChildren(childNode);
    }

  }


  protected EntityTree createEntityTree()
  {
    return (EntityTree) createEntity();
  }

}
