using Nexus.Api.Helpers;

namespace Nexus.Api.Services;

public sealed class MemoryService : IMemoryService
{
    private const string BasePath = "/mnt/workspace-iris/memory";
    private const string LongTermPath = "/mnt/workspace-iris/MEMORY.md";
    private const int MaxFileSize = 1_000_000;
    private const int MaxFiles = 50;

    public Task<IReadOnlyList<MemoryFileInfo>> GetAllAsync()
    {
        var files = new List<MemoryFileInfo>();

        if (File.Exists(LongTermPath))
        {
            var fi = new FileInfo(LongTermPath);
            files.Add(new MemoryFileInfo("MEMORY.md", "MEMORY.md", fi.Length, fi.LastWriteTimeUtc));
        }

        if (Directory.Exists(BasePath))
        {
            var memFiles = Directory.GetFiles(BasePath, "*.md")
                .Select(f => new FileInfo(f))
                .OrderByDescending(f => f.Name)
                .Select(f => new MemoryFileInfo(
                    f.Name,
                    f.FullName.Replace(BasePath, "").TrimStart('/'),
                    f.Length,
                    f.LastWriteTimeUtc));
            files.AddRange(memFiles);
        }

        return Task.FromResult<IReadOnlyList<MemoryFileInfo>>(files);
    }

    public async Task<IReadOnlyList<MemorySearchResult>> SearchAsync(string query)
    {
        var results = new List<MemorySearchResult>();

        async Task SearchDir(string dir)
        {
            if (!Directory.Exists(dir)) return;
            foreach (var file in Directory.GetFiles(dir, "*.md").Take(MaxFiles))
            {
                var fi = new FileInfo(file);
                if (fi.Length > MaxFileSize) continue;
                var content = await File.ReadAllTextAsync(file);
                if (!content.Contains(query, StringComparison.OrdinalIgnoreCase)) continue;

                var idx = content.IndexOf(query, StringComparison.OrdinalIgnoreCase);
                var start = Math.Max(0, idx - 60);
                var excerpt = (start > 0 ? "…" : "") + content.Substring(start, Math.Min(200, content.Length - start)) + "…";
                results.Add(new MemorySearchResult(
                    Path.GetFileName(file),
                    file.Replace(BasePath, "").TrimStart('/'),
                    excerpt,
                    fi.Length));
            }
        }

        await SearchDir(BasePath);

        if (File.Exists(LongTermPath))
        {
            var content = await File.ReadAllTextAsync(LongTermPath);
            if (content.Contains(query, StringComparison.OrdinalIgnoreCase))
            {
                var idx = content.IndexOf(query, StringComparison.OrdinalIgnoreCase);
                var start = Math.Max(0, idx - 60);
                var excerpt = (start > 0 ? "…" : "") + content.Substring(start, Math.Min(200, content.Length - start)) + "…";
                results.Insert(0, new MemorySearchResult("MEMORY.md", "MEMORY.md", excerpt, content.Length));
            }
        }

        return results;
    }

    public async Task<MemoryFileContent?> GetFileAsync(string name)
    {
        string? filePath;

        if (name.Equals("MEMORY.md", StringComparison.OrdinalIgnoreCase))
        {
            filePath = LongTermPath;
        }
        else
        {
            if (!PathSecurityHelper.TryResolveSafePath(BasePath, name, out filePath))
                return null;
        }

        if (!File.Exists(filePath!))
            return null;

        var content = await File.ReadAllTextAsync(filePath!);
        return new MemoryFileContent(name, name, content, content.Length, File.GetLastWriteTimeUtc(filePath!));
    }
}
