using System.Text.RegularExpressions;
using Nexus.Api.Models;

namespace Nexus.Api.Services;

public sealed partial class IncidentService(
    IOpenClawAgentConfigurationService configuration) : IIncidentService
{
    private const string IncidentDirectory = "memory/incidents";

    public async Task<IReadOnlyList<IncidentSummary>> GetAllAsync(
        string agentId,
        CancellationToken cancellationToken = default)
    {
        var normalizedAgentId = NormalizeAgentId(agentId);
        OpenClawWorkspaceCollectionDto listing;
        try
        {
            listing = await configuration.GetWorkspaceAsync(
                normalizedAgentId,
                IncidentDirectory,
                0,
                OpenClawContentReadHelpers.MaxFiles,
                cancellationToken);
        }
        catch (OpenClawGatewayRpcException exception)
            when (OpenClawContentReadHelpers.IsNotFound(exception))
        {
            return [];
        }

        var entries = listing.Entries
            .Where(OpenClawContentReadHelpers.IsMarkdownFile)
            .OrderByDescending(entry => entry.Name, StringComparer.OrdinalIgnoreCase);
        return await OpenClawContentReadHelpers.SelectBoundedAsync<
            OpenClawWorkspaceEntryDto,
            IncidentSummary>(
            entries,
            async (entry, token) =>
            {
                var file = await configuration.GetWorkspaceFileAsync(
                    normalizedAgentId,
                    entry.Path,
                    token);
                var content = OpenClawContentReadHelpers.ReadText(file);
                if (content is null)
                    return null;
                var baseName = Path.GetFileNameWithoutExtension(file.Name);
                return new IncidentSummary(
                    file.Name,
                    ExtractTitle(baseName, content),
                    ExtractDate(file.Name),
                    ExtractSeverity(content),
                    ExtractExcerpt(content),
                    file.Size,
                    normalizedAgentId,
                    file.Path);
            },
            cancellationToken);
    }

    public async Task<IncidentDetail?> GetByNameAsync(
        string name,
        string agentId,
        CancellationToken cancellationToken = default)
    {
        if (!OpenClawContentReadHelpers.IsSafeFileName(name))
            return null;
        var normalizedAgentId = NormalizeAgentId(agentId);
        var fileName = name.EndsWith(".md", StringComparison.OrdinalIgnoreCase)
            ? name
            : name + ".md";
        try
        {
            var file = await configuration.GetWorkspaceFileAsync(
                normalizedAgentId,
                $"{IncidentDirectory}/{fileName}",
                cancellationToken);
            var content = OpenClawContentReadHelpers.ReadText(file);
            if (content is null)
                return null;
            return new IncidentDetail(
                file.Name,
                ExtractTitle(
                    Path.GetFileNameWithoutExtension(file.Name),
                    content),
                ExtractDate(file.Name),
                content,
                file.Size,
                normalizedAgentId,
                file.Path);
        }
        catch (OpenClawGatewayRpcException exception)
            when (OpenClawContentReadHelpers.IsNotFound(exception))
        {
            return null;
        }
    }

    private static string NormalizeAgentId(string? agentId)
        => string.IsNullOrWhiteSpace(agentId)
            ? "iris"
            : agentId.Trim().ToLowerInvariant();

    private static string ExtractTitle(string name, string content)
    {
        var match = TitleRegex().Match(content);
        return match.Success ? match.Groups[1].Value.Trim() : name;
    }

    private static string? ExtractDate(string fileName)
    {
        var match = DateRegex().Match(fileName);
        return match.Success ? match.Groups[1].Value : null;
    }

    private static string ExtractSeverity(string content)
    {
        var match = SeverityRegex().Match(content);
        return match.Success ? match.Groups[1].Value.Trim() : "unknown";
    }

    private static string ExtractExcerpt(string content)
    {
        var excerptEnd = content.IndexOf("\n## ", StringComparison.Ordinal);
        var excerpt = excerptEnd > 0
            ? content[..excerptEnd].Trim()
            : content[..Math.Min(300, content.Length)].Trim();
        return excerpt.Length > 200 ? excerpt[..200] + "…" : excerpt;
    }

    [GeneratedRegex(@"^#\s+(.+)$", RegexOptions.Multiline)]
    private static partial Regex TitleRegex();

    [GeneratedRegex(@"^(\d{4}-\d{2}-\d{2})")]
    private static partial Regex DateRegex();

    [GeneratedRegex(@"\*\*Severity:\*\*\s*(.+)$", RegexOptions.Multiline)]
    private static partial Regex SeverityRegex();
}
