package top.tqx.demo_1.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import top.tqx.demo_1.common.PageResult;
import top.tqx.demo_1.dto.QuestionCreateRequest;
import top.tqx.demo_1.dto.QuestionStatsRequest;
import top.tqx.demo_1.dto.QuestionStatsResponse;
import top.tqx.demo_1.dto.QuestionUpdateRequest;
import top.tqx.demo_1.entity.File;
import top.tqx.demo_1.entity.Question;
import top.tqx.demo_1.mapper.FileMapper;
import top.tqx.demo_1.mapper.QuestionMapper;
import top.tqx.demo_1.service.QuestionService;
import top.tqx.demo_1.service.LogService;
import com.baomidou.mybatisplus.extension.service.impl.ServiceImpl;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.math.BigDecimal;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.Arrays;
import java.util.List;
import java.util.Map;
import java.util.UUID;
import java.util.stream.Collectors;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.fasterxml.jackson.databind.node.ObjectNode;

@Service
public class QuestionServiceImpl extends ServiceImpl<QuestionMapper, Question> implements QuestionService {

    private final LogService logService;
    private final ObjectMapper objectMapper = new ObjectMapper();

    @Value("${file.upload.path:./uploads/questions/}")
    private String uploadBasePath;

    @Value("${file.allowed-extensions:.doc,.docx,.xls,.xlsx,.ppt,.pptx,.pdf,.txt,.jpg,.jpeg,.png,.gif,.bmp}")
    private String allowedExtensions;

    @Value("${file.max-size:104857600}")
    private long maxFileSize;

    @Autowired
    private FileMapper fileMapper;

    @Autowired
    public QuestionServiceImpl(LogService logService) {
        this.logService = logService;
    }

    @Override
    public String uploadAndProcessFile(MultipartFile file, String user, String customFileName) throws IOException {
        if (file == null || file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空");
        }

        validateFile(file);

        String directory = createDirectoryByFileName(file, customFileName);
        String filePath = saveFileToDirectory(file, directory, customFileName);

        String aiResult = callAIInterface(filePath, user);

        logService.recordLog(0L, "AI_FILE_UPLOAD",
                String.format("用户:%s 上传文件:%s, 路径:%s", user, file.getOriginalFilename(), filePath));

        return aiResult;
    }

    @Override
    public boolean saveQuestion(Question question) {
        return save(question);
    }

    @Override
    public Question getByQuestionId(String questionId) {
        return lambdaQuery().eq(Question::getQuestionId, questionId).one();
    }

    @Override
    public boolean updateReviewStatus(String questionId, String status, String reviewerComment) {
        return lambdaUpdate()
                .eq(Question::getQuestionId, questionId)
                .set(Question::getStatus, status)
                .set(Question::getReviewerComment, reviewerComment)
                .update();
    }

    @Override
    public PageResult<Question> pageQuestions(Integer pageNum, Integer pageSize,
                                              String questionType, Integer difficulty, String status) {
        Page<Question> page = new Page<>(pageNum, pageSize);
        LambdaQueryWrapper<Question> wrapper = new LambdaQueryWrapper<>();

        if (questionType != null && !questionType.isEmpty()) {
            wrapper.eq(Question::getQuestionType, questionType);
        }

        if (difficulty != null) {
            wrapper.eq(Question::getDifficulty, difficulty);
        }

        if (status != null && !status.isEmpty()) {
            wrapper.eq(Question::getStatus, status);
        }

        wrapper.orderByDesc(Question::getCreatedAt);

        Page<Question> questionPage = this.page(page, wrapper);

        return PageResult.of(
                questionPage.getRecords(),
                questionPage.getTotal(),
                questionPage.getSize(),
                questionPage.getCurrent()
        );
    }

    @Override
    public List<Question> getPendingQuestions() {
        return lambdaQuery()
                .eq(Question::getStatus, "pending")
                .orderByDesc(Question::getCreatedAt)
                .list();
    }

