package com.inspect.metadata.area.controller;

import com.inspect.metadata.area.domain.BaseDataArea;
import com.inspect.metadata.area.service.IBaseDataAreaService;
import com.inspect.metadata.prodevmnt.util.ExportExcelUtil;
import com.inspect.base.core.utils.DateUtils;
import com.inspect.base.core.utils.StringUtils;
import com.inspect.base.core.utils.poi.ExcelUtil;
import com.inspect.base.core.web.controller.BaseController;
import com.inspect.base.core.web.domain.AjaxResult;
import com.inspect.common.log.annotation.Log;
import com.inspect.common.log.enums.BizType;
import com.inspect.common.security.annotation.RequiresPermissions;
import com.inspect.common.security.utils.SecurityUtils;

import java.io.IOException;
import java.io.InputStream;
import java.util.ArrayList;
import java.util.HashMap;
import java.util.Iterator;
import java.util.List;
import java.util.Map;
import javax.servlet.http.HttpServletResponse;

import org.apache.commons.lang3.ArrayUtils;
import org.apache.commons.math3.exception.NullArgumentException;
import org.apache.poi.hssf.usermodel.HSSFWorkbook;
import org.apache.poi.ss.usermodel.CellType;
import org.apache.poi.ss.usermodel.Row;
import org.apache.poi.ss.usermodel.Sheet;
import org.apache.poi.ss.usermodel.Workbook;
import org.apache.poi.xssf.usermodel.XSSFWorkbook;
import org.springframework.validation.annotation.Validated;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestBody;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.multipart.MultipartFile;

@RestController
@RequestMapping({"/area"})
public class BaseDataAreaController extends BaseController {
    private final IBaseDataAreaService baseDataAreaService;

    public BaseDataAreaController(IBaseDataAreaService baseDataAreaService) {
        this.baseDataAreaService = baseDataAreaService;
    }

    @GetMapping({"/list"})
    public AjaxResult list(BaseDataArea area) {
        this.paramsSetAreaIdToList(area);
        List<BaseDataArea> dataAreaList = this.baseDataAreaService.selectAreaList(area);
        return AjaxResult.success(dataAreaList);
    }

    @PostMapping({"/v2/list"})
    public AjaxResult listV2(@RequestBody BaseDataArea area) {
        this.paramsSetAreaIdToList(area);
        List<BaseDataArea> dataAreaList = this.baseDataAreaService.selectAreaList(area);
        return AjaxResult.success(dataAreaList);
    }

    @RequiresPermissions({"basedata:area:list"})
    @GetMapping({"/list/exclude/{areaId}"})
    public AjaxResult excludeChild(@PathVariable(value = "areaId", required = false) Long areaId) {
        List<BaseDataArea> dataAreaList = this.baseDataAreaService.selectAreaList(new BaseDataArea());
        Iterator<BaseDataArea> it = dataAreaList.iterator();
        while (true) {
            BaseDataArea d;
            do {
                if (!it.hasNext()) {
                    return AjaxResult.success(dataAreaList);
                }

                d = it.next();
            } while ((long) d.getAreaId().intValue() != areaId && !ArrayUtils.contains(StringUtils.split(d.getAncestors(), StringUtils.COMMA), areaId + ""));

            it.remove();
        }
    }

    @RequiresPermissions({"basedata:area:query"})
    @GetMapping({"/{areaId}"})
    public AjaxResult getInfo(@PathVariable Long areaId) {
        this.baseDataAreaService.checkAreaDataScope(areaId);
        return AjaxResult.success(this.baseDataAreaService.selectAreaById(areaId));
    }

    @GetMapping({"/treeselect"})
    public AjaxResult treeSelect(BaseDataArea area) {
        List<BaseDataArea> dataAreaList = this.baseDataAreaService.selectAreaList(area);
        return AjaxResult.success(this.baseDataAreaService.buildAreaTreeSelect(dataAreaList));
    }

    @GetMapping({"/roleAreaTreeselect/{roleId}"})
    public AjaxResult roleAreaTreeSelect(@PathVariable("roleId") Long roleId) {
        List<BaseDataArea> dataAreaList = this.baseDataAreaService.selectAreaList(new BaseDataArea());
        AjaxResult ajax = AjaxResult.success();
        ajax.put("checkedKeys", this.baseDataAreaService.selectAreaListByRoleId(roleId));
        ajax.put("depts", this.baseDataAreaService.buildAreaTreeSelect(dataAreaList));
        return ajax;
    }

