package jnpf.authority.controller;

import cn.hutool.core.bean.BeanUtil;
import io.swagger.v3.oas.annotations.Operation;
import jnpf.authority.service.FtbPermissionOrganizeService;
import jnpf.authority.utils.PermissionsApplicableObject;
import jnpf.base.ActionResult;
import jnpf.base.UserInfo;
import jnpf.config.ConfigValueUtil;
import jnpf.database.util.TenantDataSourceUtil;
import jnpf.exception.LoginException;
import jnpf.permission.dto.v2.organzie.QueryOrganizeNodeDTO;
import jnpf.permission.eum.v2.NodeTypeEnum;
import jnpf.permission.eum.v2.OrganizeCategoryEnums;
import jnpf.permission.eum.v2.UserWorkStatusEnums;
import jnpf.permission.vo.store.StoreBaseListInfo;
import jnpf.permission.vo.v2.TargetAuthIdsVO;
import jnpf.permission.vo.v2.organzie.OrganizeGeneralDetailVO;
import jnpf.permission.vo.v2.organzie.OrganizeManagerFilterNodeVO;
import jnpf.permission.vo.v2.organzie.OrganizeManagerNodeVO;
import jnpf.util.NoDataSourceBind;
import jnpf.util.StringUtil;
import jnpf.util.UserProvider;
import jnpf.util.data.DataSourceContextHolder;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.util.Assert;
import org.springframework.web.bind.annotation.*;

import javax.annotation.Resource;
import javax.servlet.http.HttpServletRequest;
import java.util.ArrayList;
import java.util.List;
import java.util.Map;

/**
 * 带权限的组织管理功能接口
 *
 * @author Flynn Chan
 * @create 2025-05-06
 */
@RestController
@RequestMapping("/permission/organize")
@Slf4j
public class FtbPermissionOrganizeController {

    @Resource
    private FtbPermissionOrganizeService ftbPermissionOrganizeService;

    @Autowired
    private ConfigValueUtil configValueUtil;

    @Operation(summary = "[树形全]组织(公司,部门,门店,班主)+组织下的人[含人事离职的人]")
    @PostMapping(value = "/tree/user")
    public ActionResult<List<OrganizeManagerNodeVO>> allOrganizeUsersTree(@RequestBody QueryOrganizeNodeDTO dto) {
        return ActionResult.success(ftbPermissionOrganizeService.allOrganizeUsersTree(dto));
    }

    @Operation(summary = "[树形]人员权限过滤后的组织(公司,部门,门店,班主),人员")
    @GetMapping(value = "/tree/users")
    public ActionResult<List<OrganizeManagerNodeVO>> listOrganizeTreeUsers(@RequestParam(value = "organizeCategoryEnums", required = false) List<OrganizeCategoryEnums> organizeCategoryEnums,
                                                                           @RequestParam(value = "workStatusEnums", required = false) List<UserWorkStatusEnums> workStatusEnums,
                                                                           @RequestParam(value = "organizeKeyword", required = false) String organizeKeyword,
                                                                           //是否包含人员
                                                                           @RequestParam(value = "withEmployee", required = false) Boolean withEmployee,
                                                                           @RequestParam(value = "includeResigned", required = false) Boolean includeResigned,
                                                                           HttpServletRequest request) {
        //默认包含人员
        if (withEmployee == null) {
            withEmployee = Boolean.TRUE;
        }
        //默认不包含离职人员
        if (includeResigned == null) {
            includeResigned = Boolean.FALSE;
        }

        List<OrganizeManagerNodeVO> result = ftbPermissionOrganizeService.listOrganizeTreeUsers(organizeCategoryEnums, workStatusEnums, organizeKeyword, withEmployee, includeResigned);

        // 判断是否为原生端请求
        String clientType = request.getHeader("clientType");
        boolean isNativeClient = StringUtil.isNotEmpty(clientType) &&
                ("android".equalsIgnoreCase(clientType) || "ios".equalsIgnoreCase(clientType));

        // 如果是原生端请求，过滤掉子组织不含门店的父级组织
        if (isNativeClient) {
            result = filterOrganizesWithoutStore(result);
        }

        return ActionResult.success(result);
    }

