package tech.easyflow.admin.controller.system;

import cn.dev33.satoken.annotation.SaCheckPermission;
import com.mybatisflex.core.paginate.Page;
import com.mybatisflex.core.query.QueryWrapper;
import com.mybatisflex.core.table.TableInfo;
import com.mybatisflex.core.table.TableInfoFactory;
import jakarta.servlet.http.HttpServletRequest;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.bind.annotation.GetMapping;
import org.springframework.web.bind.annotation.PostMapping;
import org.springframework.web.bind.annotation.RequestMapping;
import org.springframework.web.bind.annotation.RestController;
import tech.easyflow.ai.service.KnowledgeSharePermissionService;
import tech.easyflow.ai.service.WorkflowApiPermissionService;
import tech.easyflow.ai.enums.KnowledgeApiPermissionScope;
import tech.easyflow.common.domain.Result;
import tech.easyflow.common.entity.LoginAccount;
import tech.easyflow.common.satoken.util.SaTokenUtil;
import tech.easyflow.common.util.IdUtil;
import tech.easyflow.common.vo.PkVo;
import tech.easyflow.common.web.controller.BaseCurdController;
import tech.easyflow.common.web.jsonbody.JsonBody;
import tech.easyflow.system.entity.SysApiKey;
import tech.easyflow.system.entity.SysApiKeyResourceMapping;
import tech.easyflow.system.service.SysApiKeyResourceMappingService;
import tech.easyflow.system.service.SysApiKeyService;

import javax.annotation.Resource;
import java.math.BigInteger;
import java.time.LocalDate;
import java.time.ZoneId;
import java.util.Date;
import java.util.List;
import java.util.Set;

/**
 *  控制层。
 *
 * @author wangGangQiang
 * @since 2025-04-18
 */
@RestController
@RequestMapping("/api/v1/sysApiKey")
public class SysApiKeyController extends BaseCurdController<SysApiKeyService, SysApiKey> {

    /**
     * 访问令牌名称最大长度。
     */
    private static final int API_KEY_NAME_MAX_LENGTH = 100;

    /**
     * 兼容旧客户端时使用的默认名称前缀。
     */
    private static final String DEFAULT_API_KEY_NAME_PREFIX = "访问令牌-";

    public SysApiKeyController(SysApiKeyService service) {
        super(service);
    }

    /**
     * 获取 API Key 列表关键字搜索字段。
     *
     * @return 名称和 Key 属性
     */
    @Override
    protected String[] getKeywordSearchProperties() {
        return new String[]{"name", "apiKey"};
    }

    @Resource
    private SysApiKeyResourceMappingService sysApiKeyResourceMappingService;
    @Resource
    private KnowledgeSharePermissionService knowledgeSharePermissionService;
    @Resource
    private WorkflowApiPermissionService workflowApiPermissionService;
    /**
     * 添加（保存）数据
     *
     * @param name 访问令牌名称
     * @return {@code Result.errorCode == 0} 添加成功，否则添加失败
     */
    @PostMapping("/key/save")
    @SaCheckPermission("/api/v1/sysApiKey/save")
    public Result<PkVo> save(@JsonBody(value = "name", required = false) String name) {
        String apiKey = IdUtil.generateUUID();
        String normalizedName = normalizeCreateName(name, apiKey);
        if (normalizedName.length() > API_KEY_NAME_MAX_LENGTH) {
            return Result.fail("访问令牌名称不能超过100个字符", null);
        }
        SysApiKey entity = new SysApiKey();
        entity.setName(normalizedName);
        entity.setApiKey(apiKey);
        entity.setCreated(new Date());
        entity.setStatus(1);
        // 将Date转换为LocalDate
        LocalDate localDate = new Date().toInstant()
                .atZone(ZoneId.systemDefault())
                .toLocalDate();

        // 添加30天
        LocalDate newLocalDate = localDate.plusDays(30);
        // 转换回Date
        Date expireDate =  Date.from(newLocalDate.atStartOfDay()
                .atZone(ZoneId.systemDefault())
                .toInstant());
        entity.setExpiredAt(expireDate);
        LoginAccount loginAccount = SaTokenUtil.getLoginAccount();
        commonFiled(entity,loginAccount.getId(),loginAccount.getTenantId(),loginAccount.getDeptId());
        service.save(entity);
        onSaveOrUpdateAfter(entity, true);
        TableInfo tableInfo = TableInfoFactory.ofEntityClass(entity.getClass());
        Object[] pkArgs = tableInfo.buildPkSqlArgs(entity);
        return Result.ok(new PkVo(pkArgs));
    }

