package com.ruoyi.system.service;

import cn.hutool.core.collection.CollectionUtil;
import com.ruoyi.common.core.domain.entity.SysDept;
import com.ruoyi.common.utils.ConvertUtils;
import com.ruoyi.common.utils.StringUtils;
import com.ruoyi.common.utils.spring.SpringUtils;

import java.util.LinkedHashMap;
import java.util.List;
import java.util.Map;
import java.util.function.BiConsumer;
import java.util.function.Function;

// 部门助手
public class DeptHelper
{
    private Map<String, SysDept> byOrgCodeCache;
    private Map<Long, SysDept> byDeptIdCache;

    private final ISysDeptService      sysDeptService;

    public DeptHelper()
    {
        this(GetDeptService());
    }

    public DeptHelper(ISysDeptService deptService)
    {
        sysDeptService = deptService;
    }

    private static ISysDeptService GetDeptService()
    {
        return SpringUtils.getBean(com.ruoyi.system.service.ISysDeptService.class);
    }

    public static <T> void SetupFullDeptNameByOrgCode(T obj, Function<T, String> getOrgCodeFunc, BiConsumer<T, String> setDeptNameFunc)
    {
        SetupFullDeptNameByOrgCode(GetDeptService(), obj, getOrgCodeFunc, setDeptNameFunc);
    }

    public static <T> void SetupFullDeptNameByDeptId(T obj, Function<T, Long> getDeptIdFunc, BiConsumer<T, String> setDeptNameFunc)
    {
        SetupFullDeptNameByDeptId(GetDeptService(), obj, getDeptIdFunc, setDeptNameFunc);
    }

    public static <T> void SetupFullDeptNameByOrgCode(List<T> list, Function<T, String> getOrgCodeFunc, BiConsumer<T, String> setDeptNameFunc)
    {
        SetupFullDeptNameByOrgCode(GetDeptService(), list, getOrgCodeFunc, setDeptNameFunc);
    }

    public static <T> void SetupFullDeptNameByDeptId(List<T> list, Function<T, Long> getDeptIdFunc, BiConsumer<T, String> setDeptNameFunc)
    {
        SetupFullDeptNameByDeptId(GetDeptService(), list, getDeptIdFunc, setDeptNameFunc);
    }

    public static <T> void SetupFullDeptNameByOrgCode(ISysDeptService deptService, T obj, Function<T, String> getOrgCodeFunc, BiConsumer<T, String> setDeptNameFunc)
    {
        new DeptHelper(deptService).HandleByOrgCode(obj, getOrgCodeFunc, (x, dept) -> {
            setDeptNameFunc.accept(x, GenDeptName(dept));
        });
    }

    public static <T> void SetupFullDeptNameByDeptId(ISysDeptService deptService, T obj, Function<T, Long> getDeptIdFunc, BiConsumer<T, String> setDeptNameFunc)
    {
        new DeptHelper(deptService).HandleByDeptId(obj, getDeptIdFunc, (x, dept) -> {
            setDeptNameFunc.accept(x, GenDeptName(dept));
        });
    }

    public static <T> void SetupFullDeptNameByOrgCode(ISysDeptService deptService, List<T> list, Function<T, String> getOrgCodeFunc, BiConsumer<T, String> setDeptNameFunc)
    {
        new DeptHelper(deptService).HandleByOrgCode(list, getOrgCodeFunc, (x, dept) -> {
            setDeptNameFunc.accept(x, GenDeptName(dept));
        });
    }

    public static <T> void SetupFullDeptNameByDeptId(ISysDeptService deptService, List<T> list, Function<T, Long> getDeptIdFunc, BiConsumer<T, String> setDeptNameFunc)
    {
        new DeptHelper(deptService).HandleByDeptId(list, getDeptIdFunc, (x, dept) -> {
            setDeptNameFunc.accept(x, GenDeptName(dept));
        });
    }

    public <T> void HandleByOrgCode(List<T> list, Function<T, String> getOrgCodeFunc, BiConsumer<T, SysDept> handler)
    {
        if(CollectionUtil.isEmpty(list))
            return;
        list.forEach((x) -> HandleByOrgCode(x, getOrgCodeFunc, handler));
    }

    public <T> void HandleByDeptId(List<T> list, Function<T, Long> getDeptIdFunc, BiConsumer<T, SysDept> handler)
    {
        if(CollectionUtil.isEmpty(list))
            return;
        list.forEach((x) -> HandleByDeptId(x, getDeptIdFunc, handler));
    }

    public <T> void HandleByOrgCode(T obj, Function<T, String> getOrgCodeFunc, BiConsumer<T, SysDept> handler)
    {
        if(null == obj)
            return;
        String orgCode = getOrgCodeFunc.apply(obj);
        SysDept dept = GetDept(orgCode);
        if(null != dept)
            handler.accept(obj, dept);
    }

    public <T> void HandleByDeptId(T obj, Function<T, Long> getDeptIdFunc, BiConsumer<T, SysDept> handler)
    {
        if(null == obj)
            return;
        Long deptId = getDeptIdFunc.apply(obj);
        SysDept dept = GetDept(deptId);
        if(null != dept)
            handler.accept(obj, dept);
    }

    public SysDept GetDept(String orgCode)
    {
        if(StringUtils.isEmpty(orgCode))
            return null;
        SysDept dept = FindDept(orgCode);
        if(null != dept)
            return dept;
        dept = LoadDept(orgCode);
        AddCache(dept);
        return dept;
    }

    public SysDept GetDept(Long deptId)
    {
        if(null == deptId)
            return null;
        SysDept dept = FindDept(deptId);
        if(null != dept)
            return dept;
        dept = LoadDept(deptId);
        AddCache(dept);
        return dept;
    }

    private void AddCache(SysDept dept)
    {
        if(null == dept)
            return;
        if(null == FindDept(dept.getDeptId()))
        {
            ByDeptIdCache().put(dept.getDeptId(), dept);
            ByOrgCodeCache().put(dept.getOrgCode(), dept);
        }
    }

    private Map<String, SysDept> ByOrgCodeCache()
    {
        if(null == byOrgCodeCache)
            byOrgCodeCache = new LinkedHashMap<>();
        return byOrgCodeCache;
    }

    private Map<Long, SysDept> ByDeptIdCache()
    {
        if(null == byDeptIdCache)
            byDeptIdCache = new LinkedHashMap<>();
        return byDeptIdCache;
    }

    private SysDept FindDept(String orgCode)
    {
        if(null == byOrgCodeCache)
            return null;
        return byOrgCodeCache.get(orgCode);
    }

    private SysDept FindDept(Long deptId)
    {
        if(null == byDeptIdCache)
            return null;
        return byDeptIdCache.get(deptId);
    }

    private SysDept LoadDept(String orgCode)
    {
        return sysDeptService.selectDeptByOrgCode(orgCode);
    }

    private SysDept LoadDept(Long deptId)
    {
        return sysDeptService.selectDeptById(deptId);
    }

    public static String GenDeptName(SysDept dept)
    {
        if(null == dept)
            return "";
        return ConvertUtils.toString_s(dept.getParentName()) + dept.getDeptName();
    }
}
