package tech.easyflow.ai.permission;

import jakarta.servlet.http.HttpServletRequest;
import org.springframework.stereotype.Component;
import org.springframework.web.context.request.RequestContextHolder;
import org.springframework.web.context.request.ServletRequestAttributes;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.entity.WorkflowShare;
import tech.easyflow.ai.service.KnowledgeShareAuditService;
import tech.easyflow.ai.service.WorkflowShareService;
import tech.easyflow.ai.share.WorkflowSharePolicy;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.system.enums.CategoryResourceType;
import tech.easyflow.system.enums.ResourceAction;
import tech.easyflow.system.permission.resource.ResourceAccessGrantProvider;
import tech.easyflow.system.permission.resource.VisibilityResource;

import java.math.BigInteger;
import java.util.Map;

/**
 * 基于工作流分享密钥补充协作编辑权限。
 */
@Component
public class WorkflowShareResourceAccessGrantProvider implements ResourceAccessGrantProvider {

    private static final String AUDIT_RECORDED_ATTRIBUTE =
            WorkflowShareResourceAccessGrantProvider.class.getName() + ".AUDIT_RECORDED";

    private final WorkflowShareService workflowShareService;
    private final KnowledgeShareAuditService knowledgeShareAuditService;

    /**
     * 创建工作流分享授权提供器。
     *
     * @param workflowShareService 工作流分享服务
     * @param knowledgeShareAuditService 分享审计服务
     */
    public WorkflowShareResourceAccessGrantProvider(
            WorkflowShareService workflowShareService,
            KnowledgeShareAuditService knowledgeShareAuditService
    ) {
        this.workflowShareService = workflowShareService;
        this.knowledgeShareAuditService = knowledgeShareAuditService;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public boolean grants(
            LoginAccount loginAccount,
            CategoryResourceType resourceType,
            VisibilityResource resource,
            ResourceAction action
    ) {
        if (resourceType != CategoryResourceType.WORKFLOW
                || !(resource instanceof Workflow workflow)
                || loginAccount == null
                || !WorkflowSharePolicy.isAllowedRequest(
                        currentRequestMethod(),
                        currentRequestUri(),
                        action
                )) {
            return false;
        }
        return isSharedRequestFor(workflow.getId(), loginAccount);
    }

    /**
     * 判断当前请求是否携带指定工作流的有效分享密钥。
     *
     * @param workflowId 工作流 ID
     * @param loginAccount 当前登录账号
     * @return 未携带分享密钥时返回 {@code false}，携带有效密钥时返回 {@code true}
     */
    public boolean isSharedRequestFor(BigInteger workflowId, LoginAccount loginAccount) {
        HttpServletRequest request = currentRequest();
        if (request == null) {
            return false;
        }
        String shareKey = request.getHeader(WorkflowSharePolicy.SHARE_KEY_HEADER);
        if (shareKey == null || shareKey.isBlank()) {
            return false;
        }
        WorkflowShare share = workflowShareService.assertUrlShareAccess(
                shareKey,
                workflowId,
                loginAccount == null ? null : loginAccount.getTenantId()
        );
        recordSharedOperation(request, share, loginAccount);
        return true;
    }

    /**
     * 每个请求只记录一次工作流分享操作审计。
     *
     * @param request 当前请求
     * @param share 分享记录
     * @param loginAccount 当前登录账号
     */
    private void recordSharedOperation(
            HttpServletRequest request,
            WorkflowShare share,
            LoginAccount loginAccount
    ) {
        if (Boolean.TRUE.equals(request.getAttribute(AUDIT_RECORDED_ATTRIBUTE))) {
            return;
        }
        request.setAttribute(AUDIT_RECORDED_ATTRIBUTE, Boolean.TRUE);
        knowledgeShareAuditService.log(
                loginAccount.getId(),
                "使用工作流协作分享",
                "WORKFLOW_SHARE_ACCESS",
                request.getRequestURI(),
                Map.of(
                        "workflowId", share.getWorkflowId(),
                        "shareId", share.getId(),
                        "method", request.getMethod()
                )
        );
    }

    /**
     * 获取当前 HTTP 请求。
     *
     * @return 当前请求，不在 Web 请求中时返回 {@code null}
     */
    private HttpServletRequest currentRequest() {
        if (!(RequestContextHolder.getRequestAttributes() instanceof ServletRequestAttributes attributes)) {
            return null;
        }
        return attributes.getRequest();
    }

    /**
     * 获取当前请求方法。
     *
     * @return 请求方法
     */
    private String currentRequestMethod() {
        HttpServletRequest request = currentRequest();
        return request == null ? null : request.getMethod();
    }

    /**
     * 获取当前请求路径。
     *
     * @return 请求路径
     */
    private String currentRequestUri() {
        HttpServletRequest request = currentRequest();
        return request == null ? null : request.getRequestURI();
    }
}
