"""Custom widgets for the TactiTerm TUI with auto-completion engine and StdinInput."""
import asyncio
from typing import List, Dict
from textual import events
from textual.message import Message
from textual.widgets import TextArea, Input

# Comprehensive auto-completion syntax catalog per language for TUI
TUI_COMPLETIONS: Dict[str, List[str]] = {
    "python": [
        "int", "float", "bool", "str", "list", "dict", "set", "tuple", "bytes", "None",
        "True", "False", "print()", "len()", "range()", "enumerate()", "zip()", "map()",
        "filter()", "sorted()", "isinstance()", "type()", "open()", "input()", ".append()",
        ".split()", ".join()", ".get()", "def ", "class ", "return ", "import ", "from ",
        "if ", "elif ", "else:", "try:", "except ", "finally:", "raise ", "with ", "as ",
        "yield ", "async ", "await ", "lambda ", "pass", "break", "continue", "assert "
    ],
    "rust": [
        "bool", "i32", "i64", "u32", "u64", "usize", "f32", "f64", "char", "str", "String",
        "Vec", "Option", "Result", "Some", "None", "Ok", "Err", "println!()", "print!()",
        "format!()", "vec![]", "Vec::push()", "String::from()", "Option::unwrap()",
        "Result::expect()", ".iter()", ".collect()", "Box::new()", "fn ", "let ", "let mut ",
        "pub ", "struct ", "enum ", "impl ", "trait ", "match ", "if ", "else ", "loop ",
        "while ", "for ", "in ", "return ", "use std::", "async ", "await "
    ],
    "cpp": [
        "int", "float", "double", "bool", "char", "void", "size_t", "std::string",
        "std::vector<", "std::map<", "std::set<", "std::unique_ptr<", "std::shared_ptr<",
        "std::cout << ", "std::cin >> ", "std::endl", ".push_back()", "std::sort()",
        "std::make_unique<", "std::make_shared<", "class ", "struct ", "public:", "private:",
        "protected:", "virtual ", "override", "const ", "constexpr ", "auto ", "template<typename T>",
        "namespace ", "using namespace std;", "return ", "if ", "else ", "for ", "while "
    ],
    "go": [
        "int", "int64", "float64", "bool", "string", "byte", "rune", "error", "nil", "true",
        "false", "fmt.Println()", "fmt.Printf()", "fmt.Sprintf()", "make()", "append()",
        "len()", "cap()", "delete()", "strings.Split()", "os.Open()", "func ", "var ", "type ",
        "struct ", "interface ", "package main", "import ", "return ", "if ", "else ", "for ",
        "range ", "switch ", "select ", "chan ", "go func()"
    ],
    "javascript": [
        "number", "string", "boolean", "bool", "any", "void", "null", "undefined", "Array",
        "Object", "Promise", "console.log()", "console.error()", "console.warn()", ".map()",
        ".filter()", ".reduce()", ".find()", ".push()", ".includes()", "Object.keys()",
        "JSON.parse()", "fetch()", "const ", "let ", "var ", "function ", "class ", "return ",
        "if ", "else ", "for ", "while ", "switch ", "try ", "catch ", "async ", "await ", "new "
    ],
    "typescript": [
        "number", "string", "boolean", "bool", "any", "void", "unknown", "never", "null",
        "undefined", "Array<", "Record<", "Partial<", "Readonly<", "Pick<", "Omit<",
        "Promise<", "console.log()", ".map()", ".filter()", "interface ", "type ", "const ",
        "let ", "function ", "class ", "export ", "import ", "async ", "await "
    ],
    "java": [
        "int", "long", "double", "float", "boolean", "bool", "char", "byte", "short", "void",
        "String", "List<", "ArrayList<", "Map<", "HashMap<", "Set<", "HashSet<",
        "System.out.println()", ".add()", ".get()", ".size()", "public ", "private ",
        "protected ", "static ", "final ", "class ", "interface ", "extends ", "implements ",
        "new ", "return ", "if ", "else ", "for ", "while ", "try ", "catch "
    ],
    "csharp": [
        "int", "long", "double", "float", "bool", "char", "string", "object", "void", "var",
        "List<", "Dictionary<", "HashSet<", "Task<", "Console.WriteLine()", "Console.ReadLine()",
        ".Add()", "Enumerable.Where()", "public ", "private ", "protected ", "internal ",
        "static ", "class ", "struct ", "interface ", "record ", "namespace ", "using System;",
        "new ", "return ", "if ", "else ", "foreach ", "while ", "async ", "await "
    ],
    "lua": [
        "number", "int", "string", "boolean", "bool", "table", "nil", "function", "print()",
        "type()", "tostring()", "tonumber()", "table.insert()", "string.sub()", "local ",
        "if ", "then", "else", "elseif ", "end", "for ", "while ", "do", "return ", "require()"
    ],
    "html": [
        "<!DOCTYPE html>", "<html>", "<head>", "<title>", "<body>", "<h1>", "<h2>", "<h3>",
        "<p>", "<span>", "<div>", "<a href=\"\">", "<img src=\"\">", "<form>", "<input type=\"text\">",
        "<button>", "<select>", "<option>", "<ul>", "<ol>", "<li>", "<table>", "<tr>", "<td>", "<th>",
        "<script>", "<link rel=\"stylesheet\">"
    ],
}


