package com.ruoyi.asset.service.impl;

import java.io.ByteArrayOutputStream;
import java.io.File;
import java.io.FileInputStream;
import java.io.IOException;
import java.util.ArrayList;
import java.util.HashSet;
import java.util.List;

import cn.hutool.core.util.StrUtil;
import com.ruoyi.common.code.QRCodeUtils;
import com.ruoyi.common.code.QrDTO;
import com.ruoyi.common.core.domain.TreeSelect;
import com.ruoyi.common.utils.DateUtils;
import com.ruoyi.common.utils.SecurityUtils;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FileUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import com.ruoyi.asset.mapper.TbLocationMapper;
import com.ruoyi.asset.domain.TbLocation;
import com.ruoyi.asset.service.ITbLocationService;

import javax.annotation.Resource;

/**
 * 所属位置Service业务层处理
 * 
 * @author 原动力
 * @date 2023-05-15
 */
@Slf4j
@Service
public class TbLocationServiceImpl implements ITbLocationService 
{
    @Resource
    private TbLocationMapper tbLocationMapper;

    /**
     * 查询所属位置
     * 
     * @param id 所属位置主键
     * @return 所属位置
     */
    @Override
    public TbLocation selectTbLocationById(Long id)
    {
        return tbLocationMapper.selectTbLocationById(id);
    }

    @Override
    public TbLocation selectTbLocationByNumber(String number) {
        return tbLocationMapper.selectTbLocationByNumber(number);
    }

    @Override
    public List<TbLocation> selectTbLocationListByNumbers(List<String> numbers) {
        return tbLocationMapper.selectTbLocationListByNumbers(numbers);
    }

    /**
     * 查询所属位置列表
     * 
     * @param tbLocation 所属位置
     * @return 所属位置
     */
    @Override
    public List<TbLocation> selectTbLocationList(TbLocation tbLocation)
    {
        return tbLocationMapper.selectTbLocationList(tbLocation);
    }

    @Override
    public List<TbLocation> selectTree(TbLocation tbLocation) {
        List<TbLocation> locations;
        if (tbLocation.getParentId() == null) {
            tbLocation.setParentId(0L);
        }
        locations = selectTbLocationList(tbLocation);
        for (TbLocation location : locations) {
            List<TbLocation> tbLocations = buildChildren(location);
            location.setChildren(tbLocations);
        }
        return locations;
    }

    private List<TbLocation> buildChildren(TbLocation location) {
        TbLocation sunLocation = new TbLocation();
        sunLocation.setParentId(location.getId());
        List<TbLocation> locations = selectTbLocationList(sunLocation);
        if (locations != null && !locations.isEmpty()) {
            for (TbLocation tbLocation : locations) {
                List<TbLocation> tbLocations = buildChildren(tbLocation);
                tbLocation.setChildren(tbLocations);
            }
        }
        return locations;
    }

    @Override
    public List<TreeSelect> selectTreeSelect(Long id) {
        ArrayList<TreeSelect> treeSelects = new ArrayList<>();
        if (id != null) {
            TbLocation location = selectTbLocationById(id);
            TreeSelect treeSelect = new TreeSelect();
            treeSelect.setId(location.getId());
            treeSelect.setNumber(location.getNumber());
            treeSelect.setLabel(location.getName());
            treeSelects.add(treeSelect);
        } else {
            TbLocation location = new TbLocation();
            location.setParentId(0L);
            List<TbLocation> locations = selectTbLocationList(location);
            for (TbLocation tbLocation : locations) {
                TreeSelect treeSelect = new TreeSelect();
                treeSelect.setId(tbLocation.getId());
                treeSelect.setNumber(tbLocation.getNumber());
                treeSelect.setLabel(tbLocation.getName());
                treeSelects.add(treeSelect);
            }
        }
        for (TreeSelect treeSelect : treeSelects) {
            List<TreeSelect> treeSelectList = buildChildrenSelect(treeSelect);
            treeSelect.setChildren(treeSelectList);
        }
        return treeSelects;
    }