    @RequiresPermissions({"basedata:area:add"})
    @Log(
            title = "部门管理",
            businessType = BizType.INSERT
    )
    @PostMapping({"/add"})
    public AjaxResult add(@Validated @RequestBody BaseDataArea area) {
        if ("1".equals(this.baseDataAreaService.checkAreaNameUnique(area))) {
            return AjaxResult.error("新增区域'" + area.getAreaName() + "'失败，区域名称已存在");
        } else {
            area.setCreateBy(SecurityUtils.getUsername());
            area.setCreateTime(DateUtils.getNowDate());
            return this.toAjax(this.baseDataAreaService.insertArea(area));
        }
    }

    @RequiresPermissions({"basedata:area:edit"})
    @Log(
            title = "部门管理",
            businessType = BizType.UPDATE
    )
    @PostMapping({"/update"})
    public AjaxResult edit(@Validated @RequestBody BaseDataArea area) {
        Long areaId = area.getAreaId();
        this.baseDataAreaService.checkAreaDataScope(areaId);
        if ("1".equals(this.baseDataAreaService.checkAreaNameUnique(area))) {
            return AjaxResult.error("修改部门'" + area.getAreaName() + "'失败，部门名称已存在");
        } else if (area.getParentId().equals(areaId)) {
            return AjaxResult.error("修改部门'" + area.getAreaName() + "'失败，上级部门不能是自己");
        } else if (StringUtils.equals("1", area.getStatus()) && this.baseDataAreaService.selectNormalChildrenAreaById(areaId) > 0) {
            return AjaxResult.error("该部门包含未停用的子部门！");
        } else {
            area.setUpdateBy(SecurityUtils.getUsername());
            return this.toAjax(this.baseDataAreaService.updateArea(area));
        }
    }

    @RequiresPermissions({"basedata:area:remove"})
    @Log(
            title = "部门管理",
            businessType = BizType.DELETE
    )
    @PostMapping({"/remove/{areaId}"})
    public AjaxResult remove(@PathVariable Long areaId) {
        if (this.baseDataAreaService.hasChildByAreaId(areaId)) {
            return AjaxResult.error("存在下级部门,不允许删除");
        } else if (this.baseDataAreaService.checkAreaExistUser(areaId)) {
            return AjaxResult.error("部门存在用户,不允许删除");
        } else {
            this.baseDataAreaService.checkAreaDataScope(areaId);
            return this.toAjax(this.baseDataAreaService.deleteAreaById(areaId));
        }
    }

    @PostMapping({"/exportTemplate"})
    public void downloadTemp(HttpServletResponse response) {
        ExportExcelUtil.exportTemplate(response, "区域导入模板.xlsx");
    }

    @RequiresPermissions({"basedata:area:export"})
    @Log(
            title = "区域数据",
            businessType = BizType.EXPORT
    )
    @PostMapping({"/export"})
    public void export(HttpServletResponse response, BaseDataArea baseDataArea) {
        List<BaseDataArea> list = this.baseDataAreaService.selectAreaList(baseDataArea);
        Map<Object, Object> mapNew = new HashMap<>();
        Map<String, Long> map = this.baseDataAreaService.selectAreaForNamePatch(new BaseDataArea());
        for (Object key : map.keySet()) {
            mapNew.put(map.get(key), key.toString());
        }

        for (BaseDataArea baseDataAreaList : list) {
            Long ss = baseDataAreaList.getAreaId();
            String str = mapNew.get(ss).toString();
            baseDataAreaList.setAreaAddr(str);
        }

        ExcelUtil<BaseDataArea> util = new ExcelUtil<>(BaseDataArea.class);
        util.exportExcel(response, list, "区域数据");
    }

    @RequiresPermissions({"basedata:area:list"})
    @GetMapping({"/apiList"})
    public AjaxResult apiList(BaseDataArea area) {
        List<BaseDataArea> baseDataAreaList = this.baseDataAreaService.selectAreaList(area);
        return AjaxResult.success(baseDataAreaList);
    }

    @GetMapping({"/getAreaInfo/{patrolpointId}"})
    public AjaxResult getAreaInfo(@PathVariable("patrolpointId") String patrolPointId) {
        BaseDataArea baseDataArea = this.baseDataAreaService.selectBasedataAreaByPatrolPointId(patrolPointId);
        return AjaxResult.success(baseDataArea);
    }

