using System.Text.RegularExpressions;

namespace AxCopilot.Services.Agent;

/// <summary>
/// Phase 17-G: 사용자 메시지에서 파일 참조를 감지하여 자동으로 컨텍스트에 추가.
/// @파일명 멘션, 경로 패턴, 확장자 기반 감지.
/// </summary>
public static class AutoContextCollector
{
    // Patterns to detect file references
    // 1. @mention: @filename.ext or @path/to/file
    // 2. explicit paths: C:\path\file.ext or /path/to/file.ext
    // 3. quoted filenames: "filename.ext" or 'filename.ext'
    // 4. code-like references: `filename.ext`

    private static readonly Regex AtMentionPattern = new(@"@([\w./\\-]+\.\w+)", RegexOptions.Compiled);
    private static readonly Regex AbsolutePathPattern = new(@"[A-Za-z]:\\[\w\\./\s-]+\.\w+|/[\w/.-]+\.\w+", RegexOptions.Compiled);
    private static readonly Regex QuotedFilePattern = new(@"""([\w./\\-]+\.\w{1,10})""|'([\w./\\-]+\.\w{1,10})'", RegexOptions.Compiled);
    private static readonly Regex BacktickFilePattern = new(@"`([\w./\\-]+\.\w{1,10})`", RegexOptions.Compiled);

    // Common code file extensions to match bare names
    private static readonly HashSet<string> CodeExtensions = new(StringComparer.OrdinalIgnoreCase)
    {
        ".cs", ".py", ".js", ".ts", ".tsx", ".jsx", ".java", ".cpp", ".c", ".h", ".go",
        ".rs", ".rb", ".php", ".swift", ".kt", ".scala", ".dart", ".vue", ".svelte",
        ".html", ".css", ".scss", ".json", ".xml", ".yaml", ".yml", ".toml", ".ini",
        ".md", ".txt", ".sql", ".sh", ".bat", ".ps1", ".dockerfile", ".gitignore"
    };

    /// <summary>
    /// 사용자 메시지에서 파일 참조를 추출합니다.
    /// </summary>
    /// <returns>감지된 파일 경로/이름 목록 (중복 제거)</returns>
    public static IReadOnlyList<string> ExtractFileReferences(string userMessage)
    {
        if (string.IsNullOrWhiteSpace(userMessage)) return new List<string>();

        var found = new HashSet<string>(StringComparer.OrdinalIgnoreCase);

        // @mention
        foreach (Match m in AtMentionPattern.Matches(userMessage))
            found.Add(m.Groups[1].Value.TrimStart('@'));

        // absolute paths
        foreach (Match m in AbsolutePathPattern.Matches(userMessage))
            found.Add(m.Value.Trim());

        // quoted filenames
        foreach (Match m in QuotedFilePattern.Matches(userMessage))
        {
            var val = m.Groups[1].Success ? m.Groups[1].Value : m.Groups[2].Value;
            if (!string.IsNullOrEmpty(val)) found.Add(val);
        }

        // backtick references
        foreach (Match m in BacktickFilePattern.Matches(userMessage))
            found.Add(m.Groups[1].Value);

        // filter: only keep entries with recognized extensions
        return found.Where(f => {
            var ext = System.IO.Path.GetExtension(f);
            return CodeExtensions.Contains(ext);
        }).ToList();
    }

    /// <summary>
    /// 파일 참조가 실제 파일로 존재하는지 확인하고, 존재하면 내용 로드.
    /// workFolder를 기준으로 상대 경로 해석.
    /// </summary>
    public static async Task<IReadOnlyList<(string Path, string Content)>> ResolveAndLoadAsync(
        IEnumerable<string> references, string workFolder, int maxFileSizeBytes = 32768)
    {
        var results = new List<(string, string)>();
        foreach (var reference in references)
        {
            try
            {
                // Try absolute first, then relative to workFolder
                var fullPath = System.IO.Path.IsPathRooted(reference)
                    ? reference
                    : System.IO.Path.Combine(workFolder, reference);

                if (!System.IO.File.Exists(fullPath)) continue;

                var info = new System.IO.FileInfo(fullPath);
                if (info.Length > maxFileSizeBytes) continue; // too large

                var content = await System.IO.File.ReadAllTextAsync(fullPath, System.Text.Encoding.UTF8);
                results.Add((fullPath, content));
            }
            catch (Exception) { }
        }
        return results;
    }

    /// <summary>
    /// 해결된 파일 내용을 시스템 프롬프트 주입용 텍스트로 빌드.
    /// </summary>
    public static string BuildContextInjection(IReadOnlyList<(string Path, string Content)> files)
    {
        if (files.Count == 0) return string.Empty;
        var sb = new System.Text.StringBuilder("## 참조된 파일 컨텍스트\n\n");
        foreach (var (path, content) in files)
        {
            var name = System.IO.Path.GetFileName(path);
            var ext = System.IO.Path.GetExtension(path).TrimStart('.').ToLowerInvariant();
            sb.AppendLine($"### `{name}`");
            sb.AppendLine($"```{ext}");
            // Truncate very large content
            if (content.Length > 8000)
                sb.AppendLine(content[..8000] + "\n... (이하 생략)");
            else
                sb.AppendLine(content);
            sb.AppendLine("```");
            sb.AppendLine();
        }
        return sb.ToString();
    }
}
