package com.erp.file.service.impl;

import com.baomidou.mybatisplus.core.conditions.query.LambdaQueryWrapper;
import com.baomidou.mybatisplus.core.metadata.IPage;
import com.baomidou.mybatisplus.extension.plugins.pagination.Page;
import com.erp.file.dto.*;
import com.erp.file.entity.FileEntity;
import com.erp.file.mapper.FileMapper;
import com.erp.file.service.FileService;
import com.erp.file.service.storage.StorageFactory;
import com.erp.file.service.storage.StorageStrategy;
import com.erp.common.core.exception.BusinessException;
import lombok.RequiredArgsConstructor;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Value;
import org.springframework.stereotype.Service;
import org.springframework.transaction.annotation.Transactional;
import org.springframework.util.StringUtils;
import org.springframework.web.multipart.MultipartFile;

import java.io.IOException;
import java.io.InputStream;
import java.time.LocalDate;
import java.time.LocalDateTime;
import java.time.format.DateTimeFormatter;
import java.util.*;
import java.util.stream.Collectors;

/**
 * 文件服务实现
 */
@Slf4j
@Service
@RequiredArgsConstructor
public class FileServiceImpl implements FileService {
    
    private final FileMapper fileMapper;
    private final StorageFactory storageFactory;
    
    @Value("${file.upload.max-size:10485760}")
    private Long maxFileSize;
    
    @Value("${file.upload.max-files-per-request:10}")
    private Integer maxFilesPerRequest;
    
    private static final List<String> PREVIEWABLE_TYPES = Arrays.asList(
            "image/jpeg", "image/png", "image/gif", "image/bmp", "image/svg+xml", "image/webp",
            "application/pdf",
            "text/plain", "text/html", "text/css", "text/javascript",
            "application/json", "application/xml"
    );
    
    private static final List<String> ALLOWED_TYPES = Arrays.asList(
            "image/jpeg", "image/png", "image/gif", "image/bmp", "image/svg+xml", "image/webp",
            "application/pdf",
            "application/msword", "application/vnd.openxmlformats-officedocument.wordprocessingml.document",
            "application/vnd.ms-excel", "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
            "application/vnd.ms-powerpoint", "application/vnd.openxmlformats-officedocument.presentationml.presentation",
            "text/plain", "text/csv",
            "application/zip", "application/x-rar-compressed", "application/x-7z-compressed",
            "application/json", "application/xml"
    );
    
    private static final List<String> ALLOWED_EXTENSIONS = Arrays.asList(
            "jpg", "jpeg", "png", "gif", "bmp", "svg", "webp",
            "pdf",
            "doc", "docx",
            "xls", "xlsx",
            "ppt", "pptx",
            "txt", "csv",
            "zip", "rar", "7z",
            "json", "xml"
    );
    
    // ==================== 查询操作 ====================
    
    @Override
    public PagedResponse<FileResponse> listFiles(FileQueryRequest request) {
        LambdaQueryWrapper<FileEntity> wrapper = new LambdaQueryWrapper<>();
        
        // 租户过滤（后续根据上下文设置）
        // wrapper.eq(FileEntity::getTenantId, tenantId);
        
        // 筛选条件
        if (request.getUserId() != null) {
            wrapper.eq(FileEntity::getUserId, request.getUserId());
        }
        if (StringUtils.hasText(request.getModule())) {
            wrapper.eq(FileEntity::getModule, request.getModule());
        }
        if (StringUtils.hasText(request.getPurpose())) {
            wrapper.eq(FileEntity::getPurpose, request.getPurpose());
        }
        if (StringUtils.hasText(request.getMimeType())) {
            wrapper.like(FileEntity::getMimeType, request.getMimeType());
        }
        if (StringUtils.hasText(request.getOriginalName())) {
            wrapper.like(FileEntity::getOriginalName, request.getOriginalName());
        }
        if (StringUtils.hasText(request.getStatus())) {
            wrapper.eq(FileEntity::getStatus, request.getStatus());
        }
        
        // 日期范围
        if (StringUtils.hasText(request.getDateRange())) {
            String[] dates = request.getDateRange().split(",");
            if (dates.length == 2) {
                LocalDate startDate = LocalDate.parse(dates[0].trim());
                LocalDate endDate = LocalDate.parse(dates[1].trim());
                wrapper.between(FileEntity::getCreatedAt, startDate.atStartOfDay(), endDate.plusDays(1).atStartOfDay());
            }
        }
        
        // 关键词搜索
        if (StringUtils.hasText(request.getKeyword())) {
            wrapper.and(w -> w
                    .like(FileEntity::getOriginalName, request.getKeyword())
                    .or()
                    .like(FileEntity::getDescription, request.getKeyword())
                    .or()
                    .like(FileEntity::getModule, request.getKeyword())
                    .or()
                    .like(FileEntity::getPurpose, request.getKeyword())
            );
        }
        
        // 默认按创建时间倒序
        wrapper.orderByDesc(FileEntity::getCreatedAt);
        
        // 分页查询
        Page<FileEntity> page = new Page<>(request.getPage(), request.getLimit());
        IPage<FileEntity> pageResult = fileMapper.selectPage(page, wrapper);
        
        // 转换结果
        List<FileResponse> list = pageResult.getRecords().stream()
                .map(entity -> {
                    StorageStrategy strategy = storageFactory.getStrategy(entity.getDisk());
                    boolean exists = strategy.exists(entity.getPath() + "/" + entity.getStorageName());
                    return FileResponse.fromEntity(entity, exists);
                })
                .collect(Collectors.toList());
        
        return PagedResponse.<FileResponse>builder()
                .list(list)
                .total(pageResult.getTotal())
                .currentPage((int) pageResult.getCurrent())
                .lastPage((int) pageResult.getPages())
                .limit((int) pageResult.getSize())
                .build();
    }
    