    @Override
    public Question createQuestion(QuestionCreateRequest request) {
        Question question = new Question();
        question.setQuestionId(UUID.randomUUID().toString());
        question.setQuestionType(request.getQuestionType());
        question.setDifficulty(request.getDifficulty() != null ? request.getDifficulty() : 3);
        question.setStatus("pending");

        if (request.getContent() != null) {
            question.setContent(objectMapper.valueToTree(request.getContent()));
        }
        if (request.getTags() != null && !request.getTags().isEmpty()) {
            question.setTags(objectMapper.valueToTree(request.getTags()));
        }
        if (request.getScore() != null) {
            question.setScore(request.getScore());
        } else {
            question.setScore(calculateDefaultScore(request.getQuestionType()));
        }
        question.setDocumentId(request.getDocumentId());
        question.setDocumentName(request.getDocumentName());
        question.setKnowledgeBasePath(request.getKnowledgeBasePath());
        question.setSourceContext(request.getSourceContext());
        if (request.getChunkIds() != null) {
            question.setChunkIds(objectMapper.valueToTree(request.getChunkIds()));
        }
        question.setSourceChunksUsed(request.getSourceChunksUsed());
        if (request.getPageNumbers() != null) {
            question.setPageNumbers(objectMapper.valueToTree(request.getPageNumbers()));
        }

        question.setVersion("1.0");
        question.setCreatedAt(LocalDateTime.now());
        question.setUpdatedAt(LocalDateTime.now());

        save(question);
        return question;
    }

    private BigDecimal calculateDefaultScore(String questionType) {
        if (questionType == null) return new BigDecimal("2.00");
        switch (questionType) {
            case "single_choice": return new BigDecimal("2.00");
            case "multiple_choice": return new BigDecimal("4.00");
            case "true_false": return new BigDecimal("1.00");
            case "fill_blank": return new BigDecimal("2.00");
            case "subjective": return new BigDecimal("6.00");
            default: return new BigDecimal("2.00");
        }
    }

    @Override
    public Question updateQuestion(Long id, QuestionUpdateRequest request) {
        Question question = getById(id);
        if (question == null) {
            throw new IllegalArgumentException("题目不存在");
        }

        if (request.getQuestionType() != null) {
            question.setQuestionType(request.getQuestionType());
        }
        if (request.getDifficulty() != null) {
            question.setDifficulty(request.getDifficulty());
        }
        if (request.getContent() != null) {
            question.setContent(objectMapper.valueToTree(request.getContent()));
        }
        if (request.getTags() != null) {
            question.setTags(objectMapper.valueToTree(request.getTags()));
        }
        if (request.getScore() != null) {
            question.setScore(request.getScore());
        }
        if (request.getStatus() != null) {
            question.setStatus(request.getStatus());
        }
        if (request.getReviewerComment() != null) {
            question.setReviewerComment(request.getReviewerComment());
        }
        if (request.getDocumentId() != null) {
            question.setDocumentId(request.getDocumentId());
        }
        if (request.getDocumentName() != null) {
            question.setDocumentName(request.getDocumentName());
        }
        if (request.getKnowledgeBasePath() != null) {
            question.setKnowledgeBasePath(request.getKnowledgeBasePath());
        }
        if (request.getSourceContext() != null) {
            question.setSourceContext(request.getSourceContext());
        }
        if (request.getChunkIds() != null) {
            question.setChunkIds(objectMapper.valueToTree(request.getChunkIds()));
        }
        if (request.getSourceChunksUsed() != null) {
            question.setSourceChunksUsed(request.getSourceChunksUsed());
        }
        if (request.getPageNumbers() != null) {
            question.setPageNumbers(objectMapper.valueToTree(request.getPageNumbers()));
        }

        question.setUpdatedAt(LocalDateTime.now());
        updateById(question);
        return question;
    }

    @Override
    public boolean deleteById(Long id) {
        return removeById(id);
    }

    @Override
    public int batchDelete(List<Long> ids) {
        return removeByIds(ids) ? ids.size() : 0;
    }

