package p.studio.controls.shell;

import com.fasterxml.jackson.annotation.JsonIgnoreProperties;
import com.fasterxml.jackson.databind.ObjectMapper;
import p.studio.projects.ProjectReference;
import p.studio.projects.ProjectStudioPaths;

import java.io.IOException;
import java.io.UncheckedIOException;
import java.nio.file.Files;
import java.nio.file.Path;
import java.util.ArrayList;
import java.util.List;
import java.util.Objects;

public final class StudioActivityStorageService {
    public static final int MAX_HISTORY = 500;

    private static final ObjectMapper MAPPER = new ObjectMapper();

    public List<StudioActivityEntry> load(ProjectReference projectReference) {
        final Path activitiesPath = ProjectStudioPaths.activitiesPath(projectReference);
        if (!Files.isRegularFile(activitiesPath)) {
            return List.of();
        }

        try {
            final PersistedActivityEntry[] persistedEntries = MAPPER.readValue(
                    activitiesPath.toFile(),
                    PersistedActivityEntry[].class);
            final List<StudioActivityEntry> entries = new ArrayList<>();
            for (PersistedActivityEntry persistedEntry : persistedEntries) {
                final StudioActivityEntry mapped = map(persistedEntry);
                if (mapped != null) {
                    entries.add(mapped);
                }
            }
            return bounded(entries);
        } catch (IOException | RuntimeException ignored) {
            return List.of();
        }
    }

    public void save(ProjectReference projectReference, List<StudioActivityEntry> entries) {
        final Path activitiesPath = ProjectStudioPaths.activitiesPath(projectReference);
        final List<StudioActivityEntry> boundedEntries = bounded(entries);
        final List<PersistedActivityEntry> persistedEntries = boundedEntries.stream()
                .map(entry -> new PersistedActivityEntry(
                        entry.source(),
                        entry.message(),
                        entry.severity().name(),
                        entry.sticky()))
                .toList();

        try {
            Files.createDirectories(activitiesPath.getParent());
            MAPPER.writerWithDefaultPrettyPrinter().writeValue(activitiesPath.toFile(), persistedEntries);
        } catch (IOException ioException) {
            throw new UncheckedIOException(ioException);
        }
    }

    public List<StudioActivityEntry> bounded(List<StudioActivityEntry> entries) {
        final List<StudioActivityEntry> normalized = List.copyOf(Objects.requireNonNull(entries, "entries"));
        if (normalized.size() <= MAX_HISTORY) {
            return normalized;
        }
        return List.copyOf(normalized.subList(0, MAX_HISTORY));
    }

    private StudioActivityEntry map(PersistedActivityEntry persistedEntry) {
        if (persistedEntry == null
                || persistedEntry.source == null
                || persistedEntry.message == null
                || persistedEntry.severity == null) {
            return null;
        }
        try {
            return new StudioActivityEntry(
                    persistedEntry.source,
                    persistedEntry.message,
                    StudioActivityEntrySeverity.valueOf(persistedEntry.severity.trim()),
                    persistedEntry.sticky);
        } catch (RuntimeException ignored) {
            return null;
        }
    }

    @JsonIgnoreProperties(ignoreUnknown = true)
    private static final class PersistedActivityEntry {
        public String source;
        public String message;
        public String severity;
        public boolean sticky;

        public PersistedActivityEntry() {
        }

        private PersistedActivityEntry(String source, String message, String severity, boolean sticky) {
            this.source = source;
            this.message = message;
            this.severity = severity;
            this.sticky = sticky;
        }
    }
}