    @Override
    public FileResponse getFileById(Long id) {
        FileEntity entity = fileMapper.selectById(id);
        if (entity == null) {
            throw new BusinessException(404, "文件不存在");
        }
        
        StorageStrategy strategy = storageFactory.getStrategy(entity.getDisk());
        boolean exists = strategy.exists(entity.getPath() + "/" + entity.getStorageName());
        return FileResponse.fromEntity(entity, exists);
    }
    
    @Override
    public FileStatisticsResponse getStatistics(Long userId) {
        LambdaQueryWrapper<FileEntity> wrapper = new LambdaQueryWrapper<>();
        if (userId != null) {
            wrapper.eq(FileEntity::getUserId, userId);
        }
        
        // 总数
        Long totalCount = fileMapper.selectCount(wrapper);
        
        // 总大小
        List<FileEntity> allFiles = fileMapper.selectList(wrapper);
        long totalSize = allFiles.stream().mapToLong(f -> f.getSize() != null ? f.getSize() : 0).sum();
        
        // 活跃文件数
        LambdaQueryWrapper<FileEntity> activeWrapper = new LambdaQueryWrapper<>(wrapper);
        activeWrapper.eq(FileEntity::getStatus, "active");
        Long activeCount = fileMapper.selectCount(activeWrapper);
        
        // 用户数
        Long userCount = fileMapper.countDistinctUsers();
        
        // 模块数
        Long moduleCount = fileMapper.countDistinctModules();
        
        return FileStatisticsResponse.builder()
                .totalCount(totalCount)
                .totalSize(totalSize)
                .totalSizeFormatted(formatSize(totalSize))
                .activeCount(activeCount)
                .userCount(userCount)
                .moduleCount(moduleCount)
                .build();
    }
    
    @Override
    public List<String> getModules() {
        LambdaQueryWrapper<FileEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.select(FileEntity::getModule)
                .isNotNull(FileEntity::getModule)
                .ne(FileEntity::getModule, "")
                .groupBy(FileEntity::getModule)
                .orderByAsc(FileEntity::getModule);
        
        List<FileEntity> files = fileMapper.selectList(wrapper);
        return files.stream().map(FileEntity::getModule).collect(Collectors.toList());
    }
    
    // ==================== 上传操作 ====================
    
    @Override
    @Transactional
    public FileResponse uploadFile(MultipartFile file, String module, String purpose, String description, Long userId) {
        // 验证文件
        validateFile(file);
        
        try {
            // 生成存储信息
            String originalName = file.getOriginalFilename();
            String extension = getExtension(originalName);
            String storageName = UUID.randomUUID().toString() + "." + extension;
            String path = "uploads/" + LocalDate.now().format(DateTimeFormatter.ofPattern("yyyy/MM/dd"));
            
            // 获取存储策略
            StorageStrategy strategy = storageFactory.getDefaultStrategy();
            String url = strategy.upload(file, path, storageName);
            
            // 创建文件记录
            FileEntity entity = new FileEntity();
            entity.setUserId(userId);
            entity.setOriginalName(originalName);
            entity.setStorageName(storageName);
            entity.setPath(path);
            entity.setUrl(url);
            entity.setMimeType(file.getContentType());
            entity.setSize(file.getSize());
            entity.setExtension(extension);
            entity.setDisk(strategy.getType());
            entity.setModule(module != null ? module : "default");
            entity.setPurpose(purpose != null ? purpose : "upload");
            entity.setDescription(description);
            entity.setStatus("active");
            entity.setCreatedAt(LocalDateTime.now());
            entity.setUpdatedAt(LocalDateTime.now());
            
            fileMapper.insert(entity);
            
            log.info("文件上传成功: {} -> {}", originalName, storageName);
            return FileResponse.fromEntity(entity, true);
            
        } catch (Exception e) {
            log.error("文件上传失败", e);
            throw new BusinessException("文件上传失败: " + e.getMessage());
        }
    }
    