    /**
     * @param organizeCategoryEnums 组织类型
     * @param workStatusEnums       工作状态
     * @param withEmployee          包含人员
     * @param filterBindOtherStore  过滤绑定第三方信息门店
     * @param filterBindPayStore    过滤收银平台门店
     * @return 组织树(with auth)
     */
    @Operation(summary = "[树形,滤掉没有的分支]人员权限过滤后的组织(公司,部门,门店,班主),人员")
    @GetMapping(value = "/tree/users/filterNode")
    public ActionResult<List<OrganizeManagerFilterNodeVO>> listOrganizeTreeUsersFilterNodeJson(
            @RequestParam(value = "organizeCategoryEnums", required = false) List<OrganizeCategoryEnums> organizeCategoryEnums,
            @RequestParam(value = "workStatusEnums", required = false) List<UserWorkStatusEnums> workStatusEnums,
            @RequestParam(value = "withEmployee", required = false) Boolean withEmployee,
            @RequestParam(value = "filterBindOtherStore", required = false) Boolean filterBindOtherStore,
            @RequestParam(value = "filterBindPayStore", required = false) Boolean filterBindPayStore
    ) {
        withEmployee = withEmployee == null ? Boolean.TRUE : withEmployee;
        filterBindOtherStore = filterBindOtherStore == null ? Boolean.FALSE : filterBindOtherStore;
        filterBindPayStore = filterBindPayStore == null ? Boolean.FALSE : filterBindPayStore;
        return ActionResult.success(ftbPermissionOrganizeService.
                listOrganizeTreeUsersFilterNodeJson(
                        organizeCategoryEnums,
                        workStatusEnums,
                        withEmployee,
                        filterBindOtherStore,
                        filterBindPayStore
                ));
    }

    /**
     * @param organizeCategoryEnums 组织类型
     * @param workStatusEnums       工作状态
     * @param withEmployee          是否包含人员
     * @param filterBindOtherStore  过滤绑定第三方信息门店
     * @param filterBindPayStore    过滤收银平台门店
     * @return 组织树(with auth)
     */
    @Operation(summary = "[api树形,滤掉没有的分支]人员权限过滤后的组织(公司,部门,门店,班主),默认不带人员")
    @GetMapping(value = "/api/tree/users/filterNode")
    public List<OrganizeManagerFilterNodeVO> listOrganizeTreeFilterNode(
            @RequestParam(value = "organizeCategoryEnums", required = false) List<OrganizeCategoryEnums> organizeCategoryEnums,
            @RequestParam(value = "workStatusEnums", required = false) List<UserWorkStatusEnums> workStatusEnums,
            @RequestParam(value = "withEmployee", required = false) Boolean withEmployee,
            @RequestParam(value = "filterBindOtherStore", required = false) Boolean filterBindOtherStore,
            @RequestParam(value = "filterBindPayStore", required = false) Boolean filterBindPayStore
    ) {
        withEmployee = withEmployee == null ? Boolean.FALSE : withEmployee;
        filterBindOtherStore = filterBindOtherStore == null ? Boolean.FALSE : filterBindOtherStore;
        filterBindPayStore = filterBindPayStore == null ? Boolean.FALSE : filterBindPayStore;
        return ftbPermissionOrganizeService.
                listOrganizeTreeUsersFilterNodeJson(
                        organizeCategoryEnums,
                        workStatusEnums,
                        withEmployee,
                        filterBindOtherStore,
                        filterBindPayStore
                );
    }

