package com.yingpaipay.business.controller;

import com.yingpaipay.business.domain.Document;
import com.yingpaipay.business.domain.dto.WpsGetVersionsDto;
import com.yingpaipay.business.domain.dto.WpsR;
import com.yingpaipay.business.domain.dto.WpsVersionControlDto;
import com.yingpaipay.business.domain.dto.WpsVersionDto;
import com.yingpaipay.business.service.impl.CommonDocumentService;
import jakarta.servlet.http.HttpServletRequest;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.dromara.common.core.domain.R;
import org.dromara.common.core.exception.BusinessException;
import org.dromara.common.core.utils.StringUtils;
import org.dromara.common.json.utils.JsonUtils;
import org.dromara.common.oss.core.OssClient;
import org.dromara.common.oss.entity.UploadResult;
import org.dromara.common.oss.factory.OssFactory;
import org.dromara.common.web.core.BaseController;
import org.dromara.system.domain.SysOssExt;
import org.dromara.system.domain.SysUser;
import org.dromara.system.domain.vo.SysOssVo;
import org.dromara.system.domain.vo.SysUserVo;
import org.dromara.system.service.ISysOssService;
import org.dromara.system.service.ISysUserService;
import org.springframework.http.MediaType;
import org.springframework.web.bind.annotation.*;

import java.io.File;
import java.io.FileOutputStream;
import java.io.IOException;
import java.io.InputStream;
import java.util.*;
import java.util.concurrent.ConcurrentHashMap;

/**
 * @Author: Huanyi
 * @Description: 由于 WPS 服务对于版本管理非常的麻烦，版本回退一直没有很好的解决方案，因此直接由我们自己负责管理版本。
 */

@Deprecated
@RestController
@RequestMapping("/wps/callback/v3/3rd")
@RequiredArgsConstructor
@Slf4j
public class WpsController extends BaseController {

    /**
     * 这里为版本控制缓存
     */
    private static final Map<Long, WpsVersionControlDto> DOCUMENT_MAP = new ConcurrentHashMap<>();

    private final ISysOssService ossService;
    private final CommonDocumentService documentService;
    private final ISysUserService userService;

    @PutMapping(value = "/upload/file/{documentId}", consumes = MediaType.APPLICATION_OCTET_STREAM_VALUE)
    public void upload(@PathVariable String documentId, HttpServletRequest request) {
        String[] ids = documentId.split("_");
        WpsVersionControlDto dto = DOCUMENT_MAP.get(Long.valueOf(ids[0]));
        File tempFile = null;
        try {

            tempFile = File.createTempFile(dto.getFileName() + "_", dto.getSuffix());

            try (InputStream in = request.getInputStream();
                 FileOutputStream out = new FileOutputStream(tempFile)) {
                byte[] buffer = new byte[8192];
                int bytesRead;
                while ((bytesRead = in.read(buffer)) != -1) {
                    out.write(buffer, 0, bytesRead);
                }
            }

            // 防止自增ID过早炸掉，这里采用更新操作，不使用自带的图片上传
            String originalfileName = tempFile.getName();
            String suffix = StringUtils.substring(originalfileName, originalfileName.lastIndexOf("."));
            OssClient storage = OssFactory.instance();
            UploadResult uploadResult = storage.uploadSuffix(tempFile, suffix, originalfileName);
            dto.setCurrentVersion(Long.parseLong(ids[1]));
            List<WpsVersionDto> versions = dto.getVersions();
            for (WpsVersionDto version : versions) {
                if (Objects.equals(version.getVersion(), Long.valueOf(ids[1]))) {

                    // FIXME 由于原始版本不能被删除,暂时先不实现: 每新增一个版本，就将原始版本上传一个全新的版本
                    // 旧的版本可以不需要了，只需要新的版本
//                    storage.delete(version.getUrl());

                    version.setFileName(uploadResult.getFilename());
                    version.setUrl(uploadResult.getUrl());
                    version.setUpdateTime(new Date());
                }
            }

        } catch (IOException e) {
            log.error("文件写入失败, documentId={}", documentId, e);
        } finally {
            if (tempFile != null && tempFile.exists()) {
                boolean deleted = tempFile.delete();
                if (!deleted) {
                    log.warn("临时文件删除失败: {}", tempFile.getAbsolutePath());
                }
            }
        }
    }

