package com.agileboot.reader.service.impl;

import cn.hutool.core.io.FileUtil;
import cn.hutool.core.util.IdUtil;
import cn.hutool.core.util.StrUtil;
import com.agileboot.common.core.exception.BizException;
import com.agileboot.common.core.exception.error.ErrorCode;
import com.agileboot.common.mybatis.core.page.PageQuery;
import com.agileboot.common.mybatis.core.page.PageR;
import com.agileboot.common.satoken.utils.LoginHelper;
import com.agileboot.reader.dto.TextFileQueryDTO;
import com.agileboot.reader.entity.TextFile;
import com.agileboot.reader.mapper.TextFileMapper;
import com.agileboot.reader.service.ITextFileService;
import com.agileboot.reader.vo.TextFileContentVO;
import com.agileboot.reader.vo.TextFileVO;
import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.toolkit.Wrappers;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.BeanUtils;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.nio.charset.Charset;
import java.nio.charset.StandardCharsets;
import java.util.List;
import java.util.stream.Collectors;

/**
 * 文本文件服务实现类
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class TextFileServiceImpl implements ITextFileService {

    private final TextFileMapper textFileMapper;

    @Value("${reader.upload.path:./upload/reader}")
    private String uploadPath;

    @Override
    @Transactional(rollbackFor = Exception.class)
    public Long uploadFile(MultipartFile file, String description) {
        if (file == null || file.isEmpty()) {
            throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, "文件不能为空");
        }

        String originalFilename = file.getOriginalFilename();
        if (StrUtil.isBlank(originalFilename)) {
            throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, "文件名不能为空");
        }

        // 检查文件类型
        String extension = FileUtil.extName(originalFilename);
        if (!"txt".equalsIgnoreCase(extension)) {
            throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, "只支持上传txt文件");
        }

        try {
            // 获取绝对路径
            String absoluteUploadPath = FileUtil.getAbsolutePath(uploadPath);
            
            // 创建上传目录
            File uploadDir = new File(absoluteUploadPath);
            if (!uploadDir.exists()) {
                boolean created = uploadDir.mkdirs();
                if (!created) {
                    log.error("创建上传目录失败: {}", absoluteUploadPath);
                }
            }

            // 生成唯一文件名
            String fileName = IdUtil.fastSimpleUUID() + ".txt";
            String filePath = absoluteUploadPath + File.separator + fileName;
            File destFile = new File(filePath);

            // 保存文件
            file.transferTo(destFile);

            // 保存文件信息到数据库
            TextFile textFile = new TextFile();
            textFile.setFileName(fileName);
            textFile.setOriginalFileName(originalFilename);
            textFile.setFilePath(filePath);
            textFile.setFileSize(file.getSize());
            textFile.setDescription(description);
            textFile.setStatus(0);
            
            // 获取当前登录用户信息
            try {
                Long userId = LoginHelper.getUserId();
                String username = LoginHelper.getUsername();
                textFile.setUploadUserId(userId);
                textFile.setUploadUserName(username);
            } catch (Exception e) {
                log.warn("获取登录用户信息失败", e);
            }

            textFileMapper.insert(textFile);
            return textFile.getFileId();
        } catch (IOException e) {
            log.error("文件上传失败", e);
            throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, "文件上传失败：" + e.getMessage());
        }
    }

    @Override
    public PageR<TextFileVO> getFileList(TextFileQueryDTO query) {
        Page<TextFile> page = textFileMapper.selectPage(query.toPage(), query.toQueryWrapper());
        
        List<TextFileVO> voList = page.getRecords().stream().map(this::convertToVO).collect(Collectors.toList());
        
        return new PageR<>(page, voList);
    }

    @Override
    public List<TextFileVO> getAllFiles() {
        LambdaQueryWrapper<TextFile> wrapper = Wrappers.lambdaQuery();
        wrapper.eq(TextFile::getStatus, 0);
        wrapper.orderByDesc(TextFile::getCreateTime);
        
        List<TextFile> files = textFileMapper.selectList(wrapper);
        return files.stream().map(this::convertToVO).collect(Collectors.toList());
    }

    @Override
    public TextFileVO getFileDetail(Long fileId) {
        TextFile textFile = textFileMapper.selectById(fileId);
        if (textFile == null) {
            throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, "文件不存在");
        }
        return convertToVO(textFile);
    }

    @Override
    public TextFileContentVO readFileContent(Long fileId) {
        TextFile textFile = textFileMapper.selectById(fileId);
        if (textFile == null) {
            throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, "文件不存在");
        }

        File file = new File(textFile.getFilePath());
        if (!file.exists()) {
            throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, "文件已被删除");
        }

        try {
            // 尝试读取文件内容，自动检测编码
            String content = readFileWithEncoding(file);
            
            TextFileContentVO vo = new TextFileContentVO();
            vo.setFileId(textFile.getFileId());
            vo.setFileName(textFile.getOriginalFileName());
            vo.setContent(content);
            vo.setFileSize(textFile.getFileSize());
            
            return vo;
        } catch (Exception e) {
            log.error("读取文件内容失败", e);
            throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, "读取文件内容失败：" + e.getMessage());
        }
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteFile(Long fileId) {
        TextFile textFile = textFileMapper.selectById(fileId);
        if (textFile == null) {
            throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, "文件不存在");
        }

        // 删除物理文件
        File file = new File(textFile.getFilePath());
        if (file.exists()) {
            file.delete();
        }

        // 删除数据库记录
        return textFileMapper.deleteById(fileId) > 0;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean deleteBatch(List<Long> fileIds) {
        if (fileIds == null || fileIds.isEmpty()) {
            return false;
        }

        for (Long fileId : fileIds) {
            deleteFile(fileId);
        }
        
        return true;
    }

    @Override
    @Transactional(rollbackFor = Exception.class)
    public boolean updateStatus(Long fileId, Integer status) {
        TextFile textFile = textFileMapper.selectById(fileId);
        if (textFile == null) {
            throw new BizException(ErrorCode.Business.COMMON_OBJECT_NOT_FOUND, "文件不存在");
        }

        textFile.setStatus(status);
        return textFileMapper.updateById(textFile) > 0;
    }

    /**
     * 转换为VO
     */
    private TextFileVO convertToVO(TextFile textFile) {
        TextFileVO vo = new TextFileVO();
        BeanUtils.copyProperties(textFile, vo);
        return vo;
    }

    /**
     * 读取文件内容，自动检测编码
     */
    private String readFileWithEncoding(File file) {
        try {
            // 尝试UTF-8
            return FileUtil.readString(file, StandardCharsets.UTF_8);
        } catch (Exception e) {
            try {
                // 尝试GBK
                return FileUtil.readString(file, Charset.forName("GBK"));
            } catch (Exception ex) {
                // 使用系统默认编码
                return FileUtil.readString(file, Charset.defaultCharset());
            }
        }
    }
}

