using LiquidCode.Tester.Worker.Services.Isolate;
using LiquidCode.Tester.Worker.Models;

namespace LiquidCode.Tester.Worker.Services;

/// <summary>
/// Python compilation service using Isolate sandbox for security
/// Python doesn't require compilation, but performs syntax validation in sandbox
/// </summary>
public class PythonCompilationServiceIsolate : ICompilationService
{
    private readonly ILogger<PythonCompilationServiceIsolate> _logger;
    private readonly IConfiguration _configuration;
    private readonly IsolateService _isolateService;
    private readonly IsolateBoxPool _boxPool;

    private const int ValidationTimeLimitSeconds = 10;
    private const int ValidationMemoryLimitMb = 256;

    public PythonCompilationServiceIsolate(
        ILogger<PythonCompilationServiceIsolate> logger,
        IConfiguration configuration,
        IsolateService isolateService,
        IsolateBoxPool boxPool)
    {
        _logger = logger;
        _configuration = configuration;
        _isolateService = isolateService;
        _boxPool = boxPool;
    }

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

        _logger.LogInformation("Preparing Python code with Isolate validation in {WorkingDirectory} with version {Version}",
            workingDirectory, version ?? "latest");

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

            // Optionally validate syntax in Isolate sandbox
            var validateSyntax = _configuration.GetValue<bool>("Python:ValidateSyntax", true);
            if (validateSyntax)
            {
                var validationResult = await ValidateSyntaxInIsolateAsync(sourceFilePath, version);
                if (!validationResult.Success)
                {
                    return validationResult;
                }
            }

            var executable = ResolveVersion(version);
            _logger.LogInformation("Python code prepared and validated successfully");

            return new CompilationResult
            {
                Success = true,
                ExecutablePath = sourceFilePath,
                CompilerOutput = $"Python code validated successfully (using {executable})"
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error preparing Python code");
            return new CompilationResult
            {
                Success = false,
                ErrorMessage = $"Error preparing code: {ex.Message}"
            };
        }
    }

    private async Task<CompilationResult> ValidateSyntaxInIsolateAsync(
        string sourceFilePath,
        string? version = null)
    {
        int boxId = -1;

        try
        {
            boxId = await _boxPool.AcquireBoxAsync();
            _logger.LogDebug("Acquired isolate box {BoxId} for Python syntax validation", boxId);

            await _isolateService.InitBoxAsync(boxId);

            var boxDir = $"/var/local/lib/isolate/{boxId}/box";
            var sourceFileName = Path.GetFileName(sourceFilePath);
            var boxSourcePath = Path.Combine(boxDir, sourceFileName);

            File.Copy(sourceFilePath, boxSourcePath, overwrite: true);

            var executable = ResolveVersion(version);
            _logger.LogDebug("Using Python executable: {Executable}", executable);

            var stderrFilePath = Path.Combine(boxDir, "validation_stderr.txt");

            // Validate syntax using: python3 -m py_compile solution.py
            var isolateResult = await _isolateService.RunAsync(new IsolateRunOptions
            {
                BoxId = boxId,
                Executable = $"/usr/bin/{executable}",
                Arguments = new[] { "-m", "py_compile", $"/box/{sourceFileName}" },
                TimeLimitSeconds = ValidationTimeLimitSeconds,
                WallTimeLimitSeconds = ValidationTimeLimitSeconds * 2,
                MemoryLimitKb = ValidationMemoryLimitMb * 1024,
                StackLimitKb = 64 * 1024,
                ProcessLimit = 1,
                EnableNetwork = false,
                StderrFile = stderrFilePath,
                WorkingDirectory = "/box",
                DirectoryBindings = new List<DirectoryBinding>
                {
                    new DirectoryBinding { HostPath = "/usr/lib", SandboxPath = "/usr/lib", ReadOnly = true },
                    new DirectoryBinding { HostPath = "/lib", SandboxPath = "/lib", ReadOnly = true }
                }
            });

            var validationOutput = string.Empty;
            if (File.Exists(stderrFilePath))
            {
                validationOutput = await File.ReadAllTextAsync(stderrFilePath);
            }
            if (!string.IsNullOrEmpty(isolateResult.ErrorOutput))
            {
                validationOutput = $"{validationOutput}\n{isolateResult.ErrorOutput}".Trim();
            }

            if (isolateResult.TimeLimitExceeded)
            {
                _logger.LogWarning("Python validation time limit exceeded for box {BoxId}", boxId);
                return new CompilationResult
                {
                    Success = false,
                    ErrorMessage = $"Validation timeout: exceeded {ValidationTimeLimitSeconds}s limit",
                    CompilerOutput = validationOutput
                };
            }

            if (isolateResult.MemoryLimitExceeded)
            {
                _logger.LogWarning("Python validation memory limit exceeded for box {BoxId}", boxId);
                return new CompilationResult
                {
                    Success = false,
                    ErrorMessage = $"Validation memory limit exceeded: {ValidationMemoryLimitMb}MB",
                    CompilerOutput = validationOutput
                };
            }

            if (isolateResult.ExitCode != 0)
            {
                _logger.LogWarning("Python syntax validation failed with exit code {ExitCode} in box {BoxId}",
                    isolateResult.ExitCode, boxId);
                return new CompilationResult
                {
                    Success = false,
                    ErrorMessage = "Python syntax error",
                    CompilerOutput = validationOutput
                };
            }

            _logger.LogDebug("Python syntax validation successful in Isolate box {BoxId}", boxId);
            return new CompilationResult
            {
                Success = true,
                CompilerOutput = "Syntax validation passed"
            };
        }
        catch (Exception ex)
        {
            _logger.LogError(ex, "Error during Python syntax validation");
            return new CompilationResult
            {
                Success = false,
                ErrorMessage = $"Validation error: {ex.Message}"
            };
        }
        finally
        {
            if (boxId >= 0)
            {
                try
                {
                    await _isolateService.CleanupBoxAsync(boxId);
                    _logger.LogDebug("Cleaned up isolate box {BoxId}", boxId);
                }
                catch (Exception ex)
                {
                    _logger.LogWarning(ex, "Failed to cleanup validation box {BoxId}", boxId);
                }

                _boxPool.ReleaseBox(boxId);
                _logger.LogDebug("Released validation box {BoxId} back to pool", boxId);
            }
        }
    }

    private string ResolveVersion(string? version)
    {
        if (string.IsNullOrEmpty(version) || version.Equals("latest", StringComparison.OrdinalIgnoreCase))
        {
            var executable = _configuration["Python:Executable"] ?? "python3";
            return executable;
        }

        var versionKey = $"Python:Versions:{version}";
        var versionExecutable = _configuration[$"{versionKey}:Executable"];

        if (!string.IsNullOrEmpty(versionExecutable))
        {
            _logger.LogInformation("Using Python version {Version} configuration", version);
            return versionExecutable;
        }

        _logger.LogWarning("Python version {Version} not found in configuration, using default", version);
        var defaultExecutable = _configuration["Python:Executable"] ?? "python3";
        return defaultExecutable;
    }
}
