using System.Diagnostics;
using LiquidCode.Tester.Worker.Models;

namespace LiquidCode.Tester.Worker.Services;

public class CSharpCompilationService : ICompilationService
{
    private readonly ILogger<CSharpCompilationService> _logger;
    private readonly IConfiguration _configuration;

    public CSharpCompilationService(ILogger<CSharpCompilationService> logger, IConfiguration configuration)
    {
        _logger = logger;
        _configuration = configuration;
    }

    public async Task<CompilationResult> CompileAsync(string sourceCode, string workingDirectory, string? version = null)
    {
        var sourceFilePath = Path.Combine(workingDirectory, "Solution.cs");
        var executablePath = Path.Combine(workingDirectory, "solution.exe");

        _logger.LogInformation("Compiling C# code in {WorkingDirectory} with version {Version}", workingDirectory, version ?? "latest");

        try
        {
            await File.WriteAllTextAsync(sourceFilePath, sourceCode);

            // Resolve version-specific configuration
            var (compiler, compilerFlags) = ResolveVersion(version);

            _logger.LogDebug("Using compiler: {Compiler} with flags: {Flags}", compiler, compilerFlags);

            var arguments = $"{compilerFlags} /out:\"{executablePath}\" \"{sourceFilePath}\"";

            var process = new Process
            {
                StartInfo = new ProcessStartInfo
                {
                    FileName = compiler,
                    Arguments = arguments,
                    WorkingDirectory = workingDirectory,
                    RedirectStandardOutput = true,
                    RedirectStandardError = true,
                    UseShellExecute = false,
                    CreateNoWindow = true
                }
            };

            process.Start();

            var output = await process.StandardOutput.ReadToEndAsync();
            var error = await process.StandardError.ReadToEndAsync();

            await process.WaitForExitAsync();

            var compilerOutput = $"{output}\n{error}".Trim();

            if (process.ExitCode == 0 && File.Exists(executablePath))
            {
                _logger.LogInformation("C# compilation successful");
                return new CompilationResult
                {
                    Success = true,
                    ExecutablePath = executablePath,
                    CompilerOutput = compilerOutput
                };
            }
            else
            {
                _logger.LogWarning("C# compilation failed with exit code {ExitCode}", process.ExitCode);
                return new CompilationResult
                {
                    Success = false,
                    ErrorMessage = "Compilation failed",
                    CompilerOutput = compilerOutput
                };
            }
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error during C# compilation");
            return new CompilationResult
            {
                Success = false,
                ErrorMessage = $"Compilation error: {ex.Message}"
            };
        }
    }

    private (string compiler, string compilerFlags) ResolveVersion(string? version)
    {
        // If version is null or "latest", use default configuration
        if (string.IsNullOrEmpty(version) || version.Equals("latest", StringComparison.OrdinalIgnoreCase))
        {
            var compiler = _configuration["CSharp:Compiler"] ?? "csc";
            var compilerFlags = _configuration["CSharp:CompilerFlags"] ?? "/optimize+";
            return (compiler, compilerFlags);
        }

        // Try to find version-specific configuration
        var versionKey = $"CSharp:Versions:{version}";
        var versionCompiler = _configuration[$"{versionKey}:Compiler"];
        var versionFlags = _configuration[$"{versionKey}:CompilerFlags"];

        if (!string.IsNullOrEmpty(versionCompiler))
        {
            _logger.LogInformation("Using C# version {Version} configuration", version);
            return (versionCompiler, versionFlags ?? "/optimize+");
        }

        // Version not found, use default and log warning
        _logger.LogWarning("C# version {Version} not found in configuration, using default", version);
        var defaultCompiler = _configuration["CSharp:Compiler"] ?? "csc";
        var defaultFlags = _configuration["CSharp:CompilerFlags"] ?? "/optimize+";
        return (defaultCompiler, defaultFlags);
    }
}
