"""Service for executing user code safely across 10 programming languages with stdin support."""
import sys
import os
import tempfile
import subprocess
from typing import Dict, Any
from src.core.registry import registry


class CodeExecutor:
    """Executes code for all 10 supported programming languages with stdin support."""

    def run(self, language: str, code: str, stdin: str = "") -> Dict[str, Any]:
        config = registry.get_config(language)
        if not config:
            return {
                "language": language,
                "exit_code": 1,
                "stdout": "",
                "stderr": f"Language '{language}' is not supported.",
            }

        lang_key = registry.canonical_name(language)
        ext = config.get("ext", ".txt")

        with tempfile.TemporaryDirectory() as tmpdir:
            if lang_key == "java":
                temp_file_name = "Main.java"
            elif lang_key == "cpp":
                temp_file_name = "main.cpp"
            elif lang_key == "rust":
                temp_file_name = "main.rs"
            elif lang_key == "csharp":
                temp_file_name = "Program.cs"
            else:
                temp_file_name = f"main{ext}"

            temp_file_path = os.path.join(tmpdir, temp_file_name)
            with open(temp_file_path, "w", encoding="utf-8") as f:
                f.write(code)

            try:
                if lang_key == "python":
                    cmd = [sys.executable, temp_file_path]
                    result = subprocess.run(
                        cmd,
                        input=stdin,
                        capture_output=True,
                        text=True,
                        cwd=tmpdir,
                        timeout=15,
                    )
                elif lang_key == "html":
                    return {
                        "language": language,
                        "exit_code": 0,
                        "stdout": code,
                        "stderr": "",
                    }
                elif lang_key == "javascript":
                    result = subprocess.run(
                        ["node", temp_file_path],
                        input=stdin,
                        capture_output=True,
                        text=True,
                        cwd=tmpdir,
                        timeout=15,
                    )
                elif lang_key == "typescript":
                    result = subprocess.run(
                        ["npx", "ts-node", temp_file_path],
                        input=stdin,
                        capture_output=True,
                        text=True,
                        cwd=tmpdir,
                        timeout=15,
                    )
                elif lang_key == "go":
                    result = subprocess.run(
                        ["go", "run", temp_file_path],
                        input=stdin,
                        capture_output=True,
                        text=True,
                        cwd=tmpdir,
                        timeout=15,
                    )
                elif lang_key == "lua":
                    result = subprocess.run(
                        ["lua", temp_file_path],
                        input=stdin,
                        capture_output=True,
                        text=True,
                        cwd=tmpdir,
                        timeout=15,
                    )
                elif lang_key == "cpp":
                    compile_res = subprocess.run(
                        ["g++", "-O2", temp_file_path, "-o", "main"],
                        capture_output=True,
                        text=True,
                        cwd=tmpdir,
                        timeout=15,
                    )
                    if compile_res.returncode != 0:
                        return {
                            "language": language,
                            "exit_code": compile_res.returncode,
                            "stdout": compile_res.stdout,
                            "stderr": f"Compilation Error:\n{compile_res.stderr}",
                        }
                    result = subprocess.run(
                        ["./main"],
                        input=stdin,
                        capture_output=True,
                        text=True,
                        cwd=tmpdir,
                        timeout=15,
                    )
                elif lang_key == "rust":
                    compile_res = subprocess.run(
                        ["rustc", temp_file_path, "-o", "main"],
                        capture_output=True,
                        text=True,
                        cwd=tmpdir,
                        timeout=15,
                    )
                    if compile_res.returncode != 0:
                        return {
                            "language": language,
                            "exit_code": compile_res.returncode,
                            "stdout": compile_res.stdout,
                            "stderr": f"Rustc Compilation Error:\n{compile_res.stderr}",
                        }
                    result = subprocess.run(
                        ["./main"],
                        input=stdin,
                        capture_output=True,
                        text=True,
                        cwd=tmpdir,
                        timeout=15,
                    )
                elif lang_key == "java":
                    compile_res = subprocess.run(
                        ["javac", temp_file_path],
                        capture_output=True,
                        text=True,
                        cwd=tmpdir,
                        timeout=15,
                    )
                    if compile_res.returncode != 0:
                        return {
                            "language": language,
                            "exit_code": compile_res.returncode,
                            "stdout": compile_res.stdout,
                            "stderr": f"Javac Compilation Error:\n{compile_res.stderr}",
                        }
                    result = subprocess.run(
                        ["java", "Main"],
                        input=stdin,
                        capture_output=True,
                        text=True,
                        cwd=tmpdir,
                        timeout=15,
                    )
                elif lang_key == "csharp":
                    result = subprocess.run(
                        ["dotnet", "run"],
                        input=stdin,
                        capture_output=True,
                        text=True,
                        cwd=tmpdir,
                        timeout=15,
                    )
                else:
                    exec_cmd = config["exec"]
                    result = subprocess.run(
                        f"{exec_cmd} {temp_file_path}",
                        shell=True,
                        input=stdin,
                        capture_output=True,
                        text=True,
                        cwd=tmpdir,
                        timeout=15,
                    )

                return {
                    "language": language,
                    "exit_code": result.returncode,
                    "stdout": result.stdout,
                    "stderr": result.stderr,
                }
            except FileNotFoundError as fnf:
                return {
                    "language": language,
                    "exit_code": 127,
                    "stdout": "",
                    "stderr": f"Compiler/Interpreter binary not found for {language}: {fnf}",
                }
            except subprocess.TimeoutExpired:
                return {
                    "language": language,
                    "exit_code": 124,
                    "stdout": "",
                    "stderr": "Execution timed out (exceeded 15 seconds).",
                }
            except Exception as e:
                return {
                    "language": language,
                    "exit_code": 1,
                    "stdout": "",
                    "stderr": str(e),
                }


executor = CodeExecutor()
