package top.tqx.demo_1.controller;

import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.Parameter;
import io.swagger.v3.oas.annotations.tags.Tag;
import jakarta.servlet.http.HttpServletRequest;
import jakarta.servlet.http.HttpServletResponse;
import lombok.extern.slf4j.Slf4j;
import org.springframework.beans.factory.annotation.Autowired;
import org.springframework.core.io.FileSystemResource;
import org.springframework.core.io.Resource;
import org.springframework.http.ContentDisposition;
import org.springframework.http.HttpHeaders;
import org.springframework.http.HttpStatus;
import org.springframework.http.MediaType;
import org.springframework.http.ResponseEntity;
import org.springframework.web.bind.annotation.*;
import org.springframework.web.multipart.MultipartFile;
import org.springframework.web.servlet.mvc.method.annotation.SseEmitter;
import top.tqx.demo_1.annotation.RateLimit;
import top.tqx.demo_1.common.PageResult;
import top.tqx.demo_1.common.Result;
import top.tqx.demo_1.dto.FileUpdateRequest;
import top.tqx.demo_1.dto.RagRequest;
import top.tqx.demo_1.entity.Department;
import top.tqx.demo_1.entity.User;
import top.tqx.demo_1.mapper.UserMapper;
import top.tqx.demo_1.service.AiChatService;
import top.tqx.demo_1.service.DepartmentService;
import top.tqx.demo_1.service.FileService;
import top.tqx.demo_1.util.FileUtil;
import top.tqx.demo_1.vo.FileVO;

import java.net.URLEncoder;
import java.nio.charset.StandardCharsets;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.time.LocalDateTime;
import java.util.ArrayList;
import java.util.List;

@Tag(name = "文件管理", description = "文件的上传、下载、删除等操作")
@RestController
@RequestMapping("/file")
@Slf4j
public class FileController extends BaseController {

    @Autowired
    private FileService fileService;

    @Autowired
    private AiChatService aiChatService;
    
    @Autowired
    private DepartmentService departmentService;
    
    @Autowired
    private UserMapper userMapper;
    
    @org.springframework.beans.factory.annotation.Value("${file.upload.path:./uploads/}")
    private String uploadPath;

    @Operation(summary = "分页查询文件", description = "根据条件分页查询文件列表")
    @GetMapping("/page")
    public Result<PageResult<FileVO>> pageFiles(
            @Parameter(description = "页码", example = "1") @RequestParam(defaultValue = "1") Integer pageNum,
            @Parameter(description = "每页大小", example = "10") @RequestParam(defaultValue = "10") Integer pageSize,
            @Parameter(description = "文件名") @RequestParam(required = false) String fileName,
            HttpServletRequest request) {
        Long userId = getCurrentUserId(request);
        if (userId == null) {
            return error("用户未登录");
        }
        User user = authService.validateToken(request.getHeader("Authorization").substring(7));
        if (user == null) {
            return error("用户信息获取失败");
        }
        PageResult<FileVO> result = fileService.pageFiles(pageNum, pageSize, fileName, user);
        return success(result);
    }

    @Operation(summary = "查询文件详情", description = "根据ID查询文件详细信息")
    @GetMapping("/{id}")
    public Result<FileVO> getFileById(@Parameter(description = "文件ID") @PathVariable Long id, HttpServletRequest request) {
        Long userId = getCurrentUserId(request);
        if (userId == null) {
            return error("用户未登录");
        }
        User user = authService.validateToken(request.getHeader("Authorization").substring(7));
        if (user == null) {
            return error("用户信息获取失败");
        }
        FileVO file = fileService.getFileById(id, user);
        return success(file);
    }

