package com.njcn.gather.tool.parsepqdif;

import com.fasterxml.jackson.databind.ObjectMapper;
import com.njcn.gather.tool.parsepqdif.component.PqdifSecondParseComponent;
import com.njcn.gather.tool.parsepqdif.pojo.vo.PqdifParseResponse;
import com.njcn.gather.tool.parsepqdif.pojo.vo.PqdifRecognizeResultVO;
import com.njcn.gather.tool.parsepqdif.reader.PqdifNativeReader;
import com.njcn.gather.tool.parsepqdif.service.ParsePqdifService;
import com.njcn.gather.tool.parsepqdif.service.impl.ParsePqdifServiceImpl;
import org.springframework.web.multipart.MultipartFile;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.net.URL;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.Paths;
import java.nio.file.StandardCopyOption;
import java.util.Arrays;
import java.util.List;

public class PqdifDesktopFileTestProgram {

    private static final String PQDIF_FILE_NAME = "PQMonitor_PQM1_20210512_1000_01.pqd";
    private static final String MULTIPART_PARAM_NAME = "pqdifFile";
    private static final String SAMPLE_RESOURCE_PATH = "pqdif-samples/" + PQDIF_FILE_NAME;

    public static void main(String[] args) throws Exception {
        Path pqdifPath = resolvePqdifPath(args);
        if (!Files.isRegularFile(pqdifPath)) {
            System.out.println("PQDIF file not found: " + pqdifPath.toAbsolutePath());
            System.out.println("Usage: java " + PqdifDesktopFileTestProgram.class.getName() + " <pqdif-file-path>");
            return;
        }

        System.out.println("Parsing PQDIF file: " + pqdifPath.toAbsolutePath());

        ParsePqdifService parsePqdifService = new ParsePqdifServiceImpl(new PqdifNativeReader(), new PqdifSecondParseComponent());
        PqdifParseResponse response = parsePqdifService.parse(new PathMultipartFile(MULTIPART_PARAM_NAME, pqdifPath));
        System.out.println("Original parse response:");
        printResponse(response);

        PqdifRecognizeResultVO recognizableResult = parsePqdifService.parseRecognizable(response);
        System.out.println("Recognizable parse response:");
        printResponse(recognizableResult);
    }

    private static Path resolvePqdifPath(String[] args) {
        if (args != null && args.length > 0 && args[0] != null && !args[0].trim().isEmpty()) {
            return Paths.get(args[0].trim()).toAbsolutePath().normalize();
        }

        Path bundledSample = resolveBundledSamplePath();
        if (bundledSample != null && Files.isRegularFile(bundledSample)) {
            return bundledSample;
        }

        return defaultCandidatePaths().stream()
                .filter(Files::isRegularFile)
                .findFirst()
                .orElse(defaultDesktopPath());
    }

    private static Path resolveBundledSamplePath() {
        URL resource = PqdifDesktopFileTestProgram.class.getClassLoader().getResource(SAMPLE_RESOURCE_PATH);
        if (resource == null || !"file".equalsIgnoreCase(resource.getProtocol())) {
            return null;
        }
        try {
            return Paths.get(resource.toURI()).toAbsolutePath().normalize();
        } catch (Exception e) {
            return null;
        }
    }

    private static List<Path> defaultCandidatePaths() {
        return Arrays.asList(
                Paths.get("tools", "parse-pqdif", "src", "main", "resources", "pqdif-samples", PQDIF_FILE_NAME),
                Paths.get("src", "main", "resources", "pqdif-samples", PQDIF_FILE_NAME),
                defaultDesktopPath());
    }

    private static Path defaultDesktopPath() {
        return Paths.get(System.getProperty("user.home"), "Desktop", PQDIF_FILE_NAME);
    }

    private static void printResponse(Object response) throws IOException {
        ObjectMapper objectMapper = new ObjectMapper();
        System.out.println(objectMapper.writerWithDefaultPrettyPrinter().writeValueAsString(response));
    }

    private static class PathMultipartFile implements MultipartFile {

        private final String name;
        private final Path path;

        private PathMultipartFile(String name, Path path) {
            this.name = name;
            this.path = path;
        }

        @Override
        public String getName() {
            return name;
        }

        @Override
        public String getOriginalFilename() {
            return path.getFileName().toString();
        }

        @Override
        public String getContentType() {
            return "application/octet-stream";
        }

        @Override
        public boolean isEmpty() {
            try {
                return Files.size(path) == 0;
            } catch (IOException e) {
                return true;
            }
        }

        @Override
        public long getSize() {
            try {
                return Files.size(path);
            } catch (IOException e) {
                return 0L;
            }
        }

        @Override
        public byte[] getBytes() throws IOException {
            return Files.readAllBytes(path);
        }

        @Override
        public InputStream getInputStream() throws IOException {
            return Files.newInputStream(path);
        }

        @Override
        public void transferTo(File dest) throws IOException {
            Files.copy(path, dest.toPath(), StandardCopyOption.REPLACE_EXISTING);
        }
    }
}