    /**
     * 更新访问令牌基础信息与授权。
     *
     * <p>权限开关不映射数据库列，权限更新请求可能只包含主键与权限字段。
     * 此时跳过主表更新，避免 MyBatis-Flex 生成空的 {@code SET} 子句。</p>
     *
     * @param entity 待更新的访问令牌
     * @return 更新结果
     */
    @Override
    @PostMapping("/update")
    @Transactional(rollbackFor = Exception.class)
    public Result<?> update(@JsonBody SysApiKey entity) {
        if (entity == null || entity.getId() == null) {
            return Result.fail("访问令牌 ID 不能为空");
        }
        Result<?> nameValidationResult = normalizeAndValidateUpdateName(entity);
        if (nameValidationResult != null) {
            return nameValidationResult;
        }
        if (!hasPersistentUpdateFields(entity) && !hasPermissionUpdateFields(entity)) {
            return Result.fail("没有可更新的访问令牌字段");
        }
        if (hasNewKnowledgePermissionFields(entity)
            && !hasCompleteKnowledgePermissionFields(entity)) {
            return Result.fail("知识库读取、导入、维护权限必须同时提交");
        }
        if (service.getById(entity.getId()) == null) {
            return Result.fail("访问令牌不存在");
        }
        Result<?> beforeResult = onSaveOrUpdateBefore(entity, false);
        if (beforeResult != null) {
            return beforeResult;
        }
        if (hasPersistentUpdateFields(entity)) {
            service.updateById(entity);
        }
        onSaveOrUpdateAfter(entity, false);
        return Result.ok();
    }

    @Override
    protected void onSaveOrUpdateAfter(SysApiKey entity, boolean isSave) {
        if (entity.getPermissionIds() != null) {
            sysApiKeyResourceMappingService.authInterface(entity);
        }
        if (hasNewKnowledgePermissionFields(entity)) {
            knowledgeSharePermissionService.replaceApiPermissions(
                entity.getId(),
                Boolean.TRUE.equals(entity.getKnowledgeReadEnabled()),
                Boolean.TRUE.equals(entity.getKnowledgeImportEnabled()),
                Boolean.TRUE.equals(entity.getKnowledgeMaintenanceEnabled())
            );
        } else if (entity.getKnowledgeShareEnabled() != null) {
            // 兼容旧客户端：开启旧总开关只授予读取和导入，维护权限保持关闭。
            knowledgeSharePermissionService.replaceApiShareEnabled(entity.getId(), entity.getKnowledgeShareEnabled());
        }
        if (entity.getWorkflowApiEnabled() != null) {
            workflowApiPermissionService.replaceWorkflowApiEnabled(entity.getId(), entity.getWorkflowApiEnabled());
        }
    }

    @Override
    @GetMapping("/detail")
    public Result<SysApiKey> detail(String id) {
        Result<SysApiKey> result = super.detail(id);
        fillApiKeyPermissions(result.getData());
        return result;
    }

    @Override
    @GetMapping("/page")
    public Result<Page<SysApiKey>> page(HttpServletRequest request, String sortKey, String sortType, Long pageNumber, Long pageSize) {
        Result<Page<SysApiKey>> pageResult = (Result<Page<SysApiKey>>) super.page(request, sortKey, sortType, pageNumber, pageSize);
        Page<SysApiKey> data = pageResult.getData();
        List<SysApiKey> records = data.getRecords();
        records.forEach(this::fillApiKeyPermissions);
        return pageResult;
    }