    private record WpsFilesCompleteRequestDto(
        String file_id, Object request, String name, Integer size, Map<String, String> digest, Boolean is_manual, Object response, Integer status_code
    ) {}
    private record WpsFilesCompleteResponseDto(
        String id, String name, Integer version, Integer size, Integer create_time, Integer modify_time, String creator_id, String modifier_id
    ) {}

    @PostMapping("/files/{documentId}/upload/complete")
    public WpsR complete(@PathVariable String documentId, @RequestBody WpsFilesCompleteRequestDto dto) {
        Map<String, Object> request = (LinkedHashMap<String, Object>) dto.request;
        return WpsR.ok(
            new WpsFilesCompleteResponseDto(
                String.valueOf(request.get("file_id")), String.valueOf(request.get("name")), 1, Integer.valueOf(String.valueOf(request.get("size"))), Math.toIntExact(System.currentTimeMillis() / 1000L), Math.toIntExact(System.currentTimeMillis() / 1000L), "1", "1"
            )
        );
    }

    private record WpsUplaodPrepareDto(String[] digest_types) {}

    @GetMapping("/files/{documentId}/upload/prepare")
    public WpsR<WpsUplaodPrepareDto> uploadPrepare(@PathVariable String documentId) {
        String[] types = {"md5"};
        return WpsR.ok(new WpsUplaodPrepareDto(types));
    }

    private record WpsUploadAddressRequestDto(
        String file_id, String name, Integer size, Map<String, String> digest, Boolean is_manual, Integer attachment_size, String content_type
    ) {}

    private record WpsUploadAddressResponseDto(String method, String url) {}

    @PostMapping("/files/{documentId}/upload/address")
    public WpsR uploadAddress(@PathVariable String documentId, @RequestBody WpsUploadAddressRequestDto dto) {
        return WpsR.ok(new WpsUploadAddressResponseDto("PUT", "http://yp1.yingpaipay.com:9029/wps/callback/v3/3rd/upload/file/" + documentId));
    }

    private record WpsGetFileInfoDto(
        String id, String name, Integer version, Integer size, Integer create_time, Integer modify_time, String creator_id, String modifier_id
    ) {}

    @GetMapping("/files/{documentId}")
    public WpsR<WpsGetFileInfoDto> getFileInfo(@PathVariable String documentId) {
        String[] ids = documentId.split("_");
        long id = Long.parseLong(ids[0]);
        long version = Long.parseLong(ids[1]);

        if (DOCUMENT_MAP.containsKey(id)) {
            WpsVersionControlDto dto = DOCUMENT_MAP.get(id);
            return WpsR.ok(new WpsGetFileInfoDto(
                documentId, dto.getFileName(), 1, dto.getSize(), Math.toIntExact(new Date().getTime() / 1000L), Math.toIntExact(new Date().getTime() / 1000L), dto.getCreator(), dto.getUpdator()
            ));
        }
        WpsVersionControlDto dto = initDocument(id);
        return WpsR.ok(new WpsGetFileInfoDto(
            documentId, dto.getFileName(), 1, dto.getSize(), Math.toIntExact(new Date().getTime() / 1000L), Math.toIntExact(new Date().getTime() / 1000L), dto.getCreator(), dto.getUpdator()
        ));
    }

    private record WpsFilesPermissionDto(
        String user_id, Integer read, Integer update, Integer download, Integer rename, Integer history, Integer copy, Integer print, Integer saves, Integer comment
    ) {}

    /**
     * 随便写的,没必要划分的这么细致
     */
    @GetMapping("/files/{documentId}/permission")
    public WpsR permission(@PathVariable String documentId) {
        return WpsR.ok(
            new WpsFilesPermissionDto(
                "1", 1, 1, 1, 1, 1, 1, 1, 1, 1
            )
        );
    }

    private record WpsGetUrlDto(String url) {}

    @GetMapping("/files/{documentId}/download")
    public WpsR getUrl(@PathVariable String documentId) {
        String[] ids = documentId.split("_");
        long id = Long.parseLong(ids[0]);
        long version = Long.parseLong(ids[1]);

        if (DOCUMENT_MAP.containsKey(id)) {
            WpsVersionControlDto dto = DOCUMENT_MAP.get(id);
            List<WpsVersionDto> versions = dto.getVersions();
            for (WpsVersionDto versionDto : versions) {
                if (versionDto.getVersion() == version) {
                    return WpsR.ok(new WpsGetUrlDto(versionDto.getUrl()));
                }
            }
            return WpsR.ok(new WpsGetUrlDto(dto.getVersions().get(0).getUrl()));
        }

        WpsVersionControlDto dto = initDocument(id);
        List<WpsVersionDto> versions = dto.getVersions();
        for (WpsVersionDto versionDto : versions) {
            if (Objects.equals(versionDto.getVersion(), dto.getCurrentVersion())) {
                return WpsR.ok(new WpsGetUrlDto(versionDto.getUrl()));
            }
        }
        return WpsR.ok(new WpsGetUrlDto(dto.getVersions().get(0).getUrl()));
    }