    @Override
    @Transactional
    public BatchUploadResponse batchUpload(MultipartFile[] files, String module, String purpose, Long userId) {
        if (files == null || files.length == 0) {
            throw new BusinessException(400, "请选择要上传的文件");
        }
        if (files.length > maxFilesPerRequest) {
            throw new BusinessException(400, "每次最多上传" + maxFilesPerRequest + "个文件");
        }
        
        List<FileResponse> uploadedFiles = new ArrayList<>();
        List<BatchUploadResponse.FailedFile> failedFiles = new ArrayList<>();
        
        for (MultipartFile file : files) {
            try {
                FileResponse response = uploadFile(file, module, purpose, null, userId);
                uploadedFiles.add(response);
            } catch (Exception e) {
                failedFiles.add(BatchUploadResponse.FailedFile.builder()
                        .name(file.getOriginalFilename())
                        .error(e.getMessage())
                        .build());
            }
        }
        
        return BatchUploadResponse.builder()
                .uploadedCount(uploadedFiles.size())
                .failedCount(failedFiles.size())
                .uploadedFiles(uploadedFiles)
                .failedFiles(failedFiles)
                .build();
    }
    
    // ==================== 更新操作 ====================
    
    @Override
    @Transactional
    public FileResponse updateFile(Long id, FileUpdateRequest request) {
        FileEntity entity = fileMapper.selectById(id);
        if (entity == null) {
            throw new BusinessException(404, "文件不存在");
        }
        
        // 更新字段
        if (StringUtils.hasText(request.getOriginalName())) {
            entity.setOriginalName(request.getOriginalName());
        }
        if (StringUtils.hasText(request.getDescription())) {
            entity.setDescription(request.getDescription());
        }
        if (StringUtils.hasText(request.getModule())) {
            entity.setModule(request.getModule());
        }
        if (StringUtils.hasText(request.getPurpose())) {
            entity.setPurpose(request.getPurpose());
        }
        if (StringUtils.hasText(request.getStatus())) {
            entity.setStatus(request.getStatus());
        }
        
        entity.setUpdatedAt(LocalDateTime.now());
        fileMapper.updateById(entity);
        
        StorageStrategy strategy = storageFactory.getStrategy(entity.getDisk());
        boolean exists = strategy.exists(entity.getPath() + "/" + entity.getStorageName());
        
        log.info("文件信息更新成功: {}", id);
        return FileResponse.fromEntity(entity, exists);
    }
    
    // ==================== 删除操作 ====================
    
    @Override
    @Transactional
    public void deleteFile(Long id) {
        FileEntity entity = fileMapper.selectById(id);
        if (entity == null) {
            throw new BusinessException(404, "文件不存在");
        }
        
        try {
            // 删除物理文件
            StorageStrategy strategy = storageFactory.getStrategy(entity.getDisk());
            strategy.delete(entity.getPath() + "/" + entity.getStorageName());
            
            // 删除数据库记录
            fileMapper.deleteById(id);
            
            log.info("文件删除成功: {}", id);
        } catch (Exception e) {
            log.error("文件删除失败: {}", id, e);
            throw new BusinessException("删除文件失败: " + e.getMessage());
        }
    }
    
    @Override
    @Transactional
    public Map<String, Object> batchDelete(List<Long> fileIds) {
        int successCount = 0;
        List<Map<String, Object>> failedFiles = new ArrayList<>();
        
        for (Long fileId : fileIds) {
            try {
                deleteFile(fileId);
                successCount++;
            } catch (Exception e) {
                FileEntity entity = fileMapper.selectById(fileId);
                failedFiles.add(Map.of(
                        "id", fileId,
                        "name", entity != null ? entity.getOriginalName() : "未知",
                        "reason", e.getMessage()
                ));
            }
        }
        
        return Map.of(
                "success_count", successCount,
                "failed_files", failedFiles
        );
    }
    