    private List<TreeSelect> buildChildrenSelect(TreeSelect treeSelect) {
        TbLocation sunLocation = new TbLocation();
        sunLocation.setParentId(treeSelect.getId());
        List<TbLocation> locations = selectTbLocationList(sunLocation);
        ArrayList<TreeSelect> treeSelects = new ArrayList<>();
        if (locations != null && !locations.isEmpty()) {
            for (TbLocation tbLocation : locations) {
                TreeSelect childrenTreeSelect = new TreeSelect();
                childrenTreeSelect.setId(tbLocation.getId());
                childrenTreeSelect.setNumber(tbLocation.getNumber());
                childrenTreeSelect.setLabel(tbLocation.getName());
                List<TreeSelect> treeSelectList = buildChildrenSelect(childrenTreeSelect);
                childrenTreeSelect.setChildren(treeSelectList);
                treeSelects.add(childrenTreeSelect);
            }
        }
        return treeSelects;
    }

    /**
     * 新增所属位置
     * 
     * @param tbLocation 所属位置
     * @return 结果
     */
    @Override
    public int insertTbLocation(TbLocation tbLocation)
    {
        Long parentId = tbLocation.getParentId();
        if (parentId == null || parentId == 0) {
            tbLocation.setParentId(0L);
        } else {
            if (selectTbLocationById(parentId) == null) {
                return 0;
            }
        }

        String dateTimeId = DateUtils.dateTimeNow("yyyyMMddHHmmssSSS");
        String orderNumber = "WZ" + dateTimeId;

        tbLocation.setNumber(orderNumber);
        tbLocation.setCreateTime(DateUtils.getNowDate());
        tbLocation.setCreateBy(SecurityUtils.getUsername());
        int flag = tbLocationMapper.insertTbLocation(tbLocation);
        if (flag < 1) {
            return flag;
        }

        String sequence = getSequence(parentId, tbLocation.getId());
        tbLocation.setSequence(sequence);

        createQrCodeDataByLocation(tbLocation);

        return tbLocationMapper.updateTbLocation(tbLocation);
    }

    /**
     * 修改所属位置
     * 
     * @param tbLocation 所属位置
     * @return 结果
     */
    @Override
    public int updateTbLocation(TbLocation tbLocation)
    {
        tbLocation.setUpdateTime(DateUtils.getNowDate());
        Long parentId = tbLocation.getParentId();

        String sequence = getSequence(parentId, tbLocation.getId());
        tbLocation.setSequence(sequence);
        int result = tbLocationMapper.updateTbLocation(tbLocation);
        if (result > 0) {
            String fileUrl = getFileUrl(tbLocation.getNumber());
            File file = new File(fileUrl);
            if (file.isFile() && file.exists()) {
                boolean delete = file.delete();
                if (!delete) {
                    System.out.println(tbLocation.getNumber()+"位置二维码删除失败，目标路径:\n"+fileUrl);
                }
            }
        }
        return result;
    }

    private String getSequence(Long parentId, Long locationId) {
        List<Long> set = new ArrayList<>();
        while (parentId != null && parentId > 0) {
            TbLocation location = selectTbLocationById(parentId);
            set.add(location.getId());
            parentId = location.getParentId();
        }

        StringBuilder stringBuilder = new StringBuilder();
        if (!set.isEmpty()) {
            for (int i = set.size() - 1; i >= 0; i--) {
                stringBuilder.append(set.get(i));
                stringBuilder.append(",");
            }
        }
        stringBuilder.append(locationId);
        return stringBuilder.toString();
    }

    /**
     * 批量删除所属位置
     * 
     * @param ids 需要删除的所属位置主键
     * @return 结果
     */
    @Override
    public int deleteTbLocationByIds(Long[] ids)
    {
        return tbLocationMapper.deleteTbLocationByIds(ids);
    }

    /**
     * 删除所属位置信息
     * 
     * @param id 所属位置主键
     * @return 结果
     */
    @Override
    public int deleteTbLocationById(Long id)
    {
        return tbLocationMapper.deleteTbLocationById(id);
    }

