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 jakarta.servlet.http.HttpServletResponse;
import org.springframework.http.MediaType;
import org.springframework.util.StringUtils;
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 org.springframework.web.multipart.MultipartFile;
import tech.easyflow.ai.entity.DocumentCollection;
import tech.easyflow.ai.entity.FaqItem;
import tech.easyflow.ai.service.DocumentCollectionService;
import tech.easyflow.ai.service.FaqCategoryService;
import tech.easyflow.ai.service.FaqItemService;
import tech.easyflow.ai.vo.FaqImportResultVo;
import tech.easyflow.common.annotation.UsePermission;
import tech.easyflow.common.domain.Result;
import tech.easyflow.common.filestorage.FileStorageService;
import tech.easyflow.common.vo.UploadResVo;
import tech.easyflow.common.web.controller.BaseCurdController;
import tech.easyflow.common.web.exceptions.BusinessException;
import tech.easyflow.common.web.jsonbody.JsonBody;
import tech.easyflow.system.enums.CategoryResourceType;
import tech.easyflow.system.enums.ResourceAction;
import tech.easyflow.system.enums.ResourceLookup;
import tech.easyflow.system.permission.resource.RequireResourceAccess;

import javax.annotation.Resource;
import java.io.Serializable;
import java.math.BigInteger;
import java.net.URLEncoder;
import java.text.SimpleDateFormat;
import java.util.Arrays;
import java.util.Date;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

@RestController
@RequestMapping("/api/v1/faqItem")
@UsePermission(moduleName = "/api/v1/documentCollection")
public class FaqItemController extends BaseCurdController<FaqItemService, FaqItem> {

    private static final long MAX_IMAGE_SIZE_BYTES = 5L * 1024L * 1024L;
    private static final Set<String> ALLOWED_IMAGE_TYPES = new HashSet<>(Arrays.asList(
            "image/jpeg",
            "image/png",
            "image/webp",
            "image/gif"
    ));

    private final FaqCategoryService faqCategoryService;

    @Resource
    private DocumentCollectionService documentCollectionService;

    @Resource(name = "default")
    private FileStorageService fileStorageService;

    public FaqItemController(FaqItemService service, FaqCategoryService faqCategoryService) {
        super(service);
        this.faqCategoryService = faqCategoryService;
    }

    @Override
    @GetMapping("list")
    @SaCheckPermission("/api/v1/documentCollection/query")
    @RequireResourceAccess(
            resource = CategoryResourceType.KNOWLEDGE,
            action = ResourceAction.READ,
            lookup = ResourceLookup.KNOWLEDGE_ID,
            idExpr = "#entity == null ? null : #entity.collectionId",
            denyMessage = "无权限访问知识库"
    )
    public Result<java.util.List<FaqItem>> list(FaqItem entity, Boolean asTree, String sortKey, String sortType) {
        BigInteger collectionId = entity == null ? null : entity.getCollectionId();
        if (collectionId == null) {
            throw new BusinessException("知识库ID不能为空");
        }
        return super.list(entity, asTree, sortKey, sortType);
    }