    @RequiresPermissions({"basedata:area:list"})
    @GetMapping({"/selectAreaForNamePatch"})
    public AjaxResult selectAreaForNamePatch(BaseDataArea area) {
        Map<String, Long> map = this.baseDataAreaService.selectAreaForNamePatch(area);
        return AjaxResult.success(map);
    }

    @PostMapping({"/importData"})
    public AjaxResult importData(MultipartFile file) throws Exception {
        if (file == null) {
            throw new NullArgumentException();
        } else {
            String filename = file.getOriginalFilename();
            if (filename == null) {
                throw new NullArgumentException();
            } else {
                String a;

                try {
                    a = this.parseRowCell(filename, file.getInputStream());
                } catch (IOException e) {
                    throw new Exception(e.getMessage());
                }

                return AjaxResult.success("导入结果", a);
            }
        }
    }

    private String parseRowCell(String filename, InputStream is) throws Exception {
        try {
            Workbook workbook = null;
            if (filename.endsWith(".xls")) {
                workbook = new HSSFWorkbook(is);
            }

            if (filename.endsWith(".xlsx")) {
                workbook = new XSSFWorkbook(is);
            }

            if (workbook == null) {
                throw new NullArgumentException();
            } else {
                Sheet sheet = workbook.getSheetAt(0);
                if (sheet == null) {
                    throw new NullArgumentException();
                } else {
                    for (int rowNum = 1; rowNum <= sheet.getLastRowNum(); ++rowNum) {
                        Row row = sheet.getRow(rowNum);
                        if (row != null) {
                            String areaName = "";
                            if (row.getCell(0) != null) {
                                row.getCell(0).setCellType(CellType.STRING);
                                areaName = row.getCell(0).getStringCellValue().trim();
                            }

                            String areaAddr = "";
                            if (row.getCell(1) != null) {
                                row.getCell(1).setCellType(CellType.STRING);
                                areaAddr = row.getCell(1).getStringCellValue().trim();
                            }

                            String remark = "";
                            if (row.getCell(2) != null) {
                                row.getCell(2).setCellType(CellType.STRING);
                                remark = row.getCell(2).getStringCellValue().trim();
                            }

                            String areaType = "";
                            if (row.getCell(3) != null) {
                                row.getCell(3).setCellType(CellType.STRING);
                                areaType = row.getCell(3).getStringCellValue().trim();
                            }

                            if (StringUtils.isAllBlank(areaName)) {
                                throw new Exception("请检查必填项！");
                            }

                            String[] str = areaAddr.split(StringUtils.SLASH);
                            int len = str.length;
                            String parentId = "0";
                            if (len != 1) {
                                parentId = this.getAreaIdByAreaName(str, len, parentId);
                                BaseDataArea baseDataArea = new BaseDataArea();
                                baseDataArea.setAreaName(areaName);
                                baseDataArea.setParentId(Long.valueOf(parentId));
                                baseDataArea.setAreaAddr(areaAddr);
                                baseDataArea.setRemark(remark);
                                baseDataArea.setAreaType(areaType);
                                String unique = this.baseDataAreaService.checkAreaNameUnique(baseDataArea);
                                if ("0".equals(unique)) {
                                    this.baseDataAreaService.insertArea(baseDataArea);
                                }
                            }
                        }
                    }

                    return "成功！";
                }
            }
        } catch (IOException e) {
            e.getMessage();
            return "失败！";
        }
    }

    public String getAreaIdByAreaName(String[] areaAddr, int len, String parentId) {
        for (int i = 0; i < len; ++i) {
            parentId = this.baseDataAreaService.selectAreaIdByName(areaAddr[i], parentId);
            if ("".equals(parentId) || null == parentId) {
                parentId = "0";

                for (int j = 0; j < i; ++j) {
                    parentId = this.baseDataAreaService.selectAreaIdByName(areaAddr[j], parentId);
                }

                return parentId;
            }
        }

        return parentId;
    }

    public void paramsSetAreaIdToList(BaseDataArea baseDataArea) {
        Map<String, Object> params = new HashMap<>();
        List<String> list = this.paramsGetListByAreaIdS(baseDataArea);
        if (!list.isEmpty()) {
            params.put("areaIdList", list);
            baseDataArea.setParams(params);
        }

    }