    @Override
    public List<Question> listQuestions(String questionType, Integer difficulty, String status, String documentName, Integer limit, Long userId, Long deptId, Integer userType) {
        LambdaQueryWrapper<Question> wrapper = new LambdaQueryWrapper<>();

        if (questionType != null && !questionType.isEmpty()) {
            wrapper.eq(Question::getQuestionType, questionType);
        }
        if (difficulty != null) {
            wrapper.eq(Question::getDifficulty, difficulty);
        }
        if (status != null && !status.isEmpty()) {
            wrapper.eq(Question::getStatus, status);
        }
        if (documentName != null && !documentName.isEmpty()) {
            wrapper.like(Question::getDocumentName, documentName);
        }

        if (userType == 1) {
        } else if (userType == 2) {
            wrapper.and(w -> w.isNull(Question::getKnowledgeBasePath)
                    .or(w2 -> w2.like(Question::getKnowledgeBasePath, "public"))
                    .or(w3 -> w3.like(Question::getKnowledgeBasePath, String.valueOf(deptId))));
        } else {
            wrapper.and(w -> w.isNull(Question::getKnowledgeBasePath)
                    .or(w2 -> w2.like(Question::getKnowledgeBasePath, "personal"))
                    .or(w3 -> w3.like(Question::getKnowledgeBasePath, "public"))
                    .or(w4 -> w4.like(Question::getKnowledgeBasePath, String.valueOf(deptId))));
        }

        wrapper.orderByDesc(Question::getCreatedAt);
        wrapper.last("LIMIT " + (limit != null ? limit : 100));

        return list(wrapper);
    }

    @Override
    public QuestionStatsResponse getQuestionStats(QuestionStatsRequest request) {
        QuestionStatsResponse response = new QuestionStatsResponse();
        response.setSuccess(true);

        LambdaQueryWrapper<Question> baseWrapper = buildStatsQueryWrapper(request);

        Long totalCount = baseMapper.selectCount(baseWrapper);
        response.setTotalCount(totalCount);

        if (request.getQuestionTypes() == null || request.getQuestionTypes().isEmpty() ||
            request.getQuestionTypes().contains("single_choice")) {
            Long singleCount = countByType("single_choice", request);
            response.setSingleChoiceCount(singleCount);
        }

        if (request.getQuestionTypes() == null || request.getQuestionTypes().isEmpty() ||
            request.getQuestionTypes().contains("multiple_choice")) {
            Long multipleCount = countByType("multiple_choice", request);
            response.setMultipleChoiceCount(multipleCount);
        }

        if (request.getQuestionTypes() == null || request.getQuestionTypes().isEmpty() ||
            request.getQuestionTypes().contains("true_false")) {
            Long trueFalseCount = countByType("true_false", request);
            response.setTrueFalseCount(trueFalseCount);
        }

        if (request.getQuestionTypes() == null || request.getQuestionTypes().isEmpty() ||
            request.getQuestionTypes().contains("fill_blank")) {
            Long fillBlankCount = countByType("fill_blank", request);
            response.setFillBlankCount(fillBlankCount);
        }

        if (request.getQuestionTypes() == null || request.getQuestionTypes().isEmpty() ||
            request.getQuestionTypes().contains("subjective")) {
            Long subjectiveCount = countByType("subjective", request);
            response.setSubjectiveCount(subjectiveCount);
        }

        return response;
    }

    private LambdaQueryWrapper<Question> buildStatsQueryWrapper(QuestionStatsRequest request) {
        LambdaQueryWrapper<Question> wrapper = new LambdaQueryWrapper<>();

        if (request.getStatus() != null && !request.getStatus().isEmpty()) {
            wrapper.eq(Question::getStatus, request.getStatus());
        }

        if (request.getDeptId() != null) {
            wrapper.like(Question::getKnowledgeBasePath, String.valueOf(request.getDeptId()));
        }

        if (request.getFileIds() != null && !request.getFileIds().isEmpty()) {
            List<String> filePaths = getFilePathsByIds(request.getFileIds());
            if (!filePaths.isEmpty()) {
                wrapper.in(Question::getKnowledgeBasePath, filePaths);
            }
        }

        if (request.getCollection() != null && !request.getCollection().isEmpty()) {
            wrapper.like(Question::getKnowledgeBasePath, request.getCollection());
        }

        return wrapper;
    }

