/**
 * Copyright (c) 2018-2099, Chill Zhuang 庄骞 (bladejava@qq.com).
 * <p>
 * Licensed under the GNU LESSER GENERAL PUBLIC LICENSE 3.0;
 * you may not use this file except in compliance with the License.
 * You may obtain a copy of the License at
 * <p>
 * http://www.gnu.org/licenses/lgpl.html
 * <p>
 * Unless required by applicable law or agreed to in writing, software
 * distributed under the License is distributed on an "AS IS" BASIS,
 * WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
 * See the License for the specific language governing permissions and
 * limitations under the License.
 */
package com.xiaoniu.subsystem.system.controller;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.github.xiaoymin.knife4j.annotations.ApiOperationSupport;
import com.xiaoniu.common.core.result.R;
import com.xiaoniu.common.core.utils.BeanUtil;
import com.xiaoniu.common.core.utils.DateUtils;
import com.xiaoniu.common.core.utils.StringUtils;
import com.xiaoniu.common.core.utils.poi.ExcelUtil;
import com.xiaoniu.common.log.annotation.Log;
import com.xiaoniu.common.log.enums.BusinessType;
import com.xiaoniu.common.security.utils.SecurityUtils;
import com.xiaoniu.subsystem.system.domain.Record;
import com.xiaoniu.subsystem.system.domain.*;
import com.xiaoniu.subsystem.system.domain.dto.UnitPageDTO;
import com.xiaoniu.subsystem.system.domain.dto.UnitSaveDTO;
import com.xiaoniu.subsystem.system.domain.dto.UnitUpdateDTO;
import com.xiaoniu.subsystem.system.domain.vo.*;
import com.xiaoniu.subsystem.system.service.ISysRoleService;
import com.xiaoniu.subsystem.system.service.ISysUserRoleService;
import com.xiaoniu.subsystem.system.service.ISysUserService;
import com.xiaoniu.subsystem.system.service.IUnitService;
import com.xiaoniu.subsystem.system.utils.MobileNumberValidator;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletResponse;
import jakarta.validation.Valid;
import jakarta.validation.constraints.NotBlank;
import lombok.AllArgsConstructor;
import org.apache.commons.collections4.CollectionUtils;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;

import javax.xml.bind.JAXBContext;
import javax.xml.bind.Unmarshaller;
import java.util.*;
import java.util.stream.Collectors;

import static com.xiaoniu.common.security.utils.SecurityUtils.getUnitId;
import static com.xiaoniu.common.security.utils.SecurityUtils.getUserId;

/**
 * 单位管理表 控制器
 *
 * @author sst
 * @since 2024-11-26
 */
@RestController
@AllArgsConstructor
@RequestMapping("/unit")
@Tag(name = "单位管理表", description = "单位管理表接口")
public class UnitController {

    private IUnitService unitService;
    private ISysRoleService sysRoleService;
    private ISysUserService sysUserService;
    private ISysUserRoleService sysUserRoleService;

    /**
     * 详情
     */
    @GetMapping("/detail")
    @ApiOperationSupport(order = 1)
    @Operation(summary = "详情", description = "传入unit")
    public R<UnitVO> detail(@Parameter(description = "主键", required = true) @RequestParam Long unitId) {
        Unit detail = unitService.getById(unitId);
        return R.data(BeanUtil.copy(detail, UnitVO.class));
    }

