package cn.novalon.manage.file.handler;

import cn.novalon.manage.file.core.domain.SysFile;
import cn.novalon.manage.file.core.service.ISysFileService;
import io.swagger.v3.oas.annotations.Operation;
import io.swagger.v3.oas.annotations.tags.Tag;
import org.springframework.http.HttpStatus;
import org.springframework.http.codec.multipart.FilePart;
import org.springframework.stereotype.Component;
import org.springframework.web.reactive.function.server.ServerRequest;
import org.springframework.web.reactive.function.server.ServerResponse;
import reactor.core.publisher.Flux;
import reactor.core.publisher.Mono;

import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;

@Component
@Tag(name = "文件管理", description = "文件上传下载相关操作")
public class SysFileHandler {

    private final ISysFileService fileService;

    public SysFileHandler(ISysFileService fileService) {
        this.fileService = fileService;
    }

    @Operation(summary = "获取所有文件", description = "获取系统中所有文件列表")
    public Mono<ServerResponse> getAllFiles(ServerRequest request) {
        Flux<SysFile> files = fileService.getAllFiles();
        return ServerResponse.ok().body(files, SysFile.class);
    }

    @Operation(summary = "根据ID获取文件", description = "根据文件ID获取文件详细信息")
    public Mono<ServerResponse> getFileById(ServerRequest request) {
        Long id = Long.parseLong(request.pathVariable("id"));
        return fileService.getFileById(id)
                .flatMap(file -> ServerResponse.ok().bodyValue(file))
                .switchIfEmpty(ServerResponse.notFound().build());
    }

    @Operation(summary = "上传文件", description = "上传文件到系统")
    public Mono<ServerResponse> uploadFile(ServerRequest request) {
        String username = request.headers().firstHeader("X-Username");
        if (username == null) {
            username = "system";
        }
        final String finalUsername = username;

        return request.multipartData()
                .flatMap(multipartData -> {
                    var part = multipartData.getFirst("file");
                    if (part == null) {
                        return ServerResponse.badRequest().bodyValue("No file uploaded");
                    }

                    if (!(part instanceof FilePart)) {
                        return ServerResponse.badRequest().bodyValue("Invalid file part");
                    }

                    final FilePart filePart = (FilePart) part;
                    return fileService.uploadFile(filePart, finalUsername)
                            .flatMap(file -> ServerResponse.status(HttpStatus.CREATED).bodyValue(file));
                })
                .switchIfEmpty(ServerResponse.badRequest().bodyValue("No file data"));
    }

    @Operation(summary = "下载文件", description = "根据文件ID下载文件")
    public Mono<ServerResponse> downloadFile(ServerRequest request) {
        Long id = Long.parseLong(request.pathVariable("id"));
        return fileService.getFileById(id)
                .flatMap(file -> {
                    try {
                        Path filePath = Paths.get(file.getFilePath());
                        byte[] fileContent = Files.readAllBytes(filePath);
                        return ServerResponse.ok()
                                .header("Content-Disposition", "attachment; filename=\"" + file.getFileName() + "\"")
                                .header("Content-Type", file.getFileType())
                                .bodyValue(fileContent);
                    } catch (Exception e) {
                        return ServerResponse.notFound().build();
                    }
                })
                .switchIfEmpty(ServerResponse.notFound().build());
    }

    @Operation(summary = "根据文件名下载", description = "根据文件名下载文件")
    public Mono<ServerResponse> downloadFileByName(ServerRequest request) {
        String fileName = request.pathVariable("fileName");
        return fileService.getAllFiles()
                .filter(file -> file.getFileName().equals(fileName))
                .next()
                .flatMap(file -> {
                    try {
                        Path filePath = Paths.get(file.getFilePath());
                        byte[] fileContent = Files.readAllBytes(filePath);
                        return ServerResponse.ok()
                                .header("Content-Disposition", "attachment; filename=\"" + file.getFileName() + "\"")
                                .header("Content-Type", file.getFileType())
                                .bodyValue(fileContent);
                    } catch (Exception e) {
                        return ServerResponse.notFound().build();
                    }
                })
                .switchIfEmpty(ServerResponse.notFound().build());
    }

    @Operation(summary = "预览文件", description = "根据文件ID预览文件")
    public Mono<ServerResponse> previewFile(ServerRequest request) {
        Long id = Long.parseLong(request.pathVariable("id"));
        return fileService.getFileById(id)
                .flatMap(file -> {
                    try {
                        Path filePath = Paths.get(file.getFilePath());
                        byte[] fileContent = Files.readAllBytes(filePath);
                        return ServerResponse.ok()
                                .header("Content-Type", file.getFileType())
                                .bodyValue(fileContent);
                    } catch (Exception e) {
                        return ServerResponse.notFound().build();
                    }
                })
                .switchIfEmpty(ServerResponse.notFound().build());
    }

    @Operation(summary = "根据文件名预览", description = "根据文件名预览文件")
    public Mono<ServerResponse> previewFileByName(ServerRequest request) {
        String fileName = request.pathVariable("fileName");
        return fileService.getAllFiles()
                .filter(file -> file.getFileName().equals(fileName))
                .next()
                .flatMap(file -> {
                    try {
                        Path filePath = Paths.get(file.getFilePath());
                        byte[] fileContent = Files.readAllBytes(filePath);
                        return ServerResponse.ok()
                                .header("Content-Type", file.getFileType())
                                .bodyValue(fileContent);
                    } catch (Exception e) {
                        return ServerResponse.notFound().build();
                    }
                })
                .switchIfEmpty(ServerResponse.notFound().build());
    }

    @Operation(summary = "删除文件", description = "删除指定文件")
    public Mono<ServerResponse> deleteFile(ServerRequest request) {
        Long id = Long.parseLong(request.pathVariable("id"));
        return fileService.deleteFile(id)
                .then(ServerResponse.noContent().build())
                .onErrorResume(e -> ServerResponse.badRequest().bodyValue(e.getMessage()));
    }
}