    @GetMapping("/files/{documentId}/versions/{version}/download")
    public WpsR getUrlByVersion(@PathVariable String documentId, @PathVariable Integer version) {
        if (DOCUMENT_MAP.containsKey(Long.valueOf(documentId.split("_")[0]))) {
            WpsVersionControlDto dto = DOCUMENT_MAP.get(Long.valueOf(documentId.split("_")[0]));
            return WpsR.ok(new WpsGetUrlDto(dto.getVersions().get(Integer.parseInt(documentId.split("_")[1])).getUrl()));
        }
        WpsVersionControlDto dto = initDocument(Long.valueOf(documentId.split("_")[0]));
        return WpsR.ok(new WpsGetUrlDto(dto.getVersions().get(0).getUrl()));
    }

    private record WpsGetUsersDto(String id, String name, String avatar_url) {}

    @GetMapping("/users")
    public WpsR getUsers(@RequestParam("user_ids") Long[] userIds) {
        if (userIds == null || userIds.length == 0) {
            return WpsR.ok();
        }
        List<SysUser> vos = userService.selectUserByIds(Arrays.stream(userIds).toList());
        List<Long> ossIds = new ArrayList<>();
        vos.forEach(e -> ossIds.add(e.getAvatar()));
        List<SysOssVo> ossVos = ossService.queryListByIds(ossIds);
        List<WpsGetUsersDto> dtos = new ArrayList<>();
        for (SysUser vo : vos) {
            String url = "";
            for (SysOssVo ossVo : ossVos) {
                if (ossVo.getOssId().equals(vo.getAvatar())) {
                    url = ossVo.getUrl();
                }
            }
            dtos.add(new WpsGetUsersDto(String.valueOf(vo.getUserId()), vo.getNickName(), url));
        }
        return WpsR.ok(dtos);
    }

    @PostMapping(value = "/init/{documentId}")
    public R init(@PathVariable Long documentId) {
        if (DOCUMENT_MAP.containsKey(documentId)) {
            throw new BusinessException("已有其他人正在审核该文件");
        }
        initDocument(documentId);
        return R.ok(DOCUMENT_MAP.get(documentId).getCurrentVersion());
    }

    private WpsVersionControlDto initDocument(Long ossId) {
        SysOssVo ossVo = ossService.getById(ossId);
        Document document = documentService.getByOssId(ossId);
        if (DOCUMENT_MAP.containsKey(document.getId())) {
            throw new BusinessException("已有其他人正在审核该文件");
        }
        long currentVersion = System.currentTimeMillis();
        List<WpsVersionDto> list = new ArrayList<>();
        list.add(new WpsVersionDto(ossVo.getFileName(), 0L, ossVo.getUrl(), new Date(), new Date(), Math.toIntExact(document.getCreateTime().getTime() / 1000L), Math.toIntExact(document.getUpdateTime().getTime() / 1000L)));
        list.add(new WpsVersionDto(ossVo.getFileName(), currentVersion, ossVo.getUrl(), new Date(), new Date(), Math.toIntExact(document.getCreateTime().getTime() / 1000L), Math.toIntExact(document.getUpdateTime().getTime() / 1000L)));
        WpsVersionControlDto dto = new WpsVersionControlDto();
        dto.setCurrentVersion(currentVersion);
        dto.setVersions(list);
        dto.setSuffix(ossVo.getFileSuffix());
        dto.setCreator(String.valueOf(document.getCreateBy()));
        dto.setUpdator(String.valueOf(document.getUpdateBy()));
        dto.setFileName(ossVo.getOriginalName());
        SysOssExt ext = JsonUtils.parseObject(ossVo.getExt1(), SysOssExt.class);
        long size = ext.getFileSize();
        dto.setSize((int) size);
        DOCUMENT_MAP.put(ossId, dto);
        return dto;
    }