class CodeEditor(TextArea):
    """A code editor with auto-completion dropdown trigger."""

    DEFAULT_CSS = """
    CodeEditor {
        height: 1fr;
        min-height: 8;
        border: solid $accent;
    }
    CodeEditor:focus {
        border: heavy $primary;
    }
    """

    def __init__(
        self,
        language: str = "python",
        theme: str = "vscode_dark",
        id: str | None = None,
        classes: str | None = None,
    ) -> None:
        super().__init__(
            language=language,
            theme=theme,
            soft_wrap=False,
            show_line_numbers=True,
            id=id,
            classes=classes,
        )

    def on_mount(self) -> None:
        self.tab_behavior = "indent"
        self.cursor_style = "bold blue"

    def get_code(self) -> str:
        return self.text

    def _on_key(self, event: events.Key) -> None:
        """Handle Tab completion and Ctrl+E toggle."""
        if event.key == "ctrl+e":
            event.prevent_default()
            event.stop()
            if hasattr(self.app, "action_toggle_expand_output"):
                self.app.action_toggle_expand_output()
            return

        if event.key == "tab":
            cursor_row, cursor_col = self.cursor_location
            lines = self.text.split("\n")
            if cursor_row < len(lines):
                current_line = lines[cursor_row][:cursor_col]
                words = current_line.replace("(", " ").replace(")", " ").split()
                if words:
                    prefix = words[-1].lower()
                    lang = (self.language or "python").lower()
                    candidates = TUI_COMPLETIONS.get(lang, TUI_COMPLETIONS["python"])
                    matches = [c for c in candidates if c.lower().startswith(prefix) or prefix in c.lower()]

                    if matches:
                        event.prevent_default()
                        event.stop()
                        if hasattr(self.app, "show_completion_popup"):
                            self.app.show_completion_popup(words[-1], matches)
                        return

        super()._on_key(event)


class StdinInput(Input):
    """Input control for stdin that forwards Ctrl+E to screen output toggler."""

    def _on_key(self, event: events.Key) -> None:
        if event.key == "ctrl+e":
            event.prevent_default()
            event.stop()
            if hasattr(self.app, "action_toggle_expand_output"):
                self.app.action_toggle_expand_output()
            return
        res = super()._on_key(event)
        if asyncio.iscoroutine(res):
            asyncio.create_task(res)


class MentorInputTextArea(TextArea):
    """Multi-line question input for Socratic Mentor. Submits on Enter, inserts newline on Shift+Enter."""

    class SubmitQuestion(Message):
        """Event posted when Enter is pressed."""

        def __init__(self, question: str) -> None:
            self.question = question
            super().__init__()

    def _on_key(self, event: events.Key) -> None:
        if event.key == "ctrl+e":
            event.prevent_default()
            event.stop()
            if hasattr(self.app, "action_toggle_expand_output"):
                self.app.action_toggle_expand_output()
            return
        elif event.key == "enter":
            event.prevent_default()
            event.stop()
            self.post_message(self.SubmitQuestion(self.text))
        elif event.key in ["shift+enter", "ctrl+j"]:
            self.insert("\n")
            event.prevent_default()
        else:
            super()._on_key(event)