    @Operation(summary = "上传文件", description = "上传文件到服务器，支持个人文件和部门制度文件")
    @PostMapping("/upload")
    @RateLimit(maxRequests = 10, timeWindow = 60, key = "user")
    public Result<FileVO> uploadFile(
            @Parameter(description = "文件对象", required = true) @RequestParam("file") MultipartFile file,
            @Parameter(description = "部门ID（管理员上传制度文件时指定）") @RequestParam(required = false) Long deptId,
            @Parameter(description = "是否公开", example = "true") @RequestParam(required = false, defaultValue = "true") Boolean isPublic,
            @Parameter(description = "文件描述") @RequestParam(required = false) String description,
            HttpServletRequest request) {
        try {
            FileUtil.validateFile(file);
            
            Long userId = getCurrentUserId(request);
            if (userId == null) {
                return error("用户未登录");
            }
            
            User user = authService.validateToken(request.getHeader("Authorization").substring(7));
            if (user == null) {
                return error("用户信息获取失败");
            }
            
            FileVO fileVO = fileService.uploadFile(file, userId, user.getDeptId(), user.getUserType(), deptId, isPublic);
            
            if (description != null && !description.isEmpty()) {
                fileService.updateFileDescription(fileVO.getId(), description);
                fileVO.setDescription(description);
            }
            
            return success(fileVO);
        } catch (Exception e) {
            log.error("文件上传失败", e);
            return error("文件上传失败: " + e.getMessage());
        }
    }

    @Operation(summary = "RAG流式问答", description = "向RAG服务发起流式问答请求，实时返回处理过程，完成后自动保存到数据库")
    @PostMapping(value = "/rag/stream", produces = MediaType.TEXT_EVENT_STREAM_VALUE)
    public SseEmitter ragStream(
            @Parameter(description = "用户问题", required = true) @RequestParam("message") String message,
            HttpServletRequest httpRequest) {
        try {
            Long userId = getCurrentUserId(httpRequest);
            if (userId == null) {
                SseEmitter emitter = new SseEmitter();
                try {
                    emitter.send(SseEmitter.event()
                            .name("error")
                            .data("{\"type\":\"error\",\"message\":\"用户未登录\"}"));
                    emitter.complete();
                } catch (Exception e) {
                    emitter.completeWithError(e);
                }
                return emitter;
            }
            
            User user = authService.validateToken(httpRequest.getHeader("Authorization").substring(7));
            if (user == null) {
                SseEmitter emitter = new SseEmitter();
                try {
                    emitter.send(SseEmitter.event()
                            .name("error")
                            .data("{\"type\":\"error\",\"message\":\"用户信息获取失败\"}"));
                    emitter.complete();
                } catch (Exception e) {
                    emitter.completeWithError(e);
                }
                return emitter;
            }
            
            RagRequest request = new RagRequest();
            request.setMessage(message);
            
            // 硬编码 collections
            List<String> collections = new ArrayList<>();
            collections.add("public_kb");
            request.setCollections(collections);
            
            // 硬编码生成 session_id
            String sessionId = "sess_" + System.currentTimeMillis();
            request.setSessionId(sessionId);
            
            request.setUserId(userId);
            request.setDeptId(user.getDeptId());
            request.setUserRole(user.getUserType());
            
            log.info("开始RAG流式问答: userId={}, deptId={}, role={}, message={}, collections={}, sessionId={}", 
                    userId, user.getDeptId(), user.getUserType(), request.getMessage(), 
                    request.getCollections(), request.getSessionId());
            return aiChatService.streamFromRagService(request, userId, user.getDeptId());
            
        } catch (Exception e) {
            log.error("RAG流式问答失败", e);
            SseEmitter emitter = new SseEmitter();
            try {
                emitter.send(SseEmitter.event()
                        .name("error")
                        .data("{\"type\":\"error\",\"message\":\"" + e.getMessage() + "\"}"));
                emitter.complete();
            } catch (Exception ex) {
                emitter.completeWithError(ex);
            }
            return emitter;
        }
    }

    @Autowired
    private org.springframework.core.env.Environment environment;