    /**
     * 回填访问令牌的接口与知识库授权。
     *
     * @param entity 访问令牌
     */
    private void fillApiKeyPermissions(SysApiKey entity) {
        if (entity == null || entity.getId() == null) {
            return;
        }
        QueryWrapper interfaceWrapper = QueryWrapper.create()
            .select(SysApiKeyResourceMapping::getApiKeyResourceId)
            .eq(SysApiKeyResourceMapping::getApiKeyId, entity.getId())
            .isNull(SysApiKeyResourceMapping::getResourceType);
        List<BigInteger> resourceIds = sysApiKeyResourceMappingService.listAs(interfaceWrapper, BigInteger.class);
        entity.setPermissionIds(resourceIds);

        Set<String> knowledgeScopes =
            knowledgeSharePermissionService.getApiPermissionScopes(entity.getId());
        boolean readEnabled =
            knowledgeScopes.contains(KnowledgeApiPermissionScope.KNOWLEDGE_READ.name());
        boolean importEnabled =
            knowledgeScopes.contains(KnowledgeApiPermissionScope.KNOWLEDGE_IMPORT.name());
        boolean maintenanceEnabled =
            knowledgeScopes.contains(KnowledgeApiPermissionScope.KNOWLEDGE_MAINTENANCE.name());
        entity.setKnowledgeReadEnabled(readEnabled);
        entity.setKnowledgeImportEnabled(importEnabled);
        entity.setKnowledgeMaintenanceEnabled(maintenanceEnabled);
        entity.setKnowledgeShareEnabled(readEnabled || importEnabled || maintenanceEnabled);

        QueryWrapper workflowWrapper = QueryWrapper.create()
            .select(SysApiKeyResourceMapping::getId)
            .eq(SysApiKeyResourceMapping::getApiKeyId, entity.getId())
            .eq(SysApiKeyResourceMapping::getResourceType, WorkflowApiPermissionService.RESOURCE_TYPE_WORKFLOW);
        entity.setWorkflowApiEnabled(sysApiKeyResourceMappingService.count(workflowWrapper) > 0);
    }

    /**
     * 判断请求是否提交了任一新版知识库权限字段。
     *
     * @param entity 访问令牌
     * @return 是否提交新版字段
     */
    private boolean hasNewKnowledgePermissionFields(SysApiKey entity) {
        return entity.getKnowledgeReadEnabled() != null
            || entity.getKnowledgeImportEnabled() != null
            || entity.getKnowledgeMaintenanceEnabled() != null;
    }

    /**
     * 判断请求是否完整提交三个新版知识库权限字段。
     *
     * @param entity 访问令牌
     * @return 三个字段是否均已提交
     */
    private boolean hasCompleteKnowledgePermissionFields(SysApiKey entity) {
        return entity.getKnowledgeReadEnabled() != null
            && entity.getKnowledgeImportEnabled() != null
            && entity.getKnowledgeMaintenanceEnabled() != null;
    }

    /**
     * 判断请求是否包含主表可持久化字段。
     *
     * @param entity 访问令牌
     * @return 是否需要更新访问令牌主表
     */
    private boolean hasPersistentUpdateFields(SysApiKey entity) {
        return entity.getName() != null
            || entity.getApiKey() != null
            || entity.getCreated() != null
            || entity.getStatus() != null
            || entity.getDeptId() != null
            || entity.getTenantId() != null
            || entity.getExpiredAt() != null
            || entity.getCreatedBy() != null;
    }

    /**
     * 判断请求是否包含任一非主表权限字段。
     *
     * @param entity 访问令牌
     * @return 是否需要更新权限映射
     */
    private boolean hasPermissionUpdateFields(SysApiKey entity) {
        return entity.getPermissionIds() != null
            || entity.getKnowledgeShareEnabled() != null
            || hasNewKnowledgePermissionFields(entity)
            || entity.getWorkflowApiEnabled() != null;
    }

    /**
     * 标准化新建访问令牌的名称。
     *
     * <p>未传名称时生成可识别的兼容名称，避免旧客户端在升级期间创建空名称记录。</p>
     *
     * @param name 客户端提交的名称
     * @param apiKey 新生成的访问令牌
     * @return 标准化后的名称
     */
    private String normalizeCreateName(String name, String apiKey) {
        if (name != null && !name.trim().isEmpty()) {
            return name.trim();
        }
        int suffixStart = Math.max(0, apiKey.length() - 6);
        return DEFAULT_API_KEY_NAME_PREFIX + apiKey.substring(suffixStart);
    }

    /**
     * 标准化并校验更新请求中的访问令牌名称。
     *
     * @param entity 待更新的访问令牌
     * @return 校验失败结果；无需校验或校验成功时返回 {@code null}
     */
    private Result<?> normalizeAndValidateUpdateName(SysApiKey entity) {
        if (entity.getName() == null) {
            return null;
        }
        String normalizedName = entity.getName().trim();
        if (normalizedName.isEmpty()) {
            return Result.fail("访问令牌名称不能为空");
        }
        if (normalizedName.length() > API_KEY_NAME_MAX_LENGTH) {
            return Result.fail("访问令牌名称不能超过100个字符");
        }
        entity.setName(normalizedName);
        return null;
    }
}