    @PutMapping("/clean/{documentId}")
    public R clean(@PathVariable Long documentId) {
        WpsVersionControlDto dto = DOCUMENT_MAP.get(documentId);
        long currentVersion = System.currentTimeMillis();
        dto.getVersions().add(new WpsVersionDto(
            dto.getVersions().get(0).getFileName(), currentVersion, dto.getVersions().get(0).getUrl(), new Date(), new Date(), Math.toIntExact(new Date().getTime() / 1000L), Math.toIntExact(new Date().getTime() / 1000L)
        ));
        dto.setCurrentVersion(currentVersion);
        log.info("自行进行刷新版本");
        dto.getVersions().forEach(e -> log.info("{}", JsonUtils.toJsonString(e)));
        return R.ok(currentVersion);
    }

    /**
     * 已废弃
     */
    @GetMapping("/files/{documentId}/versions")
    public WpsR getVersions(@PathVariable Long documentId, @RequestParam(value = "offset", required = false) Integer offset, @RequestParam(value = "limit", required = false) Integer size) {
        WpsVersionControlDto dto = DOCUMENT_MAP.get(documentId);
        List<WpsVersionDto> versions = dto.getVersions();

        List<WpsVersionDto> reversed = new ArrayList<>(versions);
        Collections.reverse(reversed);

        if (offset == null || size == null) {
            return WpsR.ok(reversed);
        }

        int fromIndex = Math.min(offset, reversed.size());
        int toIndex = Math.min(offset + size, reversed.size());

        List<WpsVersionDto> paginated = reversed.subList(fromIndex, toIndex);

        List<WpsGetVersionsDto> list = new ArrayList<>();
        paginated.forEach(e -> list.add(new WpsGetVersionsDto(
            String.valueOf(documentId), dto.getFileName(), Math.toIntExact(e.getVersion() / 1000L), dto.getSize(), e.getCreate_time(), e.getUpdate_time(), dto.getCreator(), dto.getUpdator()
        )));

        WpsR<List<WpsGetVersionsDto>> r = WpsR.ok(list);
        String str = JsonUtils.toJsonString(r);
        log.warn(str);
        return r;
    }

    /**
     * 已废弃
     */
    @GetMapping("/files/{documentId}/versions/{version}")
    public WpsR getFileByVersion(@PathVariable Long documentId, @PathVariable Integer version) {
        WpsVersionControlDto dto = DOCUMENT_MAP.get(documentId);
        WpsVersionDto current = dto.getVersions().get(version - 1);
        return WpsR.ok(new WpsGetVersionsDto(
            String.valueOf(documentId), dto.getFileName(), Math.toIntExact(current.getVersion() / 1000L), dto.getSize(), current.getCreate_time(), current.getUpdate_time(), dto.getCreator(), dto.getUpdator()
        ));
    }

    @GetMapping("/files/list")
    public R<List<WpsVersionDto>> getVersionList(@RequestParam("ossId") Long ossId) {
        List<WpsVersionDto> list = DOCUMENT_MAP.get(ossId).getVersions();
        list.forEach(e -> log.info("{}", JsonUtils.toJsonString(e)));
        return R.ok(list.stream().filter(e -> e.getVersion() != 0L).sorted((e1, e2) -> Math.toIntExact(e2.getVersion() - e1.getVersion())).toList());
    }

    @GetMapping("/getFinal")
    public R<SysOssVo> getFinal(@RequestParam("id") String id) {
        String[] ids = id.split("_");
        long documentId = Long.parseLong(ids[0]);
        long version = Long.parseLong(ids[1]);

        log.info("文档编号为 {}, 版本号为 : {}", documentId, version);

        WpsVersionControlDto dto = DOCUMENT_MAP.get(documentId);
        List<WpsVersionDto> versions = dto.getVersions();
        for (WpsVersionDto versionDto : versions) {
            log.info("当前轮询的版本号为 {}", versionDto.getVersion());
            if (versionDto.getVersion() == version) {
                String url = versionDto.getUrl();
                SysOssVo vo = ossService.insertByUrl(versionDto.getFileName(), dto.getFileName(), url);
                DOCUMENT_MAP.remove(documentId);
                return R.ok(vo);
            }
        }
        throw new BusinessException("审核内容保存失败");
    }

    @DeleteMapping("/cancel/{documentId}")
    public R<Void> cancel(@PathVariable Long documentId) {
        DOCUMENT_MAP.remove(documentId);
        return R.ok();
    }

}
