package tech.easyflow.admin.controller.ai;

import cn.dev33.satoken.annotation.SaCheckPermission;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import tech.easyflow.admin.controller.ai.support.AiResourceCreatorNameSupport;
import tech.easyflow.ai.entity.Model;
import tech.easyflow.ai.entity.Plugin;
import tech.easyflow.ai.entity.Workflow;
import tech.easyflow.ai.plugin.workflow.snapshot.WorkflowPluginSnapshotResolver;
import tech.easyflow.ai.service.ModelService;
import tech.easyflow.ai.service.PluginVisibilityService;
import tech.easyflow.ai.permission.WorkflowVisibilityQueryHelper;
import tech.easyflow.ai.service.WorkflowService;
import tech.easyflow.common.domain.Result;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.web.controller.BaseCurdController;
import tech.easyflow.ai.service.PluginService;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tech.easyflow.common.web.jsonbody.JsonBody;
import tech.easyflow.system.enums.CategoryResourceType;
import tech.easyflow.system.enums.ResourceAction;
import tech.easyflow.system.entity.vo.RoleCategoryAccessSnapshot;
import tech.easyflow.system.service.CategoryPermissionService;
import tech.easyflow.system.service.ResourceAccessService;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.util.ArrayList;
import java.util.Collections;
import java.util.List;
import java.util.Set;

import static tech.easyflow.ai.entity.table.PluginTableDef.PLUGIN;

/**
 *  控制层。
 *
 * @author Administrator
 * @since 2025-04-25
 */
@RestController
@RequestMapping("/api/v1/plugin")
public class PluginController extends BaseCurdController<PluginService, Plugin> {
    public PluginController(PluginService service) {
        super(service);
    }

    @Resource
    PluginService pluginService;
    @Resource
    private CategoryPermissionService categoryPermissionService;
    @Resource
    private PluginVisibilityService pluginVisibilityService;
    @Resource
    private ModelService modelService;
    @Resource
    private WorkflowVisibilityQueryHelper workflowVisibilityQueryHelper;
    @Resource
    private WorkflowService workflowService;
    @Resource
    private ResourceAccessService resourceAccessService;
    @Resource
    private WorkflowPluginSnapshotResolver workflowPluginSnapshotResolver;
    @Resource
    private AiResourceCreatorNameSupport aiResourceCreatorNameSupport;

    @Override
    protected Result<?> onSaveOrUpdateBefore(Plugin entity, boolean isSave) {
        return super.onSaveOrUpdateBefore(entity, isSave);
    }

    @PostMapping("/plugin/save")
    @SaCheckPermission("/api/v1/plugin/save")
    public Result<Plugin> savePlugin(@JsonBody Plugin plugin){

        return Result.ok(pluginService.savePlugin(plugin));
    }

    @PostMapping("/plugin/update")
    @SaCheckPermission("/api/v1/plugin/save")
    public Result<Boolean> updatePlugin(@JsonBody Plugin plugin){

        return Result.ok(pluginService.updatePlugin(plugin));
    }

    @PostMapping("/plugin/remove")
    @SaCheckPermission("/api/v1/plugin/remove")
    public Result<Boolean> removePlugin(@JsonBody(value = "id", required = true) String id){

        return Result.ok(pluginService.removePlugin(id));
    }

    @PostMapping("/getList")
    @SaCheckPermission("/api/v1/plugin/query")
    public Result<List<Plugin>> getList(){
        QueryWrapper queryWrapper = QueryWrapper.create().select();
        applyCategoryPermission(queryWrapper);
        List<Plugin> plugins = service.getMapper().selectListWithRelationsByQuery(queryWrapper);
        return Result.ok(pluginService.preparePluginsForCurrentUser(plugins, true, false));
    }

    @GetMapping("/pageByCategory")
    @SaCheckPermission("/api/v1/plugin/query")
    public Result<Page<Plugin>> pageByCategory(HttpServletRequest request, String sortKey, String sortType, Long pageNumber, Long pageSize, int category) {
        if (pageNumber == null || pageNumber < 1) {
            pageNumber = 1L;
        }
        if (pageSize == null || pageSize < 1) {
            pageSize = 10L;
        }
        if (category == 0){
            QueryWrapper queryWrapper = buildQueryWrapper(request);
            applyCategoryPermission(queryWrapper);
            queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
            return Result.ok(queryPage(new Page<>(pageNumber, pageSize), queryWrapper));
        } else {
            Result<Page<Plugin>> result = pluginService.pageByCategory(pageNumber, pageSize, category);
            if (result != null && result.getData() != null) {
                aiResourceCreatorNameSupport.fillPluginCreatorNames(result.getData().getRecords());
            }
            return result;
        }
    }