    /**
     * @param organizeCategoryEnums 组织类型
     * @param organizeKeyword       关键词
     * @param filterBindOtherStore  过滤绑定第三方信息门店
     * @param filterBindPayStore    过滤收银平台门店
     * @return 组织列表(with auth)
     */
    @Operation(summary = "[列表]人员权限过滤后的组织列表")
    @GetMapping(value = "/info/list/users")
    @NoDataSourceBind
    public ActionResult<List<OrganizeGeneralDetailVO>> authOrganizesByUserBound(
            @RequestParam(value = "organizeCategoryEnums", required = false) List<OrganizeCategoryEnums> organizeCategoryEnums,
            @RequestParam(value = "organizeKeyword", required = false) String organizeKeyword,
            @RequestParam(value = "filterBindOtherStore", required = false) Boolean filterBindOtherStore,
            @RequestParam(value = "filterBindPayStore", required = false) Boolean filterBindPayStore
    ) {
        filterBindOtherStore = filterBindOtherStore == null ? Boolean.FALSE : filterBindOtherStore;
        filterBindPayStore = filterBindPayStore == null ? Boolean.FALSE : filterBindPayStore;
        return ActionResult.success(ftbPermissionOrganizeService.
                authOrganizesByUserBound(
                        organizeCategoryEnums,
                        organizeKeyword,
                        filterBindOtherStore,
                        filterBindPayStore
                )
        );
    }

    @GetMapping(value = "/user-auth")
    public TargetAuthIdsVO getUserAuth() {

        return ftbPermissionOrganizeService.getUserAuth();
    }

    /**
     * @param userIds 用户列表
     * @param status  状态 1：禁用 0：启用 -1-所有
     * @return
     */
    @Operation(summary = "[列表]根据用户id批量查询权限范围内的门店")
    @PostMapping(value = "/batchForUserIds/{status}")
    public Map<String, List<String>> batchAuthOrganizesForUserIds(@RequestBody List<String> userIds, @PathVariable("status") Integer status) {
        return ftbPermissionOrganizeService.batchAuthOrganizesForUserIds(userIds, status);
    }


    @Operation(summary = "[列表]根据用户列表批量查询权限范围的门店")
    @PostMapping(value = "/batchForUserIds/{status}/{moduleId}/{tenantId}")
    @NoDataSourceBind
    Map<String, List<String>> batchAuthOrganizesForUserIdsAndTenantId(@RequestBody List<String> userIds, @PathVariable("status") Integer status, @PathVariable("moduleId") String moduleId, @PathVariable("tenantId") String tenantId) {
        checkOutTenant(tenantId);
        return ftbPermissionOrganizeService.batchAuthOrganizesForUserIdsAndTenantId(userIds, status, moduleId, tenantId);
    }
    @Operation(summary = "[列表]根据用户列表批量查询权限范围的组织及门店")
    @PostMapping(value = "/batchAllForUserIds/{status}/{moduleId}/{tenantId}")
    @NoDataSourceBind
    Map<String, List<String>> batchAuthOrganizesAllForUserIdsAndTenantId(@RequestBody List<String> userIds, @PathVariable("status") Integer status, @PathVariable("moduleId") String moduleId, @PathVariable("tenantId") String tenantId) {
        checkOutTenant(tenantId);
        return ftbPermissionOrganizeService.batchAuthOrganizesAllForUserIdsAndTenantId(userIds, status, moduleId, tenantId);
    }
    /**
     * 批量查询权限范围组织及门店
     */
    @Operation(summary = "[列表]根据用户列表批量查询权限范围组织及门店")
    @PostMapping(value = "/batchAllForUserIds")
    public  Map<String, PermissionsApplicableObject> batchAuthOrganizesAllForUserIds(@RequestBody List<String> userIds) {
        return ftbPermissionOrganizeService.batchAuthOrganizesAllForUserIds(userIds);
    }


    /**
     * api
     **/
    @Operation(summary = "[门店基础信息列表auth api] 根据登录人权限得到权限范围内门店基础信息")
    @GetMapping(value = "/list/store/login")
    public List<StoreBaseListInfo> authStoreBaseListInfo() {
        return ftbPermissionOrganizeService.authStoreBaseListInfo();
    }

