package tech.easyflow.skill.publish;

import com.fasterxml.jackson.databind.ObjectMapper;
import org.springframework.stereotype.Component;
import tech.easyflow.ai.enums.PublishStatus;
import tech.easyflow.ai.publish.AbstractAiResourceLifecycleHandler;
import tech.easyflow.approval.enums.ApprovalResourceType;
import tech.easyflow.approval.service.ApprovalInstanceService;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.skill.entity.Skill;
import tech.easyflow.skill.service.SkillService;
import tech.easyflow.system.enums.CategoryResourceType;
import tech.easyflow.system.enums.ResourceAction;
import tech.easyflow.system.service.ResourceAccessService;

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

/**
 * Skill 审批资源处理器。
 */
@Component
public class SkillApprovalSubjectHandler extends AbstractAiResourceLifecycleHandler<Skill> {

    private final SkillService skillService;
    private final ResourceAccessService resourceAccessService;

    /**
     * 创建 Skill 审批资源处理器。
     *
     * @param approvalInstanceService 审批实例服务
     * @param objectMapper JSON 映射器
     * @param skillService Skill 服务
     * @param resourceAccessService 资源访问服务
     */
    public SkillApprovalSubjectHandler(ApprovalInstanceService approvalInstanceService,
                                       ObjectMapper objectMapper,
                                       SkillService skillService,
                                       ResourceAccessService resourceAccessService) {
        super(approvalInstanceService, objectMapper);
        this.skillService = skillService;
        this.resourceAccessService = resourceAccessService;
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public String resourceType() {
        return ApprovalResourceType.SKILL.getCode();
    }

    /**
     * {@inheritDoc}
     */
    @Override
    public void assertPublishedAccess(Object identifier, String denyMessage) {
        Skill skill = skillService.getById(String.valueOf(identifier));
        if (skill == null || !PublishStatus.from(skill.getPublishStatus()).isExternallyVisible()
                || skill.getPublishedSnapshotJson() == null || skill.getPublishedSnapshotJson().isEmpty()) {
            throw new BusinessException(denyMessage);
        }
    }

    @Override
    protected Skill requireResource(BigInteger resourceId) {
        Skill skill = skillService.getById(resourceId);
        if (skill == null) {
            throw new BusinessException("Skill 不存在");
        }
        return skill;
    }

    @Override
    protected void assertManagePermission(Skill resource) {
        resourceAccessService.assertAccess(CategoryResourceType.SKILL, resource, ResourceAction.MANAGE, "无权限管理该 Skill");
    }

    @Override
    protected BigInteger getCategoryId(Skill resource) {
        return resource.getCategoryId();
    }

    @Override
    protected BigInteger getDeptId(Skill resource) {
        return resource.getDeptId();
    }

    @Override
    protected String getTitle(Skill resource) {
        return resource.getDisplayName() == null || resource.getDisplayName().isBlank()
                ? resource.getName()
                : resource.getDisplayName();
    }

    @Override
    protected PublishStatus getCurrentStatus(Skill resource) {
        return PublishStatus.from(resource.getPublishStatus());
    }

    @Override
    protected Map<String, Object> getPublishedSnapshot(Skill resource) {
        return resource.getPublishedSnapshotJson();
    }

    @Override
    protected Map<String, Object> buildResourceSnapshot(Skill resource) {
        return skillService.buildPublishSnapshot(resource);
    }

    @Override
    protected void persistResourceState(BigInteger resourceId, PublishStatus publishStatus, BigInteger currentApprovalInstanceId) {
        Skill skill = new Skill();
        skill.setId(resourceId);
        skill.setPublishStatus(publishStatus.getCode());
        skill.setCurrentApprovalInstanceId(currentApprovalInstanceId);
        skillService.updateById(skill);
    }

    @Override
    protected void publishResource(BigInteger resourceId, Map<String, Object> resourceSnapshot, BigInteger operatorId) {
        Skill skill = new Skill();
        skill.setId(resourceId);
        skill.setPublishStatus(PublishStatus.PUBLISHED.getCode());
        skill.setPublishedSnapshotJson(resourceSnapshot);
        skill.setPublishedAt(new Date());
        skill.setPublishedBy(operatorId);
        skill.setCurrentApprovalInstanceId(null);
        skillService.updateById(skill);
    }

    @Override
    protected void markResourceOffline(BigInteger resourceId) {
        Skill skill = new Skill();
        skill.setId(resourceId);
        skill.setPublishStatus(PublishStatus.OFFLINE.getCode());
        skill.setCurrentApprovalInstanceId(null);
        skillService.updateById(skill);
    }

    @Override
    protected void removeResource(BigInteger resourceId) {
        skillService.removeAggregate(resourceId);
    }

    @Override
    protected String resourceLabel() {
        return "Skill";
    }
}

