package com.zt.plat.module.qms.resource.record.controller.admin.onlyOffice.service;

import cn.hutool.core.util.StrUtil;
import cn.hutool.jwt.JWT;
import com.zt.plat.framework.common.pojo.CommonResult;
import com.zt.plat.framework.security.core.util.SecurityFrameworkUtils;
import com.zt.plat.module.infra.api.businessfile.BusinessFileApi;
import com.zt.plat.module.infra.api.file.FileApi;
import com.zt.plat.module.infra.api.file.dto.FileRespDTO;
import com.zt.plat.module.qms.resource.record.controller.admin.onlyOffice.controller.vo.OnlyOfficeEditorConfigRespVO;
import com.zt.plat.module.system.api.user.AdminUserApi;
import com.zt.plat.module.system.api.user.dto.AdminUserRespDTO;
import jakarta.annotation.Resource;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.validation.annotation.Validated;

import static com.zt.plat.framework.common.exception.util.ServiceExceptionUtil.exception;
import static com.zt.plat.module.infra.enums.ErrorCodeConstants.DOC_NOT_EXISTS;

@Service
@Validated
@Slf4j
public class OnlyOfficeServiceImpl implements OnlyOfficeService{

    @Resource
    private AdminUserApi adminUserApi;

    private static final String TEXT_DOCUMENT_EXTENSIONS = "doc,docx,odt,rtf,txt,html,htm,mht,pdf,djvu,fb2,epub,xps";
    private static final String SPREADSHEET_EXTENSIONS = "xls,xlsx,ods,csv";
    private static final String PRESENTATION_EXTENSIONS = "ppt,pptx,odp";

    // 文档类型常量
    private static final String DOCUMENT_TYPE_TEXT = "text";
    private static final String DOCUMENT_TYPE_SPREADSHEET = "spreadsheet";
    private static final String DOCUMENT_TYPE_PRESENTATION = "presentation";

    @Value("${onlyoffice.base-url:http://localhost:8085}")
    private String onlyOfficeBaseUrl;
    @Value("${onlyoffice.callback-base-url:http://host.docker.internal:48080}")
    private String onlyOfficeCallbackBaseUrl;
    @Value("${onlyoffice.jwt-secret:P@ssword25}")
    private String onlyOfficeJwtSecret;


    private String getDocumentType(String fileExtension) {
        if (StrUtil.isEmpty(fileExtension)) {
            return DOCUMENT_TYPE_TEXT;
        }

        String ext = fileExtension.toLowerCase();

        // 文本文档类型
        if (TEXT_DOCUMENT_EXTENSIONS.contains(ext)) {
            return DOCUMENT_TYPE_TEXT;
        }

        // 电子表格类型
        if (SPREADSHEET_EXTENSIONS.contains(ext)) {
            return DOCUMENT_TYPE_SPREADSHEET;
        }

        // 演示文稿类型
        if (PRESENTATION_EXTENSIONS.contains(ext)) {
            return DOCUMENT_TYPE_PRESENTATION;
        }

        // 默认返回text类型
        return DOCUMENT_TYPE_TEXT;
    }

    public String generateFileToken(Long fileId) {
        String fileToken = "";
        if (StrUtil.isNotBlank(onlyOfficeJwtSecret)) {
            // 创建文件访问token，包含fileId和过期时间（1小时后过期）
            long expTime = System.currentTimeMillis() / 1000 + 3600; // 1小时后过期
            fileToken = JWT.create()
                    .setPayload("fileId", fileId)
                    .setPayload("exp", expTime)
                    .setPayload("iat", System.currentTimeMillis() / 1000)
                    .setKey(onlyOfficeJwtSecret.getBytes())
                    .sign();
        }
        return fileToken;
    }

    @Resource
    private FileApi fileApi;

