package com.zhongshu.card.server.core.service.oss;

import com.github.microservice.core.util.response.ResponseUtil;
import com.github.microservice.net.ResultContent;
import com.github.microservice.net.ResultState;
import com.github.microservice.netdisk.client.example.AccountExample;
import com.github.microservice.netdisk.client.model.file.CopyFileModel;
import com.github.microservice.netdisk.client.model.file.FileItemModel;
import com.github.microservice.netdisk.client.model.file.FileStoreModel;
import com.github.microservice.netdisk.client.model.remote.RemoteFile;
import com.github.microservice.netdisk.client.service.NetDiskOssService;
import com.google.common.collect.Lists;
import com.mongodb.client.gridfs.model.GridFSFile;
import com.zhongshu.card.client.model.base.OidParam;
import com.zhongshu.card.server.core.dao.org.OrganizationDao;
import com.zhongshu.card.server.core.dao.org.UserCountDao;
import com.zhongshu.card.server.core.domain.org.UserAccount;
import com.zhongshu.card.server.core.model.upLoadFile.AliObjectStorageStore;
import com.zhongshu.card.server.core.model.upLoadFile.RemoteBusFile;
import com.zhongshu.card.server.core.model.upLoadFile.RemoteGetTokenFileParam;
import com.zhongshu.card.server.core.model.upLoadFile.StsToken;
import com.zhongshu.card.server.core.model.upLoadFile.oss.ALiObjectStorage;
import com.zhongshu.card.server.core.service.base.SuperService;
import com.zhongshu.card.server.core.util.CommonUtil;
import jakarta.servlet.http.HttpServletResponse;
import lombok.Cleanup;
import lombok.SneakyThrows;
import lombok.extern.slf4j.Slf4j;
import org.apache.commons.io.FilenameUtils;
import org.apache.commons.lang3.ObjectUtils;
import org.apache.commons.lang3.StringUtils;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.data.mongodb.core.query.Criteria;
import org.springframework.data.mongodb.core.query.Query;
import org.springframework.data.mongodb.gridfs.GridFsResource;
import org.springframework.data.mongodb.gridfs.GridFsTemplate;
import org.springframework.stereotype.Service;
import org.springframework.util.StreamUtils;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.io.OutputStream;
import java.util.ArrayList;
import java.util.Collection;
import java.util.List;
import java.util.UUID;
import java.util.stream.Collectors;

/**
 * @author TRX
 * @date 2024/4/10
 */
@Slf4j
@Service
public class NetDiskOssBusService extends SuperService {

    @Autowired
    private AliObjectStorageStore aliObjectStorageStore;

    @Autowired
    ALiObjectStorage aLiObjectStorage;

    @Autowired
    UserCountDao userCountDao;

    @Autowired
    private NetDiskOssService netDiskOssService;

    @Autowired
    private OrganizationDao organizationDao;

    @Autowired
    private GridFsTemplate gridFsTemplate;

    @Value("${gateWay.host:http://172.24.50.53:8080}")
    private String gateWayHost;

    @Value("${spring.application.name}")
    private String applicationName;

    /**
     * @return
     * @param file
     */
    public ResultContent<String> uploadMinioFile(MultipartFile file, OidParam param) throws IOException {
        @Cleanup var inputStream = file.getInputStream();
        String accountId = "";
        if (ObjectUtils.isNotEmpty(param)) {
            accountId = param.getOid();
        }
        if (StringUtils.isEmpty(accountId)) {
            accountId = getCurrentProjectOid();
        }
        if (StringUtils.isEmpty(accountId)) {
            accountId = getCurrentOid();
        }
        if (StringUtils.isEmpty(accountId)) {
            return ResultContent.buildFail("");
        }

        final String filename = CommonUtil.UUID() + "_" + file.getOriginalFilename();
        String mimeTypeName = ResponseUtil.getMimeType(FilenameUtils.getExtension(filename));
        gridFsTemplate.store(inputStream, filename, mimeTypeName).toHexString();
        String url = String.format("%s/%s/oss/dl/%s", gateWayHost, applicationName.toLowerCase(), filename);
        // 通知网盘上传文件
        CopyFileModel copyFileModel = new CopyFileModel();
        copyFileModel.setAccountId(accountId);
        copyFileModel.setUrl(url);
        copyFileModel.setPath(new String[]{"files", filename});

        // 通知网盘拷贝文件
        com.github.microservice.netdisk.client.content.ResultContent<FileStoreModel> fileStoreModelResultContent = this.netDiskOssService.copyFile(copyFileModel);
        //删除文件
        this.gridFsTemplate.delete(makeQuery(filename));
        if (fileStoreModelResultContent.getState() == com.github.microservice.netdisk.client.content.ResultState.Success) {
            FileStoreModel fileStoreModel = fileStoreModelResultContent.getContent();
            return ResultContent.buildSuccess(fileStoreModel.getUrl());
        } else {
            return ResultContent.buildFail(String.format("上传文件失败:%s", fileStoreModelResultContent.getMsg()));
        }
    }

    @SneakyThrows
    public void download(HttpServletResponse response, String filename) {
        GridFSFile gridFSFile = gridFsTemplate.findOne(makeQuery(filename));
        GridFsResource gridFsResource = gridFsTemplate.getResource(gridFSFile);
        @Cleanup InputStream inputStream = gridFsResource.getInputStream();

        // 拷贝流
        @Cleanup OutputStream outputStream = response.getOutputStream();
        response.setContentType(gridFsResource.getContentType());
        response.setContentLengthLong(gridFsResource.contentLength());
        StreamUtils.copy(inputStream, outputStream);
        outputStream.flush();
    }