    @Override
    @GetMapping("page")
    @SaCheckPermission("/api/v1/documentCollection/query")
    @RequireResourceAccess(
            resource = CategoryResourceType.KNOWLEDGE,
            action = ResourceAction.READ,
            lookup = ResourceLookup.KNOWLEDGE_ID,
            idExpr = "#request.getParameter('collectionId')",
            denyMessage = "无权限访问知识库"
    )
    public Result<Page<FaqItem>> page(HttpServletRequest request, String sortKey, String sortType, Long pageNumber, Long pageSize) {
        if (pageNumber == null || pageNumber < 1) {
            pageNumber = 1L;
        }
        if (pageSize == null || pageSize < 1) {
            pageSize = 10L;
        }

        String collectionIdText = request.getParameter("collectionId");
        if (collectionIdText == null || collectionIdText.trim().isEmpty()) {
            throw new BusinessException("知识库ID不能为空");
        }
        BigInteger collectionId = new BigInteger(collectionIdText);
        faqCategoryService.ensureDefaultCategory(collectionId);

        QueryWrapper queryWrapper = QueryWrapper.create()
                .eq(FaqItem::getCollectionId, collectionId);

        String question = request.getParameter("question");
        if (question != null && !question.trim().isEmpty()) {
            queryWrapper.like(FaqItem::getQuestion, question.trim());
        }

        String categoryIdText = request.getParameter("categoryId");
        if (categoryIdText != null && !categoryIdText.trim().isEmpty()) {
            BigInteger categoryId = new BigInteger(categoryIdText);
            List<BigInteger> descendantIds = faqCategoryService.findDescendantIds(collectionId, categoryId);
            if (descendantIds.isEmpty()) {
                queryWrapper.eq(FaqItem::getId, BigInteger.ZERO);
            } else {
                queryWrapper.in(FaqItem::getCategoryId, descendantIds);
            }
        }

        queryWrapper.orderBy(buildOrderBy(sortKey, sortType, getDefaultOrderBy()));
        Page<FaqItem> page = service.page(new Page<>(pageNumber, pageSize), queryWrapper);
        Map<BigInteger, String> pathMap = faqCategoryService.buildPathMap(collectionId);

        if (page.getRecords() != null) {
            for (FaqItem record : page.getRecords()) {
                record.setCategoryPath(pathMap.get(record.getCategoryId()));
            }
        }
        return Result.ok(page);
    }

    @Override
    @GetMapping("detail")
    @SaCheckPermission("/api/v1/documentCollection/query")
    @RequireResourceAccess(
            resource = CategoryResourceType.KNOWLEDGE,
            action = ResourceAction.READ,
            lookup = ResourceLookup.FAQ_ITEM_ID,
            idExpr = "#id",
            denyMessage = "无权限访问知识库"
    )
    public Result<FaqItem> detail(String id) {
        return super.detail(id);
    }

    @Override
    @PostMapping("save")
    @SaCheckPermission("/api/v1/documentCollection/save")
    @RequireResourceAccess(
            resource = CategoryResourceType.KNOWLEDGE,
            action = ResourceAction.MANAGE,
            lookup = ResourceLookup.KNOWLEDGE_ID,
            idExpr = "#entity.collectionId",
            denyMessage = "无权限管理知识库"
    )
    public Result<?> save(@JsonBody FaqItem entity) {
        return Result.ok(service.saveFaqItem(entity));
    }

    @Override
    @PostMapping("update")
    @SaCheckPermission("/api/v1/documentCollection/save")
    @RequireResourceAccess(
            resource = CategoryResourceType.KNOWLEDGE,
            action = ResourceAction.MANAGE,
            lookup = ResourceLookup.FAQ_ITEM_ID,
            idExpr = "#entity.id",
            denyMessage = "无权限管理知识库"
    )
    public Result<?> update(@JsonBody FaqItem entity) {
        return Result.ok(service.updateFaqItem(entity));
    }

    @Override
    @PostMapping("remove")
    @SaCheckPermission("/api/v1/documentCollection/remove")
    @RequireResourceAccess(
            resource = CategoryResourceType.KNOWLEDGE,
            action = ResourceAction.MANAGE,
            lookup = ResourceLookup.FAQ_ITEM_ID,
            idExpr = "#id",
            denyMessage = "无权限管理知识库"
    )
    public Result<?> remove(@JsonBody(value = "id", required = true) Serializable id) {
        return Result.ok(service.removeFaqItem(new java.math.BigInteger(String.valueOf(id))));
    }