    @GetMapping("/workflowCandidates")
    @SaCheckPermission("/api/v1/plugin/query")
    public Result<List<Workflow>> workflowCandidates(String keyword) {
        QueryWrapper queryWrapper = QueryWrapper.create();
        workflowVisibilityQueryHelper.applyReadableAccess(queryWrapper);
        queryWrapper.eq("publish_status", tech.easyflow.ai.enums.PublishStatus.PUBLISHED.getCode());
        if (keyword != null && !keyword.isBlank()) {
            queryWrapper.like("title", keyword.trim());
        }
        queryWrapper.orderBy("modified desc");
        LoginAccount loginAccount = SaTokenUtil.getLoginAccount();
        List<Workflow> workflows = workflowService.list(queryWrapper).stream()
                .filter(workflow -> canBindWorkflowCandidate(workflow, loginAccount))
                .collect(java.util.stream.Collectors.toCollection(ArrayList::new));
        return Result.ok(workflows);
    }

    @GetMapping("/modelList")
    @SaCheckPermission("/api/v1/plugin/query")
    public Result<List<Model>> modelList(Model entity, Boolean asTree, String sortKey, String sortType) {
        return Result.ok(modelService.listSelectableModels(entity, asTree, sortKey, sortType));
    }

    @Override
    protected Page<Plugin> queryPage(Page<Plugin> page, QueryWrapper queryWrapper) {
        applyCategoryPermission(queryWrapper);
        List<Plugin> totalList = service.getMapper().selectListWithRelationsByQuery(queryWrapper);
        boolean availableOnly = isAvailableOnly();
        List<Plugin> prepared = pluginService.preparePluginsForCurrentUser(totalList, !availableOnly, availableOnly);
        aiResourceCreatorNameSupport.fillPluginCreatorNames(prepared);
        long total = prepared.size();
        int fromIndex = Math.max(0, Math.toIntExact((page.getPageNumber() - 1) * page.getPageSize()));
        if (fromIndex >= prepared.size()) {
            return new Page<>(Collections.emptyList(), page.getPageNumber(), page.getPageSize(), total);
        }
        int toIndex = Math.min(prepared.size(), Math.toIntExact(fromIndex + page.getPageSize()));
        return new Page<>(prepared.subList(fromIndex, toIndex), page.getPageNumber(), page.getPageSize(), total);
    }

    @Override
    public Result<Plugin> detail(String id) {
        Plugin plugin = service.getMapper().selectOneWithRelationsById(id);
        if (plugin != null) {
            pluginVisibilityService.assertPluginVisible(plugin.getCreatedBy(), plugin.getId(), "无权限访问插件");
            pluginService.preparePluginForCurrentUser(plugin);
        }
        return Result.ok(plugin);
    }

    private void applyCategoryPermission(QueryWrapper queryWrapper) {
        RoleCategoryAccessSnapshot access = categoryPermissionService.getCurrentAccess("PLUGIN");
        if (!access.isRestricted()) {
            return;
        }
        if (access.getCategoryIds().isEmpty()) {
            queryWrapper.eq(Plugin::getCreatedBy, access.getAccountIdAsLong());
            return;
        }
        Set<BigInteger> pluginIds = pluginVisibilityService.getCurrentVisiblePluginIds();
        if (pluginIds.isEmpty()) {
            queryWrapper.eq(Plugin::getCreatedBy, access.getAccountIdAsLong());
            return;
        }
        queryWrapper.and(PLUGIN.CREATED_BY.eq(access.getAccountIdAsLong()).or(PLUGIN.ID.in(pluginIds)));
    }

    private boolean isAvailableOnly() {
        HttpServletRequest request = currentHttpRequest();
        return request != null && "true".equalsIgnoreCase(request.getParameter("availableOnly"));
    }

    private HttpServletRequest currentHttpRequest() {
        org.springframework.web.context.request.ServletRequestAttributes attributes =
                (org.springframework.web.context.request.ServletRequestAttributes)
                        org.springframework.web.context.request.RequestContextHolder.getRequestAttributes();
        return attributes == null ? null : attributes.getRequest();
    }

    private boolean canBindWorkflowCandidate(Workflow workflow, LoginAccount loginAccount) {
        if (workflow == null || loginAccount == null || loginAccount.getId() == null) {
            return false;
        }
        if (workflow.getPublishedSnapshotJson() == null || workflow.getPublishedSnapshotJson().isEmpty()) {
            return false;
        }
        Workflow publishedWorkflow = workflowService.toPublishedView(workflow);
        if (!workflowPluginSnapshotResolver.isSupportedForWorkflowPlugin(publishedWorkflow)) {
            return false;
        }
        return resourceAccessService.canAccess(loginAccount, CategoryResourceType.WORKFLOW, workflow, ResourceAction.USE);
    }
}
