package cn.reghao.tnb.file.app.zdisk.service;

import cn.reghao.file.api.iface.OssService;
import cn.reghao.jutil.jdk.web.db.Page;
import cn.reghao.jutil.jdk.web.db.PageList;
import cn.reghao.jutil.jdk.web.result.Result;
import cn.reghao.tnb.file.app.zdisk.model.constant.AlbumType;
import cn.reghao.tnb.file.app.zdisk.model.vo.DiskAlbumDetail;
import cn.reghao.tnb.file.app.zdisk.model.vo.DiskAlbumInfo;
import cn.reghao.tnb.file.app.zdisk.model.vo.DiskFileDetail;
import cn.reghao.oss.api.constant.ObjectType;
import cn.reghao.tnb.auth.api.dto.AccountAvatar;
import cn.reghao.tnb.auth.api.iface.AccountQuery;
import cn.reghao.tnb.common.auth.UserContext;
import cn.reghao.tnb.common.db.SelectOption;
import cn.reghao.tnb.file.app.zdisk.db.mapper.DiskAlbumMapper;
import cn.reghao.tnb.file.app.zdisk.db.mapper.DiskFileMapper;
import cn.reghao.tnb.file.app.zdisk.db.repository.DiskAlbumRepository;
import cn.reghao.tnb.file.app.zdisk.model.dto.AlbumCreate;
import cn.reghao.tnb.file.app.zdisk.model.po.DiskAlbum;
import cn.reghao.tnb.file.app.zdisk.model.po.DiskAlbumFile;
import cn.reghao.tnb.file.app.zdisk.model.po.DiskFile;
import cn.reghao.tnb.common.util.IdService;
import lombok.extern.slf4j.Slf4j;
import org.apache.dubbo.config.annotation.DubboReference;
import org.springframework.stereotype.Service;

import java.util.*;
import java.util.stream.Collectors;

/**
 * @author reghao
 * @date 2023-11-10 15:16:35
 */
@Slf4j
@Service
public class DiskAlbumService {
    @DubboReference(check = false, retries = 0, timeout = 60_000)
    private AccountQuery accountQuery;
    @DubboReference(check = false, timeout = 60_000)
    private OssService ossService;

    private final int channelCode = 111;
    private final int albumMaxFiles = 1000;
    private final int pageSize = 12;
    private final DiskFileMapper diskFileMapper;
    private final DiskAlbumMapper diskAlbumMapper;
    private final DiskAlbumRepository diskAlbumRepository;
    private final DiskFileService diskFileService;
    private DiskShareService diskShareService;
    private final IdService idService;

    public DiskAlbumService(DiskFileMapper diskFileMapper, DiskAlbumMapper diskAlbumMapper,
                            DiskAlbumRepository diskAlbumRepository, DiskFileService diskFileService,
                            DiskShareService diskShareService, IdService idService) {
        this.diskFileMapper = diskFileMapper;
        this.diskAlbumMapper = diskAlbumMapper;
        this.diskAlbumRepository = diskAlbumRepository;
        this.diskFileService = diskFileService;
        this.diskShareService = diskShareService;
        this.idService = idService;
    }

    public void createAlbum(AlbumCreate albumCreate) {
        long albumId = idService.getLongId();
        DiskAlbum diskAlbum = new DiskAlbum(albumId, albumCreate);
        diskAlbumMapper.save(diskAlbum);
    }

    /**
     * 添加某类型的新文件到对应类型的合集中
     *
     * @param fileIds 文件或文件夹 ID
     * @return
     * @date 2025-09-04 17:47:40
     */
    public synchronized Result addAlbumFile(long albumId, List<String> fileIds) {
        DiskAlbum diskAlbum = diskAlbumMapper.findDiskAlbum(albumId);
        if (diskAlbum == null) {
            return Result.fail("album not exist");
        }

        long loginUser = UserContext.getUserId();
        if (diskAlbum.getCreateBy() != loginUser) {
            return Result.fail("not album owner");
        }

        List<String> existSha256sumList = diskAlbumMapper.findDiskAlbumFiles(albumId).stream()
                .map(DiskAlbumFile::getSha256sum)
                .collect(Collectors.toList());
        if (existSha256sumList.size() >= albumMaxFiles) {
            return Result.fail(String.format("单个合集最多能容纳 %s 张文件", albumMaxFiles));
        }

        Set<String> set = new HashSet<>(existSha256sumList);
        int fileType = diskAlbum.getFileType();

        List<DiskFile> diskFileList0 = diskFileService.findByFileIds(fileIds);
        Map<Integer, List<DiskFile>> groupMap = diskFileList0.stream()
                .filter(diskFile -> diskFile.getOwner() == loginUser)
                .collect(Collectors.groupingBy(DiskFile::getFileType));

        List<DiskFile> diskFileList = new ArrayList<>();
        List<DiskFile> folders = groupMap.get(ObjectType.Dir.getCode());
        if (folders != null) {
            List<String> pids = folders.stream().map(DiskFile::getFileId).collect(Collectors.toList());
            // 只获取当前文件夹中的文件, 不递归查找子文件夹
            List<DiskFile> diskFileList1 = diskFileService.findByParentIds(pids).stream()
                    .filter(diskFile -> diskFile.getOwner() == loginUser)
                    .filter(diskFile -> diskFile.getFileType() == fileType)
                    .collect(Collectors.toList());
            diskFileList.addAll(diskFileList1);
        }

        List<DiskFile> files = groupMap.get(fileType);
        if (files != null) {
            List<DiskFile> diskFileList2 = diskFileList = files.stream()
                    .filter(diskFile -> !set.contains(diskFile.getSha256sum()))
                    .collect(Collectors.toList());
            diskFileList.addAll(diskFileList2);
        }

        if (diskFileList.isEmpty()) {
            return Result.fail("添加的文件在当前合集中已存在");
        }

        int currentNum = diskAlbum.getNum();
        int addNum = diskFileList.size();
        int num = currentNum + addNum;
        if (num > albumMaxFiles) {
            log.info("新添加文件数量超过合集容量, 但这个限制尚未实现...");
        }

        int startPos = currentNum+1;
        List<DiskAlbumFile> list = new ArrayList<>();
        for (DiskFile diskFile : diskFileList) {
            list.add(new DiskAlbumFile(albumId, diskFile, startPos));
            startPos++;
        }

        String coverFileId = diskFileList.get(0).getFileId();
        diskAlbumRepository.saveDiskAlbum(albumId, coverFileId, num, list);
        return Result.successWithMsg(String.format("当前合集中新添加了 %s 张文件", list.size()));
    }