    /**
     * 分页 单位管理表
     */
    @GetMapping("/list")
    @ApiOperationSupport(order = 2)
    @Operation(summary = "分页", description = "传入unit")
    public R<IPage<UnitVO>> list(@Validated UnitPageDTO dto) {
        List<Long> ids = new ArrayList<>();
        if (StringUtils.equals("0", dto.getType())) {
            ids.add(null != dto.getParentId() ? dto.getParentId() : getUnitId());
            List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                    .eq(null != dto.getParentId(), Unit::getParentId, dto.getParentId())
                    .eq(null == dto.getParentId(), Unit::getParentId, getUnitId()));
            if (CollectionUtils.isNotEmpty(units)) {
                List<Long> longs = units.stream().map(Unit::getUnitId).toList();
                ids.addAll(longs);
                List<Unit> list = unitService.list(new LambdaQueryWrapper<Unit>()
                        .in(Unit::getParentId, longs));
                setUnit(list, ids);
            }
        }
        IPage<Unit> pages = unitService.page(new Page<>(dto.getPageNum(), dto.getPageSize()),
                new LambdaQueryWrapper<Unit>()
                        .orderByDesc(Unit::getCreateTime)
                        .eq(Unit::getType, dto.getType())
                        .like(StringUtils.isNotBlank(dto.getUnitName()), Unit::getUnitName, dto.getUnitName())
                        // .eq(null != dto.getParentId(), Unit::getParentId, dto.getParentId())
                        .in(CollectionUtils.isNotEmpty(dto.getParentIds()), Unit::getParentId, dto.getParentIds())
                        .in(CollectionUtils.isNotEmpty(ids), Unit::getUnitId, ids)
                        .like(StringUtils.isNotBlank(dto.getUnitCode()), Unit::getUnitCode, dto.getUnitCode())
                        .like(StringUtils.isNotBlank(dto.getContactPerson()), Unit::getContactPerson, dto.getContactPerson())
                        .like(StringUtils.isNotBlank(dto.getUnitDesignation()), Unit::getUnitDesignation, dto.getUnitDesignation()));
        return R.data(BeanUtil.copy(pages, UnitVO.class));
    }

    /**
     * 导出
     */
    @GetMapping("/export")
    @ApiOperationSupport(order = 3)
    @Log(title = "单位管理导出", businessType = BusinessType.EXPORT)
    @Operation(summary = "导出", description = "传入ids")
    public void export(HttpServletResponse response, @Validated UnitPageDTO dto) {
        List<Unit> list = new ArrayList<>();
        if (StringUtils.isNotBlank(dto.getIds())) {
            list.addAll(unitService.list(new LambdaQueryWrapper<Unit>()
                    .orderByDesc(Unit::getCreateTime)
                    .in(StringUtils.isNotBlank(dto.getIds()), Unit::getUnitId,
                            Arrays.stream(dto.getIds().split(",")).toList())));
        } else {
            List<Long> ids = new ArrayList<>();
            if (0 != getUnitId() && StringUtils.equals("0", dto.getType())
                    && null == dto.getParentId()) {
                ids.add(getUnitId());
                List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                        .eq(Unit::getParentId, getUnitId()));
                if (CollectionUtils.isNotEmpty(units)) {
                    List<Long> longs = units.stream().map(Unit::getUnitId).toList();
                    ids.addAll(longs);
                    List<Unit> list1 = unitService.list(new LambdaQueryWrapper<Unit>()
                            .in(Unit::getParentId, longs));
                    setUnit(list1, ids);
                }
            }
            if (null != dto.getParentId()) {
                ids.add(dto.getParentId());
                List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                        .eq(Unit::getParentId, dto.getParentId()));
                if (CollectionUtils.isNotEmpty(units)) {
                    List<Long> longs = units.stream().map(Unit::getUnitId).toList();
                    ids.addAll(longs);
                    List<Unit> list1 = unitService.list(new LambdaQueryWrapper<Unit>()
                            .in(Unit::getParentId, longs));
                    setUnit(list1, ids);
                }
            }
            list.addAll(unitService.list(new LambdaQueryWrapper<Unit>()
                    .orderByDesc(Unit::getCreateTime)
                    .eq(Unit::getType, dto.getType())
                    .like(StringUtils.isNotBlank(dto.getUnitName()), Unit::getUnitName, dto.getUnitName())
                    .in(CollectionUtils.isNotEmpty(dto.getParentIds()), Unit::getParentId, dto.getParentIds())
                    .in(CollectionUtils.isNotEmpty(ids), Unit::getUnitId, ids)
                    // .eq(null != dto.getParentId(), Unit::getParentId, dto.getParentId())
                    .like(StringUtils.isNotBlank(dto.getUnitCode()), Unit::getUnitCode, dto.getUnitCode())
                    .like(StringUtils.isNotBlank(dto.getContactPerson()), Unit::getContactPerson, dto.getContactPerson())
                    .like(StringUtils.isNotBlank(dto.getUnitDesignation()),
                            Unit::getUnitDesignation, dto.getUnitDesignation())));
        }
        if (StringUtils.equals("0", dto.getType())) {
            ExcelUtil<UnitExportNewVO> excelUtil = new ExcelUtil<>(UnitExportNewVO.class);
            excelUtil.exportExcel(response, BeanUtil.copy(list, UnitExportNewVO.class), "机关单位管理数据");
        } else {
            ExcelUtil<UnitExportVO> excelUtil = new ExcelUtil<>(UnitExportVO.class);
            excelUtil.exportExcel(response, BeanUtil.copy(list, UnitExportVO.class), "承训单位管理数据");
        }

    }

    /**
     * 新增 单位管理表
     */
    @PostMapping("/save")
    @ApiOperationSupport(order = 4)
    @Operation(summary = "新增", description = "传入unit")
    public R save(@Valid @RequestBody UnitSaveDTO dto) {
        if (StringUtils.isNotBlank(dto.getPhone())
                && !MobileNumberValidator.isValidPhoneNumber(dto.getPhone())) {
            return R.fail("电话号码有误：" + dto.getPhone() + "，请核对");
        }
        long count = unitService.count(new LambdaQueryWrapper<Unit>().eq(Unit::getUnitName, dto.getUnitName())
                .eq(StringUtils.isNotBlank(dto.getType()), Unit::getType, dto.getType())
                .eq(StringUtils.isNotBlank(dto.getUnitName()), Unit::getUnitName, dto.getUnitName()));
        if (count > 0) {
            return R.fail("单位名称已存在");
        }
        Unit copy = BeanUtil.copy(dto, Unit.class)
                .setCreateDept(getUnitId()).setCreateUser(getUserId()).setCreateTime(new Date());
        unitService.save(copy);
        return R.data(copy.getUnitId());
    }

    /**
     * 修改 单位管理表
     */
    @PostMapping("/update")
    @ApiOperationSupport(order = 5)
    @Operation(summary = "修改", description = "传入unit")
    public R update(@Valid @RequestBody UnitUpdateDTO dto) {
        if (StringUtils.isNotBlank(dto.getPhone())
                && !MobileNumberValidator.isValidPhoneNumber(dto.getPhone())) {
            return R.fail("电话号码有误：" + dto.getPhone() + "，请核对");
        }
        long count = unitService.count(new LambdaQueryWrapper<Unit>()
                .eq(StringUtils.isNotBlank(dto.getUnitName()), Unit::getUnitName, dto.getUnitName())
                .eq(StringUtils.isNotBlank(dto.getType()), Unit::getType, dto.getType())
                .ne(Unit::getUnitId, dto.getUnitId()));
        if (count > 0) {
            return R.fail("单位名称已存在");
        }
        return R.status(unitService.updateById(Objects.requireNonNull(BeanUtil.copy(dto, Unit.class))
                .setUpdateUser(getUserId()).setUpdateTime(new Date())));
    }

    /**
     * 删除 单位管理表
     */
    @PostMapping("/remove")
    @ApiOperationSupport(order = 7)
    @Operation(summary = "删除", description = "传入ids")
    public R remove(@Parameter(description = "主键集合", required = true) @RequestParam String unitIds) {
        List<SysUser> list = sysUserService.list(new LambdaQueryWrapper<SysUser>()
                .ne(SysUser::getDelFlag, 2)
                .in(SysUser::getUnitId, Arrays.stream(unitIds.split(",")).toList()));
        if (CollectionUtils.isNotEmpty(list)) {
            return R.fail("所选单位包含有用户账号，请先删除用户账号");
        }
        return R.status(unitService.removeByIds(Arrays.stream(unitIds.split(",")).toList()));
    }

    /**
     * 单位列表树形结构
     */
    @GetMapping("/unitTreeList")
    @ApiOperationSupport(order = 8)
    @Operation(summary = "单位列表树形结构")
    public R<List<UnitTreeNewListVO>> unitTreeList(@Parameter(description = "单位名称")
                                                   @RequestParam(required = false) String unitName,
                                                   @NotBlank(message = "类型不能为空")
                                                   @Parameter(description = "类型（0机关单位 1承训单位）")
                                                   @RequestParam(required = false) String type) {
        return R.data(setUnitVo(unitService.unitTreeList(unitName, type)));
    }

    /**
     * 获取当前登录人下级单位
     */
    @GetMapping("/sub/unit")
    @ApiOperationSupport(order = 9)
    @Operation(summary = "获取当前登录人下级单位")
    public R<List<UnitVO>> subUnit() {
        List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                .eq(Unit::getParentId, getUnitId()));
        return R.data(BeanUtil.copy(units, UnitVO.class));
    }

    @PostMapping("/import")
    @ApiOperationSupport(order = 10)
    @Log(title = "单位管理导入", businessType = BusinessType.IMPORT)
    @Operation(summary = "单位Excel管理导入")
    public R importData(MultipartFile file,
                        @Parameter(description = "是否支持更新", required = true)
                        @RequestParam boolean updateSupport,
                        @Parameter(description = "类型（0机关单位 1承训单位）", required = true)
                        @RequestParam Integer type) throws Exception {
        if (0 == type) {
            ExcelUtil<UnitExportNewVO> util = new ExcelUtil<>(UnitExportNewVO.class);
            List<UnitExportNewVO> list = util.importExcel(file.getInputStream());
            String string = unitService.importData(BeanUtil.copy(list, Unit.class), updateSupport, getUserId(), type);
            setUsers(type);
            return R.success(string);
        }
        ExcelUtil<UnitExportVO> util = new ExcelUtil<>(UnitExportVO.class);
        List<UnitExportVO> list = util.importExcel(file.getInputStream());
        return R.success(unitService.importData(BeanUtil.copy(list, Unit.class), updateSupport, getUserId(), type));
    }

    @GetMapping("/importTemplate")
    @ApiOperationSupport(order = 11)
    @Operation(summary = "导入Excel模版下载")
    public void importTemplate(HttpServletResponse response) {
        ExcelUtil<Unit> util = new ExcelUtil<>(Unit.class);
        util.importTemplateExcel(response, "单位管理导入模版");
    }

    @PostMapping("/import/xml")
    @ApiOperationSupport(order = 12)
    @Log(title = "单位xml管理导入", businessType = BusinessType.IMPORT)
    @Operation(summary = "单位xml管理导入")
    public R importXmlData(MultipartFile file,
                           @Parameter(description = "是否支持更新", required = true)
                           @RequestParam boolean updateSupport,
                           @Parameter(description = "类型（0机关单位 1承训单位）", required = true)
                           @RequestParam Integer type) throws Exception {
        JAXBContext jaxbContext = JAXBContext.newInstance(Records.class);
        Unmarshaller unmarshaller = jaxbContext.createUnmarshaller();
        Records records = (Records) unmarshaller.unmarshal(file.getInputStream());
        List<Record> recordList = records.getRecords();
        if (0 == type) {
            List<UnitExportNewVO> list = recordList.stream().map(u -> setUnit(type, u)).collect(Collectors.toList());
            String string = unitService.importData(BeanUtil.copy(list, Unit.class), updateSupport, getUserId(), type);
            setUsers(type);
            return R.success(string);
        }
        List<UnitExportVO> list = recordList.stream().map(u -> setUnitExportVO(type, u)).collect(Collectors.toList());
        return R.success(unitService.importData(BeanUtil.copy(list, Unit.class), updateSupport, getUserId(), type));
    }

    /**
     * 获取当前登录人单位
     */
    @GetMapping("/per/se")
    @ApiOperationSupport(order = 14)
    @Operation(summary = "获取当前登录人单位")
    public R<UnitVO> perSe() {
        Unit unit = unitService.getById(getUnitId());
        return R.data(BeanUtil.copy(unit, UnitVO.class));
    }


    private UnitExportNewVO setUnit(Integer type, Record uprecord) {
        return new UnitExportNewVO()
                .setUnitDesignation(uprecord.getBuDuiFanHao())
                .setUnitName(uprecord.getDanWeiMingCheng())
                .setUnitCode(uprecord.getDanWeiDaiMa())
                .setForShort(uprecord.getDanWeiJianCheng())
                // .setType(type.toString())
                .setAddress(uprecord.getDanWeiDiZhi())
                .setUnitOldCode(uprecord.getJiuDanWeiDaiMa())
                .setParentCode(uprecord.getSuoShuDaDanWeiDaiMa())
                .setParentName(uprecord.getSuoShuDaDanWeiMingCheng())
                .setContactPerson(uprecord.getLianXiRen())
                .setPhone(uprecord.getLianXiDianHua())
                .setPostalCode(uprecord.getYouZhengBianMa())
                .setUnitUpdateTime(StringUtils.isNotBlank(uprecord.getGengXinRiQi()) ?
                        DateUtils.parseDate(uprecord.getGengXinRiQi()) : null)
                .setRemark(uprecord.getBeiZhu());
    }

    private UnitExportVO setUnitExportVO(Integer type, Record uprecord) {
        return new UnitExportVO()
                // .setUnitDesignation(uprecord.getBuDuiFanHao())
                .setUnitName(uprecord.getDanWeiMingCheng())
                .setUnitCode(uprecord.getDanWeiDaiMa())
                .setForShort(uprecord.getDanWeiJianCheng())
                // .setType(type.toString())
                .setAddress(uprecord.getDanWeiDiZhi())
                .setUnitOldCode(uprecord.getJiuDanWeiDaiMa())
                // .setParentCode(uprecord.getSuoShuDaDanWeiDaiMa())
                // .setParentName(uprecord.getSuoShuDaDanWeiMingCheng())
                .setContactPerson(uprecord.getLianXiRen())
                .setPhone(uprecord.getLianXiDianHua())
                .setPostalCode(uprecord.getYouZhengBianMa())
                // .setUnitUpdateTime(StringUtils.isNotBlank(uprecord.getGengXinRiQi()) ?
                //         DateUtils.parseDate(uprecord.getGengXinRiQi()) : null)
                .setRemark(uprecord.getBeiZhu());
    }

    private void setUnit(List<Unit> list, List<Long> ids) {
        if (CollectionUtils.isNotEmpty(list)) {
            List<Long> longs = list.stream().map(Unit::getUnitId).toList();
            ids.addAll(longs);
            List<Unit> units = unitService.list(new LambdaQueryWrapper<Unit>()
                    .in(Unit::getParentId, longs));
            setUnit(units, ids);
        }
    }

    private List<UnitTreeNewListVO> setUnitVo(List<UnitTreeListVO> list) {
        List<UnitTreeNewListVO> unitTreeNewListVOList = new ArrayList<UnitTreeNewListVO>();
        if (CollectionUtils.isNotEmpty(list)) {
            for (UnitTreeListVO vo : list) {
                UnitTreeNewListVO treeListVO = BeanUtil.copy(vo, UnitTreeNewListVO.class);
                treeListVO.setId(vo.getUnitId());
                treeListVO.setLabel(vo.getUnitName());
                if (CollectionUtils.isNotEmpty(vo.getChildren())) {
                    treeListVO.setChildren(setUnitVo(vo.getChildren()));
                }
                unitTreeNewListVOList.add(treeListVO);
            }
            return unitTreeNewListVOList;
        }
        return unitTreeNewListVOList;
    }


    private void setUsers(int type) {
        List<SysRole> roles = sysRoleService.selectRoleAll();
        Map<String, Long> map = roles.stream().collect(Collectors.toMap(SysRole::getRoleKey, SysRole::getRoleId));
        List<Unit> voList = getUnits(type, 0L);
        if (CollectionUtils.isNotEmpty(voList)) {
            // 循环一级单位
            for (Unit unit : voList) {
                // 新增一级单位账号
                long count = getCount(unit);
                if (0 == count) {
                    SysUser sysUser = setSysUser(unit);
                    sysUserRoleService.save(new SysUserRole()
                            .setRoleId(map.get("LJ")).setUserId(sysUser.getUserId()));
                }
                // 查询一级单位下二级单位
                List<Unit> voList2 = getUnits(type, unit.getUnitId());
                if (CollectionUtils.isNotEmpty(voList2)) {
                    // 循环二级单位
                    for (Unit unit2 : voList2) {
                        // 查询二级单位下三级单位
                        List<Unit> voList3 = getUnits(type, unit2.getUnitId());
                        // 判断是否存在下级单位
                        boolean b = CollectionUtils.isNotEmpty(voList3);
                        // 新增二级单位账号
                        long count1 = getCount(unit2);
                        if (0 == count1) {
                            SysUser sysUser = setSysUser(unit2);
                            sysUserRoleService.save(new SysUserRole()
                                    .setRoleId(b ? map.get("ZQLJ") : map.get("BD")).setUserId(sysUser.getUserId()));
                        }
                        if (b) {
                            // 循环三级单位
                            for (Unit unit3 : voList3) {
                                // 查询三级单位下四级单位
                                List<Unit> voList4 = getUnits(type, unit3.getUnitId());
                                // 判断是否存在下级单位
                                boolean b1 = CollectionUtils.isNotEmpty(voList4);
                                // 新增二级单位账号
                                long count2 = getCount(unit3);
                                if (0 == count2) {
                                    SysUser sysUser = setSysUser(unit3);
                                    sysUserRoleService.save(new SysUserRole()
                                            .setRoleId(b1 ? map.get("JTJ") : map.get("BD")).setUserId(sysUser.getUserId()));
                                }
                                if (b1) {
                                    // 循环四级单位
                                    for (Unit unit4 : voList4) {
                                        // 新增二级单位账号
                                        long count4 = getCount(unit4);
                                        if (0 == count4) {
                                            SysUser sysUser = setSysUser(unit4);
                                            sysUserRoleService.save(new SysUserRole()
                                                    .setRoleId(map.get("BD")).setUserId(sysUser.getUserId()));
                                        }
                                    }
                                }
                            }
                        }
                    }
                }
            }
        }
    }

    private List<Unit> getUnits(Integer type, Long pid) {
        return unitService.list(new LambdaQueryWrapper<Unit>()
                .eq(Unit::getType, type).eq(Unit::getParentId, pid));
    }

    private SysUser setSysUser(Unit unit) {
        SysUser sysUser = new SysUser()
                .setUnitId(unit.getUnitId())
                .setUserName(unit.getUnitCode())
                .setNickName(unit.getUnitCode())
                .setRealName(unit.getUnitName())
                .setPassword(SecurityUtils.encryptPassword("123456"))
                .setUpdateBy(getUserId().toString()).setUpdateTime(new Date());
        sysUserService.save(sysUser);
        return sysUser;
    }

    private long getCount(Unit unit) {
        return sysUserService.count(new LambdaQueryWrapper<SysUser>()
                .eq(SysUser::getUserName, unit.getUnitCode()));
    }


}