    @Value("${ruoyi.profile}")
    private String savePath;

    private final String dataName = "/location/qrCodes";

    private final String cacheName = "/location/qrCode";

    @Override
    public void createQrCodeDataByLocation(TbLocation tbLocation) {
        QrDTO qrDTO = new QrDTO();
        String sequence = tbLocation.getSequence();
        String[] ids = sequence.split(",");
        StringBuilder stringBuilder = new StringBuilder();
        for (int i = 0; i < ids.length; i++) {
            Long locationId = Long.valueOf(ids[i]);
            TbLocation location = tbLocationMapper.selectTbLocationById(locationId);
            if (location != null) {
                stringBuilder.append(location.getName());
                if (i < ids.length - 1) {
                    stringBuilder.append("-");
                }
            }
        }
        qrDTO.setName(stringBuilder.toString());
        qrDTO.setValue(tbLocation.getNumber());

        File file = new File(getFileUrl(qrDTO.getValue()));
        if (file.exists()) {
            return;
        }
        QRCodeUtils.createCodeToFile(qrDTO, new File(savePath + dataName), qrDTO.getValue() + ".png");
    }

    @Override
    public byte[] selectQrCodeByLocationNumber(String locationNumber) {
        TbLocation location = tbLocationMapper.selectTbLocationByNumber(locationNumber);
        if (location == null) {
            return null;
        }
        String fileURL = getFileUrl(locationNumber);
        File file = new File(fileURL);
        if (!file.exists()) {
            createQrCodeDataByLocation(location);
        }
        byte[] bytes = new byte[0];
        FileInputStream fileInputStream = null;
        try {
            fileInputStream = new FileInputStream(file);
            bytes = new byte[fileInputStream.available()];
            fileInputStream.read(bytes, 0, fileInputStream.available());
        } catch (Exception e) {
            e.printStackTrace();
        } finally {
            if (fileInputStream != null) {
                try {
                    fileInputStream.close(); // 关闭文件输入流
                } catch (IOException e) {
                    e.printStackTrace();
                }
            }
        }

         return bytes;
    }

    @Override
    public String downloadQrCode(List<Long> locationIds) {
        ArrayList<String> fileUrlList = new ArrayList<>();
        for (Long locationId : locationIds) {
            TbLocation location = tbLocationMapper.selectTbLocationById(locationId);
            if (location == null) {
                continue;
            }
            String fileUrl = getFileUrl(location.getNumber());
            fileUrlList.add(fileUrl);
        }

        // 新建一个目录
        String path = savePath + cacheName;
        File file = new File(path);
        if (file.exists()) {
            // 清空文件夹
            delete(path);
        } else {
            file.mkdir();
        }

        for (String fileUrl : fileUrlList) {
            try {
                FileUtils.copyFileToDirectory(new File(fileUrl), new File(path));
            } catch (IOException e) {
                e.printStackTrace();
            }
        }

        return path;
    }

    public void delete(String path) {
        // 为传进来的路径参数创建一个文件对象
        File file = new File(path);
        // 如果目标路径是一个文件，那么直接调用delete方法删除即可
        // file.delete();
        // 如果是一个目录，那么必须把该目录下的所有文件和子目录全部删除，才能删除该目标目录，这里要用到递归函数
        // 创建一个files数组，用来存放目标目录下所有的文件和目录的file对象
        File[] files;
        // 将目标目录下所有的file对象存入files数组中
        files = file.listFiles();
        if (files == null) {
            return;
        }
        // 循环遍历files数组
        for(File temp : files){
            // 判断该temp对象是否为文件对象
            if (temp.isFile()) {
                temp.delete();
            }
            // 判断该temp对象是否为目录对象
            if (temp.isDirectory()) {
                // 将该temp目录的路径给delete方法（自己），达到递归的目的
                delete(temp.getAbsolutePath());
                // 确保该temp目录下已被清空后，删除该temp目录
                temp.delete();
            }
        }
    }

    private String getFileUrl(String number) {
        return savePath + dataName + "/" + number + ".png";
    }
}