    /**
     * 调整合集内文件的顺序
     *
     * @param
     * @return
     * @date 2025-09-04 17:47:19
     */
    public Result updateAlbumFilePosition(long albumId, List<String> fileIds) {
        DiskAlbum diskAlbum = diskAlbumMapper.findDiskAlbum(albumId);
        if (diskAlbum == null) {
            return Result.fail("album not exist");
        }

        long loginUser = UserContext.getUserId();
        if (diskAlbum.getCreateBy() != loginUser) {
            return Result.fail("not album owner");
        }

        // fileId -> pos
        Map<String, Integer> positionMap = new HashMap<>();
        int startPos = 1;
        for (int i = 0; i < fileIds.size(); i++) {
            positionMap.put(fileIds.get(i), i+startPos);
        }

        // sha256sum -> fileId
        Map<String, String> map = new HashMap<>();
        diskFileService.findByFileIds(fileIds).forEach(diskFile -> {
                    map.put(diskFile.getSha256sum(), diskFile.getFileId());
                });

        List<DiskAlbumFile> diskAlbumFileList = diskAlbumMapper.findDiskAlbumFileList(albumId, map.keySet());
        for (DiskAlbumFile diskAlbumFile : diskAlbumFileList) {
            int id = diskAlbumFile.getId();
            String sha256sum = diskAlbumFile.getSha256sum();
            Integer pos = positionMap.get(map.get(sha256sum));
            if (pos != null) {
                diskAlbumMapper.updateDiskAlbumFilePos(id, pos);
            }
        }

        return Result.success();
    }

    /**
     * 删除合集内的文件
     *
     * @param
     * @return
     * @date 2025-09-04 17:48:05
     */
    public Result deleteAlbumFile(long albumId, List<String> fileIds) {
        DiskAlbum diskAlbum = diskAlbumMapper.findDiskAlbum(albumId);
        if (diskAlbum == null) {
            return Result.fail("album not exist");
        }

        long loginUser = UserContext.getUserId();
        if (diskAlbum.getCreateBy() != loginUser) {
            return Result.fail("not album owner");
        }

        Set<String> deletedSha256sumSet = diskFileService.findByFileIds(fileIds).stream()
                .map(DiskFile::getSha256sum)
                .collect(Collectors.toSet());

        int num = diskAlbum.getNum()-deletedSha256sumSet.size();
        if (!deletedSha256sumSet.isEmpty()) {
            diskAlbumRepository.deleteDiskAlbumFiles(albumId, num, deletedSha256sumSet);
        }

        DiskFile diskFile = diskFileService.findByFileId(diskAlbum.getCoverFileId());
        if (diskFile != null && deletedSha256sumSet.contains(diskFile.getSha256sum())) {
            List<DiskAlbumFile> diskAlbumFileList = diskAlbumMapper.findDiskAlbumFiles(albumId);
            String coverFileId = "";
            if (!diskAlbumFileList.isEmpty()) {
                String sha256sum = diskAlbumFileList.get(diskAlbumFileList.size()-1).getSha256sum();
                List<DiskFile> diskFileList = diskFileService.findBySha256sum(sha256sum);
                if (!diskFileList.isEmpty()) {
                    coverFileId = diskFileList.get(0).getFileId();
                }
            }

            diskAlbumMapper.updateDiskAlbumCover(albumId, coverFileId);
        }

        return Result.success();
    }

