/**
 * 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 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) {

        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())
                        .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())
                        .in(StringUtils.equals(dto.getType(),"0")
                                && CollectionUtils.isNotEmpty(dto.getParentIds()), Unit::getParentId, dto.getParentIds())
                        .or()
                        .in(StringUtils.equals(dto.getType(),"0")
                                        && CollectionUtils.isNotEmpty(dto.getParentIds()), Unit::getUnitId, dto.getParentIds())
                        //.in(CollectionUtils.isNotEmpty(ids), Unit::getUnitId, ids)
                       );
        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.addAll(unitService.list(new LambdaQueryWrapper<Unit>()
                            .orderByDesc(Unit::getCreateTime)
                            .eq(Unit::getType, dto.getType())
                            .like(StringUtils.isNotBlank(dto.getUnitName()), Unit::getUnitName, dto.getUnitName())
                            .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())
                            .in(StringUtils.equals(dto.getType(),"0")
                                    && CollectionUtils.isNotEmpty(dto.getParentIds()), Unit::getParentId, dto.getParentIds())
                            .or()
                            .in(StringUtils.equals(dto.getType(),"0")
                                    && CollectionUtils.isNotEmpty(dto.getParentIds()), Unit::getUnitId, dto.getParentIds())
                    //.in(CollectionUtils.isNotEmpty(ids), Unit::getUnitId, ids)
            ));
        }
        if (StringUtils.equals("0", dto.getType())) {
            ExcelUtil<Unit> excelUtil = new ExcelUtil<>(Unit.class);
            excelUtil.exportExcel(response, list, "机关单位管理数据");
        } 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) {
        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) {
        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) {
        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 {
        ExcelUtil<Unit> util = new ExcelUtil<>(Unit.class);
        List<Unit> list = util.importExcel(file.getInputStream());
        return R.success(unitService.importData(list, 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();
        List<Unit> list = recordList.stream().map(u -> setUnit(type, u)).collect(Collectors.toList());
        return R.success(unitService.importData(list, 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 Unit setUnit(Integer type, Record uprecord) {
        return new Unit()
                .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;
    }

}