    private Long countByType(String questionType, QuestionStatsRequest request) {
        LambdaQueryWrapper<Question> wrapper = new LambdaQueryWrapper<>();
        wrapper.eq(Question::getQuestionType, questionType);

        if (request.getStatus() != null && !request.getStatus().isEmpty()) {
            wrapper.eq(Question::getStatus, request.getStatus());
        }

        if (request.getDeptId() != null) {
            wrapper.like(Question::getKnowledgeBasePath, String.valueOf(request.getDeptId()));
        }

        if (request.getFileIds() != null && !request.getFileIds().isEmpty()) {
            List<String> filePaths = getFilePathsByIds(request.getFileIds());
            if (!filePaths.isEmpty()) {
                wrapper.in(Question::getKnowledgeBasePath, filePaths);
            }
        }

        if (request.getCollection() != null && !request.getCollection().isEmpty()) {
            wrapper.like(Question::getKnowledgeBasePath, request.getCollection());
        }

        return baseMapper.selectCount(wrapper);
    }

    private List<String> getFilePathsByIds(List<Long> fileIds) {
        if (fileIds == null || fileIds.isEmpty()) {
            return List.of();
        }
        LambdaQueryWrapper<File> wrapper = new LambdaQueryWrapper<>();
        wrapper.in(File::getId, fileIds);
        List<File> files = fileMapper.selectList(wrapper);

        return files.stream()
                .map(File::getFilePath)
                .filter(p -> p != null && !p.isEmpty())
                .collect(Collectors.toList());
    }

    private void validateFile(MultipartFile file) {
        if (file.isEmpty()) {
            throw new IllegalArgumentException("文件不能为空: " + file.getOriginalFilename());
        }

        if (file.getSize() > maxFileSize) {
            throw new IllegalArgumentException("文件大小超过限制: " + file.getOriginalFilename());
        }

        String originalFileName = file.getOriginalFilename();
        if (originalFileName == null || originalFileName.isEmpty()) {
            throw new IllegalArgumentException("文件名不能为空");
        }

        String extension = getFileExtension(originalFileName).toLowerCase();
        List<String> allowedExts = Arrays.stream(allowedExtensions.split(","))
                .map(String::trim)
                .map(String::toLowerCase)
                .collect(Collectors.toList());

        if (!allowedExts.contains(extension)) {
            throw new IllegalArgumentException("不支持的文件类型: " + extension + "，允许的类型: " + allowedExts);
        }
    }

    private String getFileExtension(String fileName) {
        if (fileName.contains(".")) {
            return fileName.substring(fileName.lastIndexOf("."));
        }
        return "";
    }

    private String createDirectoryByFileName(MultipartFile file, String customFileName) throws IOException {
        String dirName;

        if (customFileName != null && !customFileName.isEmpty()) {
            dirName = customFileName.contains(".")
                    ? customFileName.substring(0, customFileName.lastIndexOf("."))
                    : customFileName;
        } else {
            String originalFileName = file.getOriginalFilename();
            dirName = originalFileName.contains(".")
                    ? originalFileName.substring(0, originalFileName.lastIndexOf("."))
                    : originalFileName;
        }

        String baseDir = uploadBasePath + dirName;
        Path dirPath = Paths.get(baseDir);

        if (Files.exists(dirPath)) {
            String uniqueSuffix = UUID.randomUUID().toString().substring(0, 8);
            baseDir = baseDir + "_" + uniqueSuffix;
            dirPath = Paths.get(baseDir);
        }

        Files.createDirectories(dirPath);
        return baseDir;
    }

    private String saveFileToDirectory(MultipartFile file, String directory, String customFileName) throws IOException {
        Path dirPath = Paths.get(directory);

        String fileName;
        if (customFileName != null && !customFileName.isEmpty()) {
            fileName = customFileName;
        } else {
            String originalFileName = file.getOriginalFilename();
            String extension = getFileExtension(originalFileName);
            String timestamp = LocalDateTime.now().format(DateTimeFormatter.ofPattern("yyyyMMdd_HHmmss"));
            String uniqueId = UUID.randomUUID().toString().substring(0, 8);
            fileName = timestamp + "_" + uniqueId + extension;
        }

        Path filePath = dirPath.resolve(fileName);
        Files.write(filePath, file.getBytes());
        return filePath.toString();
    }

    private String callAIInterface(String filePath, String user) {
        StringBuilder result = new StringBuilder();

        result.append("=== AI 处理结果 ===\n");
        result.append("用户: " + user + "\n");
        result.append("文件路径: " + filePath + "\n");
        result.append("\nAI 处理状态: 成功\n");
        result.append("说明: 这是占位返回，请替换为实际的 AI 接口调用\n");

        return result.toString();
    }
}