    public List<SelectOption> getAlbumKeyValues() {
        long loginUser = UserContext.getUserId();
        return diskAlbumMapper.findByCreateBy(loginUser).stream().map(diskAlbum -> {
            long albumId = diskAlbum.getAlbumId();
            String albumName = diskAlbum.getAlbumName();
            return new SelectOption(albumName, albumId+"");
        }).collect(Collectors.toList());
    }

    public List<DiskAlbumInfo> getAlbumList() {
        long loginUser = UserContext.getUserId();
        int albumType = AlbumType.image.getValue();
        List<Long> albumIds = diskShareService.getSharedAlbumIds(albumType, loginUser);
        List<DiskAlbum> sharedAlbums = albumIds.stream().map(diskAlbumMapper::findDiskAlbum)
                .filter(Objects::nonNull)
                .peek(this::setSharedAlbumName)
                .collect(Collectors.toList());
        List<DiskAlbum> userAlbums = diskAlbumMapper.findByCreateBy(loginUser);
        userAlbums.addAll(sharedAlbums);

        return userAlbums.stream().map(diskAlbum -> {
            String coverUrl = "";
            try {
                String coverFileId = diskAlbum.getCoverFileId();
                coverUrl = ossService.getSignedUrl(coverFileId, null);
            } catch (Exception e) {
                log.error("getSignedUrl error: {}", e.getMessage());
            }
            return new DiskAlbumInfo(diskAlbum, coverUrl);
        }).collect(Collectors.toList());
    }

    private void setSharedAlbumName(DiskAlbum diskAlbum) {
        long createBy = diskAlbum.getCreateBy();
        AccountAvatar accountAvatar = accountQuery.getAccountAvatar(createBy);
        String username = accountAvatar.getUsername();
        String albumName = String.format("%s(%s的分享)", diskAlbum.getAlbumName(), username);
        diskAlbum.setAlbumName(albumName);
    }

    public DiskAlbumDetail getDiskAlbumDetail(long albumId, int pageNumber) {
        long loginUser = UserContext.getUserId();
        int albumType = AlbumType.image.getValue();
        Set<Long> sharedAlbumSet = new HashSet<>(diskShareService.getSharedAlbumIds(albumType, loginUser));
        DiskAlbum diskAlbum = diskAlbumMapper.findDiskAlbum(albumId);
        if (diskAlbum == null) {
            return null;
        } else if (diskAlbum.getCreateBy() != loginUser && !sharedAlbumSet.contains(albumId)) {
            return null;
        }

        if (sharedAlbumSet.contains(albumId)) {
            setSharedAlbumName(diskAlbum);
        }

        int total = diskAlbumMapper.countDiskAlbumFile(albumId);
        Page page = new Page(pageNumber, pageSize);
        List<DiskAlbumFile> diskAlbumFileList = diskAlbumMapper.findDiskAlbumFileByPage(page, albumId);
        List<String> sha256sumList = diskAlbumFileList.stream().map(DiskAlbumFile::getSha256sum).collect(Collectors.toList());
        if (sha256sumList.isEmpty()) {
            return new DiskAlbumDetail(diskAlbum, PageList.empty());
        }

        Map<String, Integer> map = new HashMap<>();
        for (DiskAlbumFile diskAlbumFile : diskAlbumFileList) {
            map.put(diskAlbumFile.getSha256sum(), diskAlbumFile.getPos());
        }

        List<DiskFileDetail> diskFileDetailList = diskFileService.findBySha256sumList(sha256sumList).stream()
                .sorted(Comparator.comparingInt(o -> map.get(o.getSha256sum())))
                .map(diskFile -> {
                    String objectId = diskFile.getFileId();
                    return diskFileService.getDiskFileDetail(channelCode, objectId);
                })
                .filter(Objects::nonNull)
                .collect(Collectors.toList());

        PageList<DiskFileDetail> pageList = PageList.pageList(pageNumber, pageSize, total, diskFileDetailList);
        return new DiskAlbumDetail(diskAlbum, pageList);
    }

    /**
     * 获取不存在于合集中的文件
     *
     * @param
     * @return
     * @date 2025-09-04 17:42:38
     */
    public PageList<DiskFileDetail> getAlbumExcludeFiles(int fileType, int pageNumber) {
        long loginUser = UserContext.getUserId();
        Page page = new Page(pageNumber, pageSize);
        List<DiskFile> diskFileList = diskFileMapper.findSha256sumGroupByPage(page, fileType, loginUser);
        int total = diskFileMapper.countSha256sumGroupByDiskQuery(fileType, loginUser).size();

        List<DiskFileDetail> list = diskFileList.stream().map(DiskFileDetail::new).collect(Collectors.toList());
        for (DiskFileDetail diskFileDetail : list) {
            String fileId = diskFileDetail.getFileId();
            try {
                String signedUrl = ossService.getSignedUrl(fileId, null);
                diskFileDetail.setUrl(signedUrl);
            } catch (Exception e) {
                e.printStackTrace();
            }
        }
        return PageList.pageList(pageNumber, pageSize, total, list);
    }
}
