#!/usr/bin/env dotnet-script
#nullable enable

using System;
using System.IO;
using System.Diagnostics;
using System.Threading;
using System.Text;
using System.Text.RegularExpressions;
using System.Linq;
using System.Collections.Generic;

// ── Ctrl+C: kill active process and exit cleanly ──────────────────────────────
var cts = new CancellationTokenSource();
Process? activeProcess = null;

Console.CancelKeyPress += (_, e) =>
{
    e.Cancel = true;
    Console.WriteLine("\n[runner] Interrupted — shutting down...");
    cts.Cancel();
    try { activeProcess?.Kill(entireProcessTree: true); } catch { }
};

// ── Paths ─────────────────────────────────────────────────────────────────────
var repoRoot = Directory.GetCurrentDirectory();
var tasksFile = Path.Combine(repoRoot, "Docs", "Tasks.md");

if (!File.Exists(tasksFile))
{
    Console.Error.WriteLine($"[runner] ERROR: Tasks.md not found at {tasksFile}");
    Console.Error.WriteLine("[runner] Run this script from the repository root.");
    Environment.Exit(1);
}

// ── Read & split by "---" separator lines ────────────────────────────────────
var content = File.ReadAllText(tasksFile);
var items = Regex
    .Split(content, @"\r?\n---\r?\n")
    .Select(s => s.Trim())
    .Where(s => s.Length > 0)
    .ToList();

Console.WriteLine($"[runner] Found {items.Count} section(s) in Tasks.md");

// ── Helper: run copilot and stream output, return full output ─────────────────
async Task<string> RunCopilot(IEnumerable<string> extraArgs, string prompt)
{
    var output = new StringBuilder();

    var argList = new List<string> { "launch", "copilot", "--model", "minimax-m2.7:cloud", "--yes", "--", "--allow-all-tools" };
    argList.AddRange(extraArgs);
    argList.Add("-p");
    argList.Add(prompt);

    var psi = new ProcessStartInfo("ollama")
    {
        WorkingDirectory = repoRoot,
        RedirectStandardOutput = true,
        RedirectStandardError = true,
        UseShellExecute = false,
    };
    foreach (var a in argList)
        psi.ArgumentList.Add(a);

    activeProcess = new Process { StartInfo = psi };

    activeProcess.OutputDataReceived += (_, e) =>
    {
        if (e.Data is null) return;
        Console.WriteLine(e.Data);
        output.AppendLine(e.Data);
    };
    activeProcess.ErrorDataReceived += (_, e) =>
    {
        if (e.Data is null) return;
        Console.Error.WriteLine(e.Data);
        output.AppendLine(e.Data);
    };

    activeProcess.Start();
    activeProcess.BeginOutputReadLine();
    activeProcess.BeginErrorReadLine();

    await activeProcess.WaitForExitAsync(cts.Token);
    activeProcess = null;

    return output.ToString();
}

// ── Main loop ─────────────────────────────────────────────────────────────────
for (int i = 0; i < items.Count; i++)
{
    var item = items[i];
    if (cts.IsCancellationRequested) break;

    Console.WriteLine();
    Console.WriteLine("[runner] ══════════════════════════════════════════════");
    Console.WriteLine($"[runner] Task:\n{item}");
    Console.WriteLine("[runner] ══════════════════════════════════════════════");
    Console.WriteLine();

    // Step 1 — run the task prompt
    await RunCopilot(Enumerable.Empty<string>(), $"/caveman full");
    await RunCopilot(new[] { "--continue" }, $"read ./Docs/Instructions.md. fix the following test and only that one. Keep in mind that i did many refactorings and test may is obsolet or need to be changed. {item}");
    if (cts.IsCancellationRequested) break;

    // Step 2 — confirm completion in the same chat session
    Console.WriteLine("\n[runner] Asking for task confirmation...\n");
    var confirmation = await RunCopilot(
        new[] { "--continue" },
        "are you sure tasks is done. reply with yes"
    );
    if (cts.IsCancellationRequested) break;

    // Step 3 — check for "yes" in the reply, with retry logic for issue resolution
    int maxRetries = 3;
    int retryCount = 0;
    bool taskConfirmed = confirmation.Contains("yes", StringComparison.OrdinalIgnoreCase);

    while (!taskConfirmed && retryCount < maxRetries)
    {
        retryCount++;
        Console.WriteLine($"\n[runner] Attempt {retryCount}/{maxRetries}: Resolving remaining issues and running tests...\n");
        
        confirmation = await RunCopilot(
            new[] { "--continue" },
            "resolve any remaining issues, make sure all tests are running and pass. then confirm with yes if done"
        );
        if (cts.IsCancellationRequested) break;
        
        taskConfirmed = confirmation.Contains("yes", StringComparison.OrdinalIgnoreCase);
    }

    if (!taskConfirmed)
    {
        Console.WriteLine($"\n[runner] Task not confirmed as done after {maxRetries} attempts. Stopping.");
        break;
    }

    // Step 4 — commit the work
    Console.WriteLine("\n[runner] Task confirmed. Making git commit...\n");

    await RunCopilot(Enumerable.Empty<string>(), $"/caveman full");
    await RunCopilot(new[] { "--continue" }, "make git commit");
    if (cts.IsCancellationRequested) break;

    // Step 5 — remove completed task from Tasks.md
    var remaining = items.Skip(i + 1).ToList();
    File.WriteAllText(tasksFile, string.Join("\n\n---\n\n", remaining));
    Console.WriteLine("[runner] Removed completed task from Tasks.md");
}

Console.WriteLine("\n[runner] Finished.");