    @PostMapping(value = "uploadImage", produces = MediaType.APPLICATION_JSON_VALUE)
    @SaCheckPermission("/api/v1/documentCollection/save")
    @RequireResourceAccess(
            resource = CategoryResourceType.KNOWLEDGE,
            action = ResourceAction.MANAGE,
            lookup = ResourceLookup.KNOWLEDGE_ID,
            idExpr = "#collectionId",
            denyMessage = "无权限管理知识库"
    )
    public Result<UploadResVo> uploadImage(MultipartFile file, BigInteger collectionId) {
        if (collectionId == null) {
            throw new BusinessException("知识库ID不能为空");
        }
        if (file == null || file.isEmpty()) {
            throw new BusinessException("图片不能为空");
        }
        if (file.getSize() > MAX_IMAGE_SIZE_BYTES) {
            throw new BusinessException("图片大小不能超过5MB");
        }
        if (!isAllowedImageType(file)) {
            throw new BusinessException("仅支持 JPG/PNG/WEBP/GIF 图片");
        }

        DocumentCollection collection = documentCollectionService.getById(collectionId);
        if (collection == null) {
            throw new BusinessException("知识库不存在");
        }
        if (!collection.isFaqCollection()) {
            throw new BusinessException("当前知识库不是FAQ类型");
        }

        String path = fileStorageService.save(file, "faq/" + collectionId);
        UploadResVo resVo = new UploadResVo();
        resVo.setPath(path);
        return Result.ok(resVo);
    }

    @PostMapping(value = "importExcel", consumes = MediaType.MULTIPART_FORM_DATA_VALUE)
    @SaCheckPermission("/api/v1/documentCollection/save")
    @RequireResourceAccess(
            resource = CategoryResourceType.KNOWLEDGE,
            action = ResourceAction.MANAGE,
            lookup = ResourceLookup.KNOWLEDGE_ID,
            idExpr = "#collectionId",
            denyMessage = "无权限管理知识库"
    )
    public Result<FaqImportResultVo> importExcel(MultipartFile file, BigInteger collectionId) {
        return Result.ok(service.importFromExcel(collectionId, file));
    }

    @GetMapping("downloadImportTemplate")
    @SaCheckPermission("/api/v1/documentCollection/query")
    @RequireResourceAccess(
            resource = CategoryResourceType.KNOWLEDGE,
            action = ResourceAction.READ,
            lookup = ResourceLookup.KNOWLEDGE_ID,
            idExpr = "#collectionId",
            denyMessage = "无权限访问知识库"
    )
    public void downloadImportTemplate(BigInteger collectionId, HttpServletResponse response) throws Exception {
        if (collectionId == null) {
            throw new BusinessException("知识库ID不能为空");
        }
        DocumentCollection collection = documentCollectionService.getById(collectionId);
        if (collection == null) {
            throw new BusinessException("知识库不存在");
        }
        if (!collection.isFaqCollection()) {
            throw new BusinessException("当前知识库不是FAQ类型");
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String fileName = URLEncoder.encode("faq_import_template", "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        service.writeImportTemplate(response.getOutputStream());
    }

    @GetMapping("exportExcel")
    @SaCheckPermission("/api/v1/documentCollection/query")
    @RequireResourceAccess(
            resource = CategoryResourceType.KNOWLEDGE,
            action = ResourceAction.READ,
            lookup = ResourceLookup.KNOWLEDGE_ID,
            idExpr = "#collectionId",
            denyMessage = "无权限访问知识库"
    )
    public void exportExcel(BigInteger collectionId, HttpServletResponse response) throws Exception {
        if (collectionId == null) {
            throw new BusinessException("知识库ID不能为空");
        }
        response.setContentType("application/vnd.openxmlformats-officedocument.spreadsheetml.sheet");
        response.setCharacterEncoding("utf-8");
        String timestamp = new SimpleDateFormat("yyyyMMddHHmmss").format(new Date());
        String fileName = URLEncoder.encode("faq_export_" + timestamp, "UTF-8").replaceAll("\\+", "%20");
        response.setHeader("Content-disposition", "attachment;filename*=utf-8''" + fileName + ".xlsx");
        service.exportToExcel(collectionId, response.getOutputStream());
    }

    @Override
    protected String getDefaultOrderBy() {
        return "order_no asc";
    }

    private boolean isAllowedImageType(MultipartFile file) {
        String contentType = file.getContentType();
        return StringUtils.hasText(contentType) && ALLOWED_IMAGE_TYPES.contains(contentType.toLowerCase());
    }
}