    @Override
    @Transactional
    public Map<String, Object> cleanupExpired(Integer days) {
        int cleanupDays = days != null ? days : 30;
        LocalDateTime cutoffDate = LocalDateTime.now().minusDays(cleanupDays);
        
        LambdaQueryWrapper<FileEntity> wrapper = new LambdaQueryWrapper<>();
        wrapper.lt(FileEntity::getCreatedAt, cutoffDate)
                .eq(FileEntity::getStatus, "inactive");
        
        List<FileEntity> expiredFiles = fileMapper.selectList(wrapper);
        int deletedCount = 0;
        
        for (FileEntity entity : expiredFiles) {
            try {
                StorageStrategy strategy = storageFactory.getStrategy(entity.getDisk());
                strategy.delete(entity.getPath() + "/" + entity.getStorageName());
                fileMapper.deleteById(entity.getId());
                deletedCount++;
            } catch (Exception e) {
                log.error("清理过期文件失败: {}", entity.getId(), e);
            }
        }
        
        log.info("清理过期文件完成，删除 {} 个文件", deletedCount);
        return Map.of("deleted_count", deletedCount);
    }
    
    // ==================== 下载预览 ====================
    
    @Override
    public InputStream downloadFile(Long id) {
        FileEntity entity = fileMapper.selectById(id);
        if (entity == null) {
            throw new BusinessException(404, "文件不存在");
        }
        
        StorageStrategy strategy = storageFactory.getStrategy(entity.getDisk());
        String fullPath = entity.getPath() + "/" + entity.getStorageName();
        
        if (!strategy.exists(fullPath)) {
            throw new BusinessException(404, "物理文件不存在");
        }
        
        return strategy.download(fullPath);
    }
    
    @Override
    public InputStream previewFile(Long id) {
        FileEntity entity = fileMapper.selectById(id);
        if (entity == null) {
            throw new BusinessException(404, "文件不存在");
        }
        
        StorageStrategy strategy = storageFactory.getStrategy(entity.getDisk());
        String fullPath = entity.getPath() + "/" + entity.getStorageName();
        
        if (!strategy.exists(fullPath)) {
            throw new BusinessException(404, "物理文件不存在");
        }
        
        // 检查是否支持预览
        if (!PREVIEWABLE_TYPES.contains(entity.getMimeType())) {
            throw new BusinessException(400, "该文件类型不支持预览");
        }
        
        return strategy.download(fullPath);
    }
    
    @Override
    public FileEntity getFileEntityForDownload(Long id) {
        FileEntity entity = fileMapper.selectById(id);
        if (entity == null) {
            throw new BusinessException(404, "文件不存在");
        }
        return entity;
    }
    
    // ==================== 配置 ====================
    
    @Override
    public UploadConfigResponse getUploadConfig() {
        return UploadConfigResponse.builder()
                .maxSize(maxFileSize / 1024) // 转换为KB
                .allowedTypes(ALLOWED_TYPES)
                .allowedExtensions(ALLOWED_EXTENSIONS)
                .maxFilesPerRequest(maxFilesPerRequest)
                .build();
    }
    
    // ==================== 私有方法 ====================
    
    private void validateFile(MultipartFile file) {
        if (file == null || file.isEmpty()) {
            throw new BusinessException(400, "上传文件不能为空");
        }
        if (file.getSize() > maxFileSize) {
            throw new BusinessException(400, "文件大小超过限制，最大" + (maxFileSize / 1024 / 1024) + "MB");
        }
        
        String extension = getExtension(file.getOriginalFilename());
        if (!ALLOWED_EXTENSIONS.contains(extension.toLowerCase())) {
            throw new BusinessException(400, "不支持的文件类型: " + extension);
        }
        
        String mimeType = file.getContentType();
        if (!ALLOWED_TYPES.contains(mimeType)) {
            throw new BusinessException(400, "不支持的MIME类型: " + mimeType);
        }
    }
    
    private String getExtension(String filename) {
        if (filename == null || !filename.contains(".")) {
            return "";
        }
        return filename.substring(filename.lastIndexOf(".") + 1).toLowerCase();
    }
    
    private String formatSize(long size) {
        if (size == 0) {
            return "0 B";
        }
        String[] units = {"B", "KB", "MB", "GB", "TB"};
        int unitIndex = 0;
        double fileSize = size;
        while (fileSize >= 1024 && unitIndex < units.length - 1) {
            fileSize /= 1024;
            unitIndex++;
        }
        return String.format("%.2f %s", fileSize, units[unitIndex]);
    }
}
