package cn.yunzhixue.ability.center.examsprint.infrastructure.report.pdf;

import java.io.File;
import java.io.IOException;
import java.io.InputStream;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.nio.file.StandardCopyOption;
import java.util.HashMap;
import java.util.List;
import java.util.Map;
import java.util.Objects;

public final class BundledOutlookReportFonts {

    private static final String DEFAULT_RESOURCE_PATH = "/fonts/MiSans-VF.ttf";
    private static final String TEMP_FILE_NAME = "MiSans-VF.ttf";
    private static final Map<String, BundledOutlookReportFonts> CACHE = new HashMap<>();

    private final List<Registration> registrations;

    private BundledOutlookReportFonts(List<Registration> registrations) {
        this.registrations = List.copyOf(registrations);
    }

    public static synchronized BundledOutlookReportFonts load() {
        return load(DEFAULT_RESOURCE_PATH);
    }

    public static synchronized BundledOutlookReportFonts load(String resourcePath) {
        Objects.requireNonNull(resourcePath, "resourcePath");

        BundledOutlookReportFonts cached = CACHE.get(resourcePath);
        if (cached != null && cached.isHealthy()) {
            return cached;
        }

        BundledOutlookReportFonts loaded = new BundledOutlookReportFonts(List.of(new Registration("MiSans", copyToTempFile(resourcePath))));
        CACHE.put(resourcePath, loaded);
        return loaded;
    }

    public List<Registration> registrations() {
        return registrations;
    }

    private boolean isHealthy() {
        return registrations.size() == 1 && isHealthy(registrations.get(0).file());
    }

    private static boolean isHealthy(File file) {
        return file.exists() && file.isFile() && file.canRead() && file.length() > 0L;
    }

    private static File copyToTempFile(String resourcePath) {
        try (InputStream inputStream = BundledOutlookReportFonts.class.getResourceAsStream(resourcePath)) {
            if (inputStream == null) {
                throw new BundledFontUnavailableException("Bundled font resource not found on classpath: " + resourcePath);
            }

            Path tempDirectory = Files.createTempDirectory("bundled-outlook-report-font-");
            Path tempFile = tempDirectory.resolve(TEMP_FILE_NAME);
            Files.copy(inputStream, tempFile, StandardCopyOption.REPLACE_EXISTING);
            File copiedFile = tempFile.toFile();
            tempDirectory.toFile().deleteOnExit();
            copiedFile.deleteOnExit();
            if (!isHealthy(copiedFile)) {
                throw new BundledFontUnavailableException("Bundled font copy is not readable: " + resourcePath + " -> " + tempFile);
            }
            return copiedFile;
        } catch (IOException exception) {
            throw new BundledFontUnavailableException("Failed to copy bundled font resource: " + resourcePath, exception);
        }
    }

    static final class BundledFontUnavailableException extends RuntimeException {

        BundledFontUnavailableException(String message) {
            super(message);
        }

        BundledFontUnavailableException(String message, Throwable cause) {
            super(message, cause);
        }
    }

    public record Registration(String family, File file) {
        public Registration {
            Objects.requireNonNull(family, "family");
            Objects.requireNonNull(file, "file");
        }
    }
}
