package p.studio.compiler.models;

import lombok.EqualsAndHashCode;
import lombok.Getter;
import org.apache.commons.io.FilenameUtils;
import p.studio.compiler.source.identifiers.ProjectId;
import p.studio.compiler.utilities.SourceProvider;
import p.studio.compiler.utilities.SourceProviderFactory;

import java.io.IOException;
import java.nio.charset.StandardCharsets;
import java.nio.file.Path;
import java.time.Instant;
import java.time.LocalDateTime;
import java.time.ZoneId;
import java.util.Optional;

@EqualsAndHashCode(onlyExplicitlyIncluded = true)
public class SourceHandle {
    @Getter
    private final ProjectId projectId;
    @Getter
    private final Path relativePath;
    @EqualsAndHashCode.Include
    @Getter
    private final Path canonPath;
    @Getter
    private final String filename;
    @Getter
    private final String extension;
    @Getter
    private final long size;
    @Getter
    private final long lastModified;
    private final SourceProvider provider;

    public SourceHandle(
            final ProjectId projectId,
            final Path relativePath,
            final Path canonPath,
            final long size,
            final long lastModified,
            final SourceProviderFactory factory) {
        this.projectId = projectId;
        this.relativePath = relativePath;
        this.canonPath = canonPath;
        this.filename = canonPath.getFileName().toString();
        this.extension = FilenameUtils.getExtension(this.filename);
        this.size = size;
        this.lastModified = lastModified;
        this.provider = factory.create(canonPath);
    }

    public Optional<byte[]> readBytes() {
        try {
            return Optional.ofNullable(provider.read());
        } catch (IOException e) {
            return Optional.empty();
        }
    }

    public Optional<String> readUtf8() {
        return readBytes().map(bytes -> new String(bytes, StandardCharsets.UTF_8));
    }

    @Override
    public String toString() {
        return "SourceHandle{ %s, %s, %sKb, mod: %s }".formatted(projectId,
                relativePath,
                size / 1024,
                LocalDateTime.ofInstant(Instant.ofEpochMilli(lastModified), ZoneId.systemDefault()));
    }
}