package tech.easyflow.admin.controller.agent;

import cn.dev33.satoken.annotation.SaCheckPermission;
import cn.dev33.satoken.annotation.SaMode;
import org.springframework.http.CacheControl;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PathVariable;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RequestParam;
import org.springframework.web.bind.annotation.RestController;
import org.springframework.web.servlet.mvc.method.annotation.StreamingResponseBody;
import tech.easyflow.agent.entity.AgentArtifact;
import tech.easyflow.agent.runtime.artifact.AgentArtifactService;
import tech.easyflow.agent.runtime.artifact.AgentArtifactView;
import tech.easyflow.common.domain.Result;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.web.exceptions.BusinessException;

import java.io.InputStream;
import java.math.BigInteger;
import java.nio.charset.StandardCharsets;

/**
 * Agent Artifact 安全元数据与鉴权下载控制器。
 */
@RestController
@RequestMapping("/api/v1/agent/artifacts")
public class AgentArtifactController {

    private final AgentArtifactService artifactService;

    /**
     * 创建 Artifact 控制器。
     *
     * @param artifactService Artifact 服务
     */
    public AgentArtifactController(AgentArtifactService artifactService) {
        this.artifactService = artifactService;
    }

    /**
     * 查询一个已鉴权 Artifact 的安全元数据。
     *
     * @param artifactId 稳定 Artifact ID
     * @return 安全元数据
     */
    @GetMapping("/{artifactId}")
    @SaCheckPermission(value = {"/api/v1/agent/session/query", "/api/v1/agent/save"}, mode = SaMode.OR)
    public Result<AgentArtifactView> metadata(@PathVariable String artifactId,
                                              @RequestParam BigInteger agentId,
                                              @RequestParam String mode,
                                              @RequestParam(required = false) BigInteger sessionId,
                                              @RequestParam(required = false) String runtimeSessionId) {
        AgentArtifact artifact = artifactService.requireDownload(
                artifactId, requireAccount(), agentId, mode, sessionId, runtimeSessionId);
        return Result.ok(artifactService.toView(artifact));
    }

    /**
     * 通过后端鉴权代理流式下载私有 Artifact。
     *
     * @param artifactId 稳定 Artifact ID
     * @return 私有流式响应
     */
    @GetMapping("/{artifactId}/content")
    @SaCheckPermission(value = {"/api/v1/agent/session/query", "/api/v1/agent/save"}, mode = SaMode.OR)
    public ResponseEntity<StreamingResponseBody> content(@PathVariable String artifactId,
                                                         @RequestParam BigInteger agentId,
                                                         @RequestParam String mode,
                                                         @RequestParam(required = false) BigInteger sessionId,
                                                         @RequestParam(required = false) String runtimeSessionId) {
        AgentArtifact artifact = artifactService.requireDownload(
                artifactId, requireAccount(), agentId, mode, sessionId, runtimeSessionId);
        StreamingResponseBody body = output -> {
            try (InputStream input = artifactService.openDownload(artifact)) {
                input.transferTo(output);
            }
        };
        String mimeType = artifact.getMimeType() == null
                ? MediaType.APPLICATION_OCTET_STREAM_VALUE : artifact.getMimeType();
        return ResponseEntity.ok()
                .cacheControl(CacheControl.noStore())
                .header(HttpHeaders.CONTENT_DISPOSITION, ContentDisposition.attachment()
                        .filename(artifact.getFileName(), StandardCharsets.UTF_8).build().toString())
                .header("X-Content-Type-Options", "nosniff")
                .contentType(MediaType.parseMediaType(mimeType))
                .contentLength(artifact.getSizeBytes() == null ? 0L : artifact.getSizeBytes())
                .body(body);
    }

    private LoginAccount requireAccount() {
        try {
            LoginAccount account = SaTokenUtil.getLoginAccount();
            if (account == null || account.getId() == null || account.getTenantId() == null) {
                throw new BusinessException("当前登录状态失效，请重新登录后再试");
            }
            return account;
        } catch (BusinessException error) {
            throw error;
        } catch (Exception error) {
            throw new BusinessException("当前登录状态失效，请重新登录后再试");
        }
    }
}