    @Override
    public OnlyOfficeEditorConfigRespVO getEditorConfig(Long id) {
//        DocFileDO doc = docFileMapper.selectById(id);
//        if (doc == null) {
//            throw exception(DOC_NOT_EXISTS);
//        }
        Long userId = SecurityFrameworkUtils.getLoginUserId();
        OnlyOfficeEditorConfigRespVO resp = new OnlyOfficeEditorConfigRespVO();

//        // 根据文件类型动态设置文档类型
//        String documentType = getDocumentType(doc.getFileType());
//        resp.setDocumentType(documentType);
//
//        DocEditorConfigRespVO.DocumentConfig document = new DocEditorConfigRespVO.DocumentConfig();
//        document.setFileType(doc.getFileType());
//
//        // 关键修复：使用基于文档版本的稳定key策略
//        // 只有当文档内容真正发生版本变更时，key才会改变
//        String documentKey;
//        if (doc.getLatestVersionId() != null) {
//            // 使用文档ID + 最新版本ID，确保同一版本在编辑期间key保持不变
//            documentKey = doc.getId() + "_v" + doc.getLatestVersionId();
//        } else {
//            // 如果没有版本信息，使用文档ID + 创建时间（不会变化）
//            documentKey = doc.getId() + "_init_" + doc.getCreateTime().toEpochSecond(java.time.ZoneOffset.UTC);
//        }
//
//        document.setKey(documentKey);
//        document.setTitle(doc.getTitle());
//
//        log.info("生成文档key: docId={}, key={}, latestVersionId={}, userId={}",
//                doc.getId(), documentKey, doc.getLatestVersionId(), userId);
//
//        // 使用新的接口生成文件 URL
//        String fileUrl = "";
//        if (doc.getFileId() != null) {
//            // 生成文件访问的JWT token
//            String fileToken = generateFileToken(doc.getFileId());
//
//            // 生成通过新接口访问文件的URL，包含JWT token
//            fileUrl = StrUtil.removeSuffix(onlyOfficeCallbackBaseUrl, "/") + "/admin-api/infra/doc-file/file-content?fileId=" + doc.getFileId();
//            if (StrUtil.isNotBlank(fileToken)) {
//                fileUrl += "&token=" + fileToken;
//            }
//        }
//        document.setUrl(fileUrl);

        CommonResult<FileRespDTO> file = fileApi.getFile(id);
        log.info("file:{}",file);
        if (file.getData() == null) throw exception(DOC_NOT_EXISTS);
        FileRespDTO data = file.getData();

        // 根据文件类型动态设置文档类型
        String documentType = getDocumentType(data.getType());
        resp.setDocumentType(documentType);

        OnlyOfficeEditorConfigRespVO.DocumentConfig document = new OnlyOfficeEditorConfigRespVO.DocumentConfig();
        // 获取文件类型，通过后缀名
        String fileName = data.getName();
        String fileType = getFileSuffix(fileName);
        document.setFileType(fileType);

        // 关键修复：使用基于文档版本的稳定key策略
        // 只有当文档内容真正发生版本变更时，key才会改变
        String documentKey;
        // TODO
//        if (doc.getLatestVersionId() != null) {
//            // 使用文档ID + 最新版本ID，确保同一版本在编辑期间key保持不变
//            documentKey = doc.getId() + "_v" + doc.getLatestVersionId();
//        } else {
//            // 如果没有版本信息，使用文档ID + 创建时间（不会变化）
//            documentKey = doc.getId() + "_init_" + doc.getCreateTime().toEpochSecond(java.time.ZoneOffset.UTC);
//        }
//
//        document.setKey(documentKey);
        document.setTitle(fileName);

//        log.info("生成文档key: docId={}, key={}, latestVersionId={}, userId={}",
//                doc.getId(), documentKey, doc.getLatestVersionId(), userId);

        // 使用新的接口生成文件 URL TODO
        String fileUrl = "";
        if (data.getId() != null) {
            // 生成文件访问的JWT token
            String fileToken = generateFileToken(data.getId());

            // 生成通过新接口访问文件的URL，包含JWT token
            fileUrl = StrUtil.removeSuffix(onlyOfficeCallbackBaseUrl, "/") + "/admin-api/infra/doc-file/file-content?fileId=" + data.getId();
            if (StrUtil.isNotBlank(fileToken)) {
                fileUrl += "&token=" + fileToken;
            }
        }
        document.setUrl(fileUrl);


        OnlyOfficeEditorConfigRespVO.Permissions permissions = new OnlyOfficeEditorConfigRespVO.Permissions();
        // TODO 权限
//        permissions.setEdit(hasPermission(id, userId, DocPermissionTypeEnum.EDIT.getType()) || hasPermission(id, userId, DocPermissionTypeEnum.MANAGE.getType()));
        permissions.setEdit(true);
        permissions.setDownload(true);
        permissions.setPrint(true);
        document.setPermissions(permissions);
        resp.setDocument(document);

        OnlyOfficeEditorConfigRespVO.EditorConfig editorConfig = new OnlyOfficeEditorConfigRespVO.EditorConfig();
        // 在回调URL中添加触发用户ID，确保回调时能准确记录操作用户
        String callbackUrl = StrUtil.removeSuffix(onlyOfficeCallbackBaseUrl, "/") +
                "/admin-api/qms/common/only-office/callback?fileId=" + id + "&userId=" + userId;
        editorConfig.setCallbackUrl(callbackUrl);
        editorConfig.setLang("zh-CN");
        editorConfig.setMode(permissions.getEdit() ? "edit" : "view");

        // 重要：设置正确的用户信息以支持多人协作
        OnlyOfficeEditorConfigRespVO.User user = new OnlyOfficeEditorConfigRespVO.User();
        user.setId(String.valueOf(userId));

        // 获取真实用户姓名
        String userName = "User" + userId; // 默认值
        try {
            AdminUserRespDTO userInfo = adminUserApi.getUser(userId).getCheckedData();
            if (userInfo != null && StrUtil.isNotBlank(userInfo.getNickname())) {
                userName = userInfo.getNickname();
            }
        } catch (Exception e) {
            log.warn("获取用户姓名失败，使用默认值，用户ID: {}", userId, e);
        }
        user.setName(userName);
        editorConfig.setUser(user);

        // 添加协作配置
        OnlyOfficeEditorConfigRespVO.CoEditing coEditing = new OnlyOfficeEditorConfigRespVO.CoEditing();
        coEditing.setMode("fast"); // 快速协作模式
        coEditing.setChange(true); // 允许实时变更
        editorConfig.setCoEditing(coEditing);

        resp.setEditorConfig(editorConfig);
        resp.setHeight("100%");
        resp.setDocumentServerUrl(onlyOfficeBaseUrl);

        // 生成 token（可选 JWT）
        if (StrUtil.isNotBlank(onlyOfficeJwtSecret)) {
            // OnlyOffice 标准 JWT payload 格式
            String token = JWT.create()
                    .setPayload("document", resp.getDocument())
                    .setPayload("documentType", resp.getDocumentType())
                    .setPayload("editorConfig", resp.getEditorConfig())
                    .setPayload("height", resp.getHeight())
                    .setKey(onlyOfficeJwtSecret.getBytes())
                    .sign();
            resp.setToken(token);
        } else {
            // 如果没有 JWT secret，不设置 token，让 OnlyOffice 在无验证模式工作
            resp.setToken(null);
        }
        return resp;
    }

    public String getFileSuffix(String fileName){
        //从文件名中最后一个点截取，例：1111.111.222.docx,截取 docx
        if (fileName == null || fileName.isEmpty()) {
            return "";
        }
        int lastDotIndex = fileName.lastIndexOf('.');
        if (lastDotIndex == -1 || lastDotIndex == fileName.length() - 1) {
            return "";
        }
        return fileName.substring(lastDotIndex + 1).toLowerCase();
    }


}