    public ResultContent<com.github.microservice.netdisk.client.model.token.StsToken> getUploadFileToken(RemoteGetTokenFileParam param) {
        com.github.microservice.netdisk.client.model.remote.RemoteFile remoteFile = new RemoteFile();
        UserAccount user = getCurrentUserAccount();

        Boolean isReserveName = param.getIsReserveName();
        String fileName = param.getFileName();
        List<String[]> allPaths = buildPathByUser(param.getFileNames(), user);
        Collection<String[]> paths = allPaths.parallelStream().map((path) -> {
            String _fileName = path[(path.length - 1)];
            return this.toPlatformFileStoreObjectPath(user, path, isReserveName, _fileName);
        }).collect(Collectors.toList());

        remoteFile.setAccountId(param.getOid());
        remoteFile.setPath(paths);
        com.github.microservice.netdisk.client.content.ResultContent<com.github.microservice.netdisk.client.model.token.StsToken> content = netDiskOssService.getUploadToken(remoteFile);
        if (content.getState() == com.github.microservice.netdisk.client.content.ResultState.Success) {
            return ResultContent.buildSuccess(content.getContent());
        } else {
            return ResultContent.buildFail(content.getMsg());
        }
    }


    public ResultContent<FileStoreModel> uploadFinish(FileItemModel fileItems) {
        FileItemModel[] arr = new FileItemModel[]{fileItems};
        com.github.microservice.netdisk.client.content.ResultContent<List<FileStoreModel>> content = netDiskOssService.uploadFinish(arr);
        if (content.getState() == com.github.microservice.netdisk.client.content.ResultState.Success) {
            List<FileStoreModel> list = content.getContent();
            return ResultContent.buildSuccess(list.get(0));
        } else {
            return ResultContent.buildFail(content.getMsg());
        }
    }

    public ResultContent<List<FileStoreModel>> uploadFinishMuli(FileItemModel[] fileItems) {
        com.github.microservice.netdisk.client.content.ResultContent<List<FileStoreModel>> content = netDiskOssService.uploadFinish(fileItems);
        if (content.getState() == com.github.microservice.netdisk.client.content.ResultState.Success) {
            return ResultContent.buildSuccess(content.getContent());
        } else {
            return ResultContent.buildFail(content.getMsg());
        }
    }

    public ResultContent<StsToken> getUploadToken(RemoteBusFile remoteFile) {
//        PathAssert.validate(remoteFile.getPath());
        String userId = getCurrentUserId();
        UserAccount user = userCountDao.findTopByUserId(userId);
        if (user == null) {
            return ResultContent.build(ResultState.AccountNotExists);
        }
        Boolean isReserveName = remoteFile.getIsReserveName();
        String fileName = remoteFile.getFileName();
        aliObjectStorageStore.setInfo(user.getId(), aLiObjectStorage);
        List<String[]> allPaths = buildPathByUser(remoteFile, user);

        // 获取三方持久化对象
//        final SuperObjectStorageStore objectStorageStore = this.objectStorageStore.getObjectStorageStore(account.getId());
        Collection<String[]> paths = allPaths.parallelStream().map((path) -> {
            String _fileName = path[(path.length - 1)];
            return this.toPlatformFileStoreObjectPath(user, path, isReserveName, fileName);
        }).collect(Collectors.toList());
        StsToken stsToken = aliObjectStorageStore.getStsToken(paths);
        stsToken.setEndPoint(aLiObjectStorage.getShowEndpoint());

        //获取操作文件路径
        return ResultContent.buildContent(stsToken);
    }

    private String[] toPlatformFileStoreObjectPath(final UserAccount account, String[] path, Boolean isReserveName, String fileName) {
        return buildUploadFilePathFromLatestVersion(account, path, isReserveName, fileName);
    }

    public String[] buildUploadFilePathFromLatestVersion(final UserAccount account, String[] sourcePath, Boolean isReserveName, String fileName) {
        //文件版本号
        final Long fileVersionNumber = 1L;
        String countId = "file";
        if (ObjectUtils.isNotEmpty(account)) {
            countId = account.getId();
        }
        return new String[]{String.format("%s", fileName)};
//        return PlatformFileItem.builder().accountId(countId) //账户
//                .versionNumber(fileVersionNumber)//版本
//                .platformStoreType(PlatformStoreType.Store) //类型
//                .sourcePath(sourcePath)//原路径
//                .isReserveName(isReserveName).orgiFileName(fileName).build().toPath(PlatformFileItem.PathType.OSS);
    }

    public List<String[]> buildPathByUser(RemoteBusFile param, UserAccount user) {
        List<String[]> paths = new ArrayList<>();
        String userId;
        if (ObjectUtils.isNotEmpty(user)) {
            userId = user.getId();
        } else {
            userId = "file";
        }
        param.getFileNames().forEach(it -> {
            String[] split = it.split("\\.");
            List<String> path = Lists.newArrayList(new String[]{userId, CommonUtil.UUID() + "." + split[(split.length - 1)]});
            paths.add(path.toArray(new String[0]));
        });
        return paths;
    }

    public List<String[]> buildPathByUser(List<String> fileNames, UserAccount user) {
        List<String[]> paths = new ArrayList<>();
        fileNames.forEach(it -> {
            String[] split = it.split("\\.");
            List<String> path = null;
            if (ObjectUtils.isNotEmpty(user)) {
                path = Lists.newArrayList(new String[]{user.getId(), CommonUtil.UUID() + "." + split[(split.length - 1)]});
            } else {
                path = Lists.newArrayList(new String[]{CommonUtil.UUID() + "." + split[(split.length - 1)]});
            }
            paths.add(path.toArray(new String[0]));
        });
        return paths;
    }

    private Query makeQuery(String filename) {
        return Query.query(Criteria.where("filename").is(filename));
    }

}