    /**
     * 过滤掉子组织不含门店的父级组织（仅用于原生端）
     *
     * @param organizeList 组织树列表
     * @return 过滤后的组织树列表
     */
    private List<OrganizeManagerNodeVO> filterOrganizesWithoutStore(List<OrganizeManagerNodeVO> organizeList) {
        if (organizeList == null || organizeList.isEmpty()) {
            return organizeList;
        }

        List<OrganizeManagerNodeVO> filteredList = new ArrayList<>();
        for (OrganizeManagerNodeVO organize : organizeList) {
            // 递归检查该组织及其子组织是否包含门店
            if (hasStoreInChildren(organize)) {
                // 如果包含门店，保留该组织，但需要递归过滤其子组织
                OrganizeManagerNodeVO filteredOrganize = new OrganizeManagerNodeVO();
                // 复制组织的基本属性
                copyOrganizeProperties(organize, filteredOrganize);
                // 递归过滤子组织
                if (organize.getChildren() != null && !organize.getChildren().isEmpty()) {
                    filteredOrganize.setChildren(filterOrganizesWithoutStore(organize.getChildren()));
                }
                filteredList.add(filteredOrganize);
            }
            // 如果不包含门店，则过滤掉该组织及其所有子组织
        }
        return filteredList;
    }

    /**
     * 递归检查组织及其子组织是否包含门店
     *
     * @param organize 组织节点
     * @return 如果包含门店返回true，否则返回false
     */
    private boolean hasStoreInChildren(OrganizeManagerNodeVO organize) {
        if (organize == null) {
            return false;
        }

        // 如果当前节点是门店，直接返回true
        if (organize.getNodeTypeEnum() != null && NodeTypeEnum.STORE.equals(organize.getNodeTypeEnum())) {
            return true;
        }

        // 如果当前节点是用户或其他非组织类型，返回false（用户节点不参与门店判断）
        if (organize.getNodeTypeEnum() != null &&
                (NodeTypeEnum.USER.equals(organize.getNodeTypeEnum()) ||
                        NodeTypeEnum.POSITION.equals(organize.getNodeTypeEnum()))) {
            return false;
        }

        // 递归检查子组织
        if (organize.getChildren() != null && !organize.getChildren().isEmpty()) {
            for (OrganizeManagerNodeVO child : organize.getChildren()) {
                if (hasStoreInChildren(child)) {
                    return true;
                }
            }
        }

        return false;
    }

    /**
     * 复制组织的基本属性（不包含children）
     *
     * @param source 源组织
     * @param target 目标组织
     */
    private void copyOrganizeProperties(OrganizeManagerNodeVO source, OrganizeManagerNodeVO target) {
        // 使用 BeanUtil 复制属性，但排除 children 字段
        BeanUtil.copyProperties(source, target, "children");
    }

    /**
     * 根据租户ID检查或切换数据库连接
     *
     * @param tenantId 租户ID
     */
    public void checkOutTenant(String tenantId) {
        // 判断是否启用了多租户功能
        if (configValueUtil.isMultiTenancy()) {
            // 判断是不是从外面直接请求
            if (StringUtil.isNotEmpty(tenantId)) {
                // 切换成租户库
                try {
                    TenantDataSourceUtil.switchTenant(tenantId);
                } catch (LoginException e) {
                    throw new RuntimeException("切换租户失败");
                }
            } else {
                // 获取当前用户信息
                UserInfo userInfo = UserProvider.getUser();
                Assert.notNull(userInfo.getUserId(), "缺少租户信息");
                // 设置数据库连接信息
                DataSourceContextHolder.setDatasource(userInfo.getTenantId(), userInfo.getTenantDbConnectionString(), userInfo.isAssignDataSource());
            }
        }
    }
}
