using System.Diagnostics;
using System.IO;
using System.Runtime.InteropServices;
using System.Text;
using System.Text.RegularExpressions;

namespace AxCopilot.Services.Agent;

/// <summary>
/// Phase 19-D-EXT: 스킬 인라인 셸 커맨드 프로세서.
/// 스킬 본문에서 !`command` 패턴을 찾아 셸 실행 결과로 교체합니다.
/// CC 스킬의 인라인 셸 커맨드 기능과 동등합니다.
/// </summary>
public static class SkillInlineCommandProcessor
{
    // !`command` 패턴: ! 뒤에 백틱으로 감싼 명령
    private static readonly Regex InlineCmdPattern = new(@"!\`([^`]+)\`", RegexOptions.Compiled);

    /// <summary>
    /// 스킬 본문에서 !`command` 패턴을 찾아 셸 실행 결과로 교체합니다.
    /// 호출 시점: 스킬이 로드된 후, LLM 프롬프트로 전달하기 직전.
    /// </summary>
    /// <param name="skillBody">스킬 본문 텍스���</param>
    /// <param name="workFolder">셸 명령 실행 작업 디렉토리</param>
    /// <param name="ct">취소 토큰</param>
    /// <returns>인라인 명령이 출력으로 교체된 텍스트</returns>
    public static async Task<string> ProcessAsync(string skillBody, string workFolder, CancellationToken ct)
    {
        if (string.IsNullOrEmpty(skillBody)) return skillBody;

        var matches = InlineCmdPattern.Matches(skillBody);
        if (matches.Count == 0) return skillBody;

        // 뒤에서부터 교체하여 인덱스 보존
        var result = skillBody;
        foreach (Match match in matches.Cast<Match>().Reverse())
        {
            var command = match.Groups[1].Value;
            var output = await ExecuteCommandAsync(command, workFolder, ct);
            result = result.Remove(match.Index, match.Length).Insert(match.Index, output);
        }

        return result;
    }

    private static async Task<string> ExecuteCommandAsync(string command, string workFolder, CancellationToken ct)
    {
        try
        {
            using var cts = CancellationTokenSource.CreateLinkedTokenSource(ct);
            cts.CancelAfter(TimeSpan.FromSeconds(10));

            var isWindows = RuntimeInformation.IsOSPlatform(OSPlatform.Windows);
            var psi = new ProcessStartInfo
            {
                FileName = isWindows ? "cmd.exe" : "bash",
                Arguments = isWindows
                    ? $"/c {command}"
                    : $"-c \"{command.Replace("\"", "\\\"")}\"",
                WorkingDirectory = string.IsNullOrEmpty(workFolder) ? Directory.GetCurrentDirectory() : workFolder,
                UseShellExecute = false,
                RedirectStandardOutput = true,
                RedirectStandardError = true,
                CreateNoWindow = true,
                StandardOutputEncoding = Encoding.UTF8,
                StandardErrorEncoding = Encoding.UTF8,
            };

            using var proc = Process.Start(psi);
            if (proc == null) return "[실행 실패]";

            var stdout = await proc.StandardOutput.ReadToEndAsync(cts.Token);
            await proc.WaitForExitAsync(cts.Token);

            return stdout.TrimEnd();
        }
        catch (OperationCanceledException)
        {
            return "[타임아웃]";
        }
        catch (Exception ex)
        {
            return $"[오류: {ex.Message}]";
        }
    }
}
