package com.gzzm.lobster.api;

import com.gzzm.lobster.artifact.Artifact;
import com.gzzm.lobster.artifact.ArtifactService;
import com.gzzm.lobster.audit.AuditService;
import com.gzzm.lobster.common.LobsterException;
import com.gzzm.lobster.identity.UserContext;
import com.gzzm.lobster.identity.UserContextHolder;
import net.cyan.arachne.HttpMethod;
import net.cyan.arachne.annotation.Service;
import net.cyan.nest.annotation.Inject;

import java.util.LinkedHashMap;
import java.util.Map;

/**
 * ArtifactApi —— 工件直写与元信息 API / Artifact direct write + metadata.
 *
 * <p>文档工坊场景下用户手动编辑工件时，不应走 Agent 再经 LLM 写回（见 review A4）。
 * 本接口让前端可以直接持久化编辑后的正文，绕过 Agent 循环但仍写审计。
 */
@Service(url = "/ai/api")
public class ArtifactApi {

    /**
     * 直写单次最大字节数 / Max content size per direct-write call.
     * <p>超过则由 Agent 用 write_file 分片覆盖；1MB 覆盖绝大多数公文/报告长度。
     */
    private static final int MAX_CONTENT_BYTES = 1 * 1024 * 1024;

    @Inject private ArtifactService artifactService;
    @Inject private AuditService auditService;

    /**
     * 覆盖工件正文 / Directly overwrite the artifact body.
     *
     * <p>权限：只能改自己的工件（由 {@link ArtifactService#overwrite} 校验）。
     * 审计：每次成功覆盖记一条 {@code artifact.direct_write}，便于后续追溯。
     *
     * <p>URL 模板：{@code POST /ai/api/artifacts/{id}/update}。
     * arachne 不开放 PUT method（HttpMethod 枚举仅 get/post），
     * 因此用 POST 子路径表达"更新"语义，与 /pending-requests/{id}/resolve 风格一致。
     */
    @Service(url = "/ai/api/artifacts/{$0}/update", method = HttpMethod.post)
    public Map<String, Object> updateArtifact(String artifactId, String content, String title) throws Exception {
        UserContext user = UserContextHolder.require();
        if (artifactId == null || artifactId.isEmpty()) {
            throw new LobsterException("artifact.bad_id", "artifactId required");
        }
        if (content == null) {
            throw new LobsterException("artifact.bad_body", "content required (use empty string to clear)");
        }
        // Fix M1: 直写 size 硬闸；按 UTF-8 字节数算
        int byteLen = content.getBytes(java.nio.charset.StandardCharsets.UTF_8).length;
        if (byteLen > MAX_CONTENT_BYTES) {
            throw new LobsterException("artifact.too_large",
                    "content exceeds direct-write limit (" + MAX_CONTENT_BYTES + " bytes); "
                    + "use write_file in chunks via Agent for oversized artifacts");
        }

        Artifact updated = artifactService.overwrite(artifactId, user, content,
                title == null || title.isEmpty() ? null : title);

        // 审计
        Map<String, Object> detail = new LinkedHashMap<>();
        detail.put("artifactId", updated.getArtifactId());
        detail.put("version", updated.getVersion());
        detail.put("contentSize", updated.getContentSize());
        detail.put("source", "workshop_direct_write");
        auditService.record(user, updated.getThreadId(), null,
                "artifact.direct_write", "artifact", updated.getArtifactId(), "ok", detail);

        Map<String, Object> out = new LinkedHashMap<>();
        out.put("artifactId", updated.getArtifactId());
        out.put("title", updated.getTitle());
        out.put("version", updated.getVersion());
        out.put("contentSize", updated.getContentSize());
        out.put("updateTime", updated.getUpdateTime());
        return out;
    }
}