    @Operation(summary = "下载文件", description = "根据ID下载文件")
    @GetMapping("/download/{id}")
    public ResponseEntity<Resource> downloadFile(
            @Parameter(description = "文件ID") @PathVariable Long id, 
            HttpServletResponse response, 
            HttpServletRequest request) {
        try {
            Long userId = getCurrentUserId(request);
            if (userId == null) {
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
            }

            User user = authService.validateToken(request.getHeader("Authorization").substring(7));
            if (user == null) {
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
            }

            top.tqx.demo_1.entity.File fileEntity = fileService.getFileEntityById(id);
            if (fileEntity == null) {
                return ResponseEntity.notFound().build();
            }

            byte[] fileContent = fileService.getFileContent(id, user);

            String contentType = determineContentType(fileEntity);
            String encodedFileName = URLEncoder.encode(fileEntity.getFileName(), StandardCharsets.UTF_8)
                    .replaceAll("\\+", "%20");

            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType(contentType));
            headers.setContentDisposition(ContentDisposition.attachment()
                    .filename(encodedFileName, StandardCharsets.UTF_8)
                    .build());
            headers.setContentLength(fileContent.length);
            headers.setCacheControl("max-age=3600");

            Resource resource = new org.springframework.core.io.ByteArrayResource(fileContent);
            return new ResponseEntity<>(resource, headers, HttpStatus.OK);
        } catch (RuntimeException e) {
            if (e.getMessage().contains("无权限")) {
                return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
            }
            log.error("下载文件失败: fileId={}", id, e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        } catch (Exception e) {
            log.error("下载文件异常: fileId={}", id, e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    @Operation(summary = "获取文件内容", description = "根据ID获取文件二进制内容，供后端服务使用")
    @GetMapping("/content/{id}")
    public Result<byte[]> getFileContent(@Parameter(description = "文件ID") @PathVariable Long id, HttpServletRequest request) {
        try {
            Long userId = getCurrentUserId(request);
            if (userId == null) {
                return error("用户未登录");
            }

            User user = authService.validateToken(request.getHeader("Authorization").substring(7));
            if (user == null) {
                return error("用户信息获取失败");
            }

            byte[] fileContent = fileService.getFileContent(id, user);
            return success(fileContent);
        } catch (RuntimeException e) {
            if (e.getMessage().contains("无权限")) {
                return error("无权限查看此文件");
            }
            log.error("获取文件内容失败: fileId={}", id, e);
            return error("获取文件内容失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("获取文件内容异常: fileId={}", id, e);
            return error("获取文件内容失败");
        }
    }

    @Operation(summary = "获取文件详细信息", description = "获取文件的所有信息包括内容，供后端服务使用")
    @GetMapping("/info/{id}")
    public Result<FileVO> getFileInfo(@Parameter(description = "文件ID") @PathVariable Long id, HttpServletRequest request) {
        try {
            Long userId = getCurrentUserId(request);
            if (userId == null) {
                return error("用户未登录");
            }
            User user = authService.validateToken(request.getHeader("Authorization").substring(7));
            if (user == null) {
                return error("用户信息获取失败");
            }
            FileVO fileInfo = fileService.getFileById(id, user);
            return success(fileInfo);
        } catch (Exception e) {
            log.error("获取文件信息失败", e);
            return error("获取文件信息失败");
        }
    }

    @Operation(summary = "预览文件", description = "获取文件二进制内容用于前端预览，支持PDF、图片、文本等格式")
    @GetMapping("/preview/{id}")
    public ResponseEntity<byte[]> previewFile(
            @Parameter(description = "文件ID") @PathVariable Long id,
            HttpServletRequest request) {
        try {
            Long userId = getCurrentUserId(request);
            if (userId == null) {
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
            }

            User user = authService.validateToken(request.getHeader("Authorization").substring(7));
            if (user == null) {
                return ResponseEntity.status(HttpStatus.UNAUTHORIZED).build();
            }

            byte[] fileContent = fileService.getFileContent(id, user);
            top.tqx.demo_1.entity.File fileEntity = fileService.getFileEntityById(id);

            if (fileEntity == null) {
                return ResponseEntity.notFound().build();
            }

            String contentType = determineContentType(fileEntity);
            HttpHeaders headers = new HttpHeaders();
            headers.setContentType(MediaType.parseMediaType(contentType));
            headers.setContentDisposition(ContentDisposition.inline()
                    .filename(fileEntity.getFileName(), java.nio.charset.StandardCharsets.UTF_8)
                    .build());
            headers.setCacheControl("max-age=3600");
            headers.setContentLength(fileContent.length);

            return new ResponseEntity<>(fileContent, headers, HttpStatus.OK);
        } catch (RuntimeException e) {
            if (e.getMessage().contains("无权限")) {
                return ResponseEntity.status(HttpStatus.FORBIDDEN).build();
            }
            log.error("预览文件失败: fileId={}", id, e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        } catch (Exception e) {
            log.error("预览文件异常: fileId={}", id, e);
            return ResponseEntity.status(HttpStatus.INTERNAL_SERVER_ERROR).build();
        }
    }

    @Operation(summary = "获取文本文件内容", description = "获取文本类文件的字符串内容，适用于txt、json、xml、csv等格式")
    @GetMapping("/text/{id}")
    public Result<String> getTextFileContent(
            @Parameter(description = "文件ID") @PathVariable Long id,
            HttpServletRequest request) {
        try {
            Long userId = getCurrentUserId(request);
            if (userId == null) {
                return error("用户未登录");
            }

            User user = authService.validateToken(request.getHeader("Authorization").substring(7));
            if (user == null) {
                return error("用户信息获取失败");
            }

            top.tqx.demo_1.entity.File fileEntity = fileService.getFileEntityById(id);
            if (fileEntity == null) {
                return error("文件不存在");
            }

            String extension = fileEntity.getExtension() != null ? fileEntity.getExtension().toLowerCase() : "";
            if (!isTextFile(extension)) {
                return error("该文件不是文本格式，请使用预览接口");
            }

            byte[] fileContent = fileService.getFileContent(id, user);
            String content = new String(fileContent, java.nio.charset.StandardCharsets.UTF_8);

            return success(content);
        } catch (RuntimeException e) {
            if (e.getMessage().contains("无权限")) {
                return error("无权限查看此文件");
            }
            log.error("获取文本文件内容失败: fileId={}", id, e);
            return error("获取文件内容失败: " + e.getMessage());
        } catch (Exception e) {
            log.error("获取文本文件内容异常: fileId={}", id, e);
            return error("获取文件内容失败");
        }
    }

    private String determineContentType(top.tqx.demo_1.entity.File fileEntity) {
        String extension = fileEntity.getExtension() != null ? fileEntity.getExtension().toLowerCase() : "";

        switch (extension) {
            case ".pdf":
                return "application/pdf";
            case ".jpg":
            case ".jpeg":
                return "image/jpeg";
            case ".png":
                return "image/png";
            case ".gif":
                return "image/gif";
            case ".webp":
                return "image/webp";
            case ".bmp":
                return "image/bmp";
            case ".svg":
                return "image/svg+xml";
            case ".txt":
                return "text/plain; charset=utf-8";
            case ".html":
            case ".htm":
                return "text/html; charset=utf-8";
            case ".json":
                return "application/json; charset=utf-8";
            case ".xml":
                return "application/xml; charset=utf-8";
            case ".csv":
                return "text/csv; charset=utf-8";
            case ".md":
                return "text/markdown; charset=utf-8";
            case ".js":
                return "application/javascript; charset=utf-8";
            case ".css":
                return "text/css; charset=utf-8";
            default:
                return "application/octet-stream";
        }
    }

    private boolean isTextFile(String extension) {
        return ".txt".equals(extension) ||
               ".json".equals(extension) ||
               ".xml".equals(extension) ||
               ".csv".equals(extension) ||
               ".html".equals(extension) ||
               ".htm".equals(extension) ||
               ".md".equals(extension) ||
               ".log".equals(extension) ||
               ".js".equals(extension) ||
               ".css".equals(extension);
    }

    @Operation(summary = "删除文件", description = "根据ID删除文件")
    @DeleteMapping("/{id}")
    public Result<Void> deleteFile(@Parameter(description = "文件ID") @PathVariable Long id, HttpServletRequest request) {
        Long userId = getCurrentUserId(request);
        if (userId == null) {
            return error("用户未登录");
        }
        
        User user = authService.validateToken(request.getHeader("Authorization").substring(7));
        if (user == null) {
            return error("用户信息获取失败");
        }
        
        top.tqx.demo_1.entity.File file = fileService.getFileEntityById(id);
        if (file == null) {
            return error("文件不存在");
        }
        
        boolean canDelete = false;
        if (user.getUserType() == 1) {
            canDelete = true;
        } else if (user.getUserType() == 2 && file.getDeptId().equals(user.getDeptId())) {
            canDelete = true;
        } else if (file.getUploadUserId().equals(userId)) {
            canDelete = true;
        }
        
        if (!canDelete) {
            return error("无权限删除此文件");
        }
        
        fileService.deleteFile(id);
        return success();
    }

    @Operation(summary = "审核通过文件", description = "管理员审核通过用户上传的公开文件")
    @PostMapping("/audit/approve/{id}")
    public Result<Void> approveFile(
            @Parameter(description = "文件ID") @PathVariable Long id,
            HttpServletRequest request) {
        try {
            Long userId = getCurrentUserId(request);
            if (userId == null) {
                return error("用户未登录");
            }
            
            User user = authService.validateToken(request.getHeader("Authorization").substring(7));
            if (user == null) {
                return error("用户信息获取失败");
            }
            
            if (user.getUserType() != 1 && user.getUserType() != 2) {
                return error("无权限执行此操作");
            }
            
            fileService.approveFile(id, userId);
            return success();
        } catch (Exception e) {
            log.error("审核通过失败", e);
            return error("审核通过失败: " + e.getMessage());
        }
    }

    @Operation(summary = "审核拒绝文件", description = "管理员拒绝用户上传的公开文件")
    @PostMapping("/audit/reject/{id}")
    public Result<Void> rejectFile(
            @Parameter(description = "文件ID") @PathVariable Long id,
            HttpServletRequest request) {
        try {
            Long userId = getCurrentUserId(request);
            if (userId == null) {
                return error("用户未登录");
            }
            
            User user = authService.validateToken(request.getHeader("Authorization").substring(7));
            if (user == null) {
                return error("用户信息获取失败");
            }
            
            if (user.getUserType() != 1 && user.getUserType() != 2) {
                return error("无权限执行此操作");
            }
            
            fileService.rejectFile(id, userId);
            return success();
        } catch (Exception e) {
            log.error("审核拒绝失败", e);
            return error("审核拒绝失败: " + e.getMessage());
        }
    }

    @Operation(summary = "查询待审核文件列表", description = "管理员查询所有待审核的文件")
    @GetMapping("/audit/pending")
    public Result<PageResult<FileVO>> getPendingFiles(
            @Parameter(description = "页码", example = "1") @RequestParam(defaultValue = "1") Integer pageNum,
            @Parameter(description = "每页大小", example = "10") @RequestParam(defaultValue = "10") Integer pageSize,
            HttpServletRequest request) {
        try {
            Long userId = getCurrentUserId(request);
            if (userId == null) {
                return error("用户未登录");
            }
            
            User user = authService.validateToken(request.getHeader("Authorization").substring(7));
            if (user == null) {
                return error("用户信息获取失败");
            }
            
            if (user.getUserType() != 1 && user.getUserType() != 2) {
                return error("无权限执行此操作");
            }
            
            PageResult<FileVO> result = fileService.getPendingFiles(pageNum, pageSize);
            return success(result);
        } catch (Exception e) {
            log.error("查询待审核文件失败", e);
            return error("查询待审核文件失败: " + e.getMessage());
        }
    }

    @Operation(summary = "更新文件信息", description = "更新文件的公开状态、描述等信息")
    @PutMapping("/{id}")
    public Result<FileVO> updateFileInfo(
            @Parameter(description = "文件ID") @PathVariable Long id,
            @RequestBody FileUpdateRequest request,
            HttpServletRequest httpRequest) {
        try {
            Long userId = getCurrentUserId(httpRequest);
            if (userId == null) {
                return error("用户未登录");
            }
            
            User user = authService.validateToken(httpRequest.getHeader("Authorization").substring(7));
            if (user == null) {
                return error("用户信息获取失败");
            }
            
            top.tqx.demo_1.entity.File file = fileService.getFileEntityById(id);
            if (file == null) {
                return error("文件不存在");
            }
            
            if (request.getIsPublic() != null) {
                Integer newIsPublic = request.getIsPublic();
                if (!newIsPublic.equals(file.getIsPublic())) {
                    String oldPath = file.getFilePath();
                    Boolean isPublicBool = newIsPublic == 1;
                    String newPath = rebuildFilePath(file, isPublicBool, user);
                    
                    Path fullOldPath = Paths.get(uploadPath, oldPath);
                    Path fullNewPath = Paths.get(uploadPath, newPath);
                    
                    if (Files.exists(fullOldPath)) {
                        Files.createDirectories(fullNewPath.getParent());
                        Files.move(fullOldPath, fullNewPath);
                        
                        file.setFilePath(newPath);
                        log.info("文件路径已更新: {} -> {}", oldPath, newPath);
                    }
                    
                    file.setIsPublic(newIsPublic);
                }
            }
            
            if (request.getDescription() != null) {
                file.setDescription(request.getDescription());
            }
            
            if (request.getAuditStatus() != null) {
                file.setAuditStatus(request.getAuditStatus());
            }
            
            file.setUpdateTime(LocalDateTime.now());
            fileService.updateFileEntity(file);
            
            return success(convertToVO(file));
        } catch (Exception e) {
            log.error("更新文件信息失败", e);
            return error("更新文件信息失败: " + e.getMessage());
        }
    }
    
    private String rebuildFilePath(top.tqx.demo_1.entity.File file, Boolean isPublic, User user) {
        String fileNameWithoutExt = file.getFileName().contains(".") 
            ? file.getFileName().substring(0, file.getFileName().lastIndexOf(".")) 
            : file.getFileName();
        
        Path basePath;
        if (user.getUserType() == 1 || user.getUserType() == 2) {
            String fullPath = departmentService.getDepartmentFullPath(user.getDeptId());
            if (fullPath == null || fullPath.isEmpty()) {
                fullPath = "默认部门";
            }
            basePath = Paths.get(uploadPath, "resources", "rule", fullPath, fileNameWithoutExt);
        } else {
            String username = getUserUsername(file.getUploadUserId());
            String privacyPath = isPublic ? "public" : "private";
            basePath = Paths.get(uploadPath, "resources", "user", username, privacyPath, fileNameWithoutExt);
        }
        
        int version = 1;
        while (Files.exists(basePath.resolve("v" + version))) {
            version++;
        }
        
        Path filePath = basePath.resolve("v" + version).resolve(file.getFileName());
        String relativePath = filePath.toString().replace(uploadPath, "");
        if (relativePath.startsWith(java.io.File.separator)) {
            relativePath = relativePath.substring(1);
        }
        if (relativePath.startsWith("/")) {
            relativePath = relativePath.substring(1);
        }
        return relativePath;
    }
    
    private String getUserUsername(Long userId) {
        try {
            User user = userMapper.selectById(userId);
            if (user != null && user.getUsername() != null && !user.getUsername().isEmpty()) {
                return user.getUsername();
            }
        } catch (Exception e) {
            log.warn("获取用户名失败: userId={}", userId, e);
        }
        return "user_" + userId;
    }
    
    private FileVO convertToVO(top.tqx.demo_1.entity.File file) {
        FileVO vo = new FileVO();
        org.springframework.beans.BeanUtils.copyProperties(file, vo);
        
        if (file.getUploadUserId() != null) {
            try {
                User user = userMapper.selectById(file.getUploadUserId());
                if (user != null && user.getUsername() != null) {
                    vo.setUploadUserName(user.getUsername());
                } else {
                    vo.setUploadUserName("user_" + file.getUploadUserId());
                }
            } catch (Exception e) {
                log.warn("获取上传用户名称失败: userId={}", file.getUploadUserId());
                vo.setUploadUserName("user_" + file.getUploadUserId());
            }
        }
        
        if (file.getDeptId() != null) {
            try {
                Department department = departmentService.getDepartmentById(file.getDeptId());
                if (department != null) {
                    vo.setDeptName(department.getDeptName());
                }
            } catch (Exception e) {
                log.warn("获取部门名称失败: deptId={}", file.getDeptId());
            }
        }
        
        return vo;
    }

}