    public List<String> paramsGetListByAreaIdS(BaseDataArea baseDataArea) {
        List<String> list = new ArrayList<>();
        if (StringUtils.isNotEmpty(baseDataArea.getAreaIdS())) {
            if (baseDataArea.getAreaIdS().contains(StringUtils.COMMA)) {
                String[] strs = baseDataArea.getAreaIdS().split(StringUtils.COMMA);
                for (String str : strs) {
                    if (StringUtils.isNotEmpty(str)) {
                        list.add(str);
                    }
                }
            } else {
                list.add(baseDataArea.getAreaIdS());
            }
        }

        return list;
    }

    @GetMapping({"/selectAreaNameSForTaskByAreaIdS"})
    public AjaxResult selectAreaNameSForTaskByAreaIdS(BaseDataArea area) {
        Map<String, BaseDataArea> areaMap = new HashMap<>();
        List<String> list = this.paramsGetListByAreaIdS(area);
        BaseDataArea areaQuery = new BaseDataArea();
        List<BaseDataArea> areas = this.baseDataAreaService.selectAreaList(areaQuery);

        for (BaseDataArea baseDataArea : areas) {
            areaMap.put(String.valueOf(baseDataArea.getAreaId()), baseDataArea);
        }

        Map<String, String> retHashMap = new HashMap<>();
        StringBuilder nameSBuilder = new StringBuilder();
        for (String areaId : list) {
            this.getAreaDeviceTreeDeviceCode(areaId, areaMap, retHashMap, nameSBuilder);
        }

        return AjaxResult.success("成功", nameSBuilder.toString());
    }

    @GetMapping({"/selectAreaNameSForTaskByAreaIdSRelation"})
    public AjaxResult selectAreaNameSForTaskByAreaIdSRelation(BaseDataArea area) {
        Map<String, BaseDataArea> areaMap = new HashMap<>();
        List<String> list = this.paramsGetListByAreaIdS(area);
        BaseDataArea areaQuery = new BaseDataArea();
        List<BaseDataArea> areas = this.baseDataAreaService.selectAreaRelationList(areaQuery);

        for (BaseDataArea baseDataArea : areas) {
            areaMap.put(String.valueOf(baseDataArea.getAreaId()), baseDataArea);
        }

        Map<String, String> retHashMap = new HashMap<>();
        StringBuilder nameSBuilder = new StringBuilder();
        for (String areaId : list) {
            this.getAreaDeviceTreeDeviceCodeRelation(areaId, areaMap, retHashMap, nameSBuilder);
        }

        return AjaxResult.success("成功", nameSBuilder.toString());
    }

    private void getAreaDeviceTreeDeviceCode(String areaId, Map<String, BaseDataArea> areaMap, Map<String, String> retHashMap, StringBuilder nameSBuilder) {
        if (areaMap.containsKey(areaId)) {
            BaseDataArea area = areaMap.get(areaId);
            if (area.getParentId() == 0L) {
                return;
            }

            if (area.getParentId() == 1L) {
                if (!retHashMap.containsKey(area.getAreaId().toString())) {
                    if (!retHashMap.isEmpty()) {
                        nameSBuilder.append(",");
                        nameSBuilder.append(area.getAreaName());
                    } else {
                        nameSBuilder.append(area.getAreaName());
                    }

                    retHashMap.put(area.getAreaId().toString(), area.getAreaName());
                    return;
                }

                return;
            }

            areaId = area.getParentId().toString();
            this.getAreaDeviceTreeDeviceCode(areaId, areaMap, retHashMap, nameSBuilder);
        }

    }

    private void getAreaDeviceTreeDeviceCodeRelation(String areaId, Map<String, BaseDataArea> areaMap, Map<String, String> retHashMap, StringBuilder nameSBuilder) {
        if (areaMap.containsKey(areaId)) {
            BaseDataArea area = areaMap.get(areaId);
            if (area.getRelationParentId() == 0L) {
                return;
            }

            if (area.getRelationParentId() == 1L) {
                if (!retHashMap.containsKey(area.getAreaId().toString())) {
                    if (!retHashMap.isEmpty()) {
                        nameSBuilder.append(",");
                        nameSBuilder.append(area.getAreaName());
                    } else {
                        nameSBuilder.append(area.getAreaName());
                    }

                    retHashMap.put(area.getAreaId().toString(), area.getAreaName());
                    return;
                }

                return;
            }

            areaId = area.getRelationParentId().toString();
            this.getAreaDeviceTreeDeviceCodeRelation(areaId, areaMap, retHashMap, nameSBuilder);
        }

    }
}
