"""Kanban AI Management TUI - Main Application."""

import asyncio
from textual.app import App, ComposeResult
from textual.binding import Binding
from textual.widgets import Static, Footer, Input, Label, Button, RichLog
from textual.containers import Vertical, Horizontal, Container, VerticalScroll
from textual.screen import ModalScreen
from textual.reactive import reactive

from .models import ColumnId, AIStatus, Task, COLUMN_CONFIG
from .state import BoardState
from .widgets import KanbanBoard, TaskCard, KanbanColumn


class AddTaskModal(ModalScreen[tuple[str, str] | None]):
    """Modal for adding a new task."""

    DEFAULT_CSS = """
    AddTaskModal {
        align: center middle;
    }

    AddTaskModal > Container {
        width: 60;
        height: auto;
        max-height: 20;
        border: thick #61afef;
        background: #1a1a1a;
        padding: 1 2;
    }

    AddTaskModal .modal-title {
        text-align: center;
        text-style: bold;
        color: #61afef;
        padding-bottom: 1;
    }

    AddTaskModal Label {
        padding: 1 0 0 0;
        color: #888888;
    }

    AddTaskModal Input {
        margin: 0 0 1 0;
    }

    AddTaskModal .buttons {
        align: center middle;
        padding-top: 1;
    }

    AddTaskModal Button {
        margin: 0 1;
    }
    """

    BINDINGS = [
        Binding("escape", "cancel", "Cancel"),
    ]

    def compose(self) -> ComposeResult:
        with Container():
            yield Static("Add New Task", classes="modal-title")
            yield Label("Title:")
            yield Input(placeholder="Task title", id="title-input")
            yield Label("Description:")
            yield Input(placeholder="Task description (optional)", id="desc-input")
            with Horizontal(classes="buttons"):
                yield Button("Add", variant="primary", id="add-btn")
                yield Button("Cancel", id="cancel-btn")

    def on_mount(self) -> None:
        self.query_one("#title-input", Input).focus()

    def on_button_pressed(self, event: Button.Pressed) -> None:
        if event.button.id == "add-btn":
            self._submit()
        else:
            self.dismiss(None)

    def on_input_submitted(self, event: Input.Submitted) -> None:
        if event.input.id == "title-input":
            self.query_one("#desc-input", Input).focus()
        else:
            self._submit()

    def _submit(self) -> None:
        title = self.query_one("#title-input", Input).value.strip()
        if title:
            desc = self.query_one("#desc-input", Input).value.strip()
            self.dismiss((title, desc))
        else:
            self.query_one("#title-input", Input).focus()

    def action_cancel(self) -> None:
        self.dismiss(None)


class TaskDetailModal(ModalScreen[None]):
    """Modal for viewing task details."""

    DEFAULT_CSS = """
    TaskDetailModal {
        align: center middle;
    }

    TaskDetailModal > Container {
        width: 70;
        height: auto;
        max-height: 30;
        border: thick #61afef;
        background: #1a1a1a;
        padding: 1 2;
    }

    TaskDetailModal .modal-title {
        text-style: bold;
        color: #e8e8e8;
        padding-bottom: 1;
    }

    TaskDetailModal .section {
        padding: 1 0;
    }

    TaskDetailModal .section-header {
        color: #61afef;
        text-style: bold;
    }

    TaskDetailModal .detail-text {
        color: #888888;
        padding-left: 1;
    }

    TaskDetailModal .status-line {
        color: #98c379;
    }

    TaskDetailModal .activity-log {
        height: 8;
        border: solid #333333;
        background: #0d0d0d;
        padding: 0 1;
    }

    TaskDetailModal Button {
        margin-top: 1;
    }
    """

    BINDINGS = [
        Binding("escape", "close", "Close"),
        Binding("q", "close", "Close"),
    ]

    def __init__(self, task: Task, **kwargs) -> None:
        super().__init__(**kwargs)
        self._task = task

    def compose(self) -> ComposeResult:
        task = self._task
        with Container():
            yield Static(task.title, classes="modal-title")

            with Vertical(classes="section"):
                yield Static("Description:", classes="section-header")
                yield Static(task.description or "(no description)", classes="detail-text")

            with Vertical(classes="section"):
                yield Static("Status:", classes="section-header")
                col_config = COLUMN_CONFIG[task.column]
                status_text = f"{col_config['icon']} {col_config['title']} - {task.ai_status.value}"
                yield Static(status_text, classes="status-line")

            if task.plan:
                with Vertical(classes="section"):
                    yield Static("Plan:", classes="section-header")
                    plan_preview = task.plan[:200]
                    if len(task.plan) > 200:
                        plan_preview += "..."
                    yield Static(plan_preview, classes="detail-text")

            if task.files_modified:
                with Vertical(classes="section"):
                    yield Static(f"Files Modified ({len(task.files_modified)}):", classes="section-header")
                    for f in task.files_modified[:5]:
                        yield Static(f"  {f}", classes="detail-text")
                    if len(task.files_modified) > 5:
                        yield Static(f"  ... and {len(task.files_modified) - 5} more", classes="detail-text")

            if task.thinking_log:
                with Vertical(classes="section"):
                    yield Static("Recent Activity:", classes="section-header")
                    with VerticalScroll(classes="activity-log"):
                        for line in task.thinking_log[-10:]:
                            yield Static(line[:60], classes="detail-text")

            if task.error:
                with Vertical(classes="section"):
                    yield Static("Error:", classes="section-header")
                    yield Static(task.error, classes="detail-text")

            yield Button("Close", id="close-btn")

    def on_button_pressed(self, event: Button.Pressed) -> None:
        self.dismiss(None)

    def action_close(self) -> None:
        self.dismiss(None)


class DeleteConfirmModal(ModalScreen[bool]):
    """Modal for confirming task deletion."""

    DEFAULT_CSS = """
    DeleteConfirmModal {
        align: center middle;
    }

    DeleteConfirmModal > Container {
        width: 50;
        height: auto;
        border: thick #e06c75;
        background: #1a1a1a;
        padding: 1 2;
    }

    DeleteConfirmModal .modal-title {
        text-align: center;
        text-style: bold;
        color: #e06c75;
        padding-bottom: 1;
    }

    DeleteConfirmModal .confirm-text {
        text-align: center;
        color: #888888;
        padding: 1 0;
    }

    DeleteConfirmModal .buttons {
        align: center middle;
        padding-top: 1;
    }

    DeleteConfirmModal Button {
        margin: 0 1;
    }
    """

    BINDINGS = [
        Binding("escape", "cancel", "Cancel"),
    ]

    def __init__(self, task_title: str, **kwargs) -> None:
        super().__init__(**kwargs)
        self._task_title = task_title

    def compose(self) -> ComposeResult:
        with Container():
            yield Static("Delete Task", classes="modal-title")
            yield Static(f'Delete "{self._task_title}"?', classes="confirm-text")
            with Horizontal(classes="buttons"):
                yield Button("Delete", variant="error", id="delete-btn")
                yield Button("Cancel", id="cancel-btn")

    def on_mount(self) -> None:
        self.query_one("#cancel-btn", Button).focus()

    def on_button_pressed(self, event: Button.Pressed) -> None:
        self.dismiss(event.button.id == "delete-btn")

    def action_cancel(self) -> None:
        self.dismiss(False)


class HelpModal(ModalScreen[None]):
    """Modal showing keyboard shortcuts."""

    DEFAULT_CSS = """
    HelpModal {
        align: center middle;
    }

    HelpModal > Container {
        width: 50;
        height: auto;
        border: thick #61afef;
        background: #1a1a1a;
        padding: 1 2;
    }

    HelpModal .modal-title {
        text-align: center;
        text-style: bold;
        color: #61afef;
        padding-bottom: 1;
    }

    HelpModal .help-row {
        padding: 0;
    }

    HelpModal .key {
        color: #e5c07b;
        width: 12;
    }

    HelpModal .action {
        color: #888888;
    }

    HelpModal Button {
        margin-top: 1;
        align: center middle;
    }
    """

    BINDINGS = [
        Binding("escape", "close", "Close"),
        Binding("?", "close", "Close"),
    ]

    SHORTCUTS = [
        ("a", "Add new task"),
        ("Enter", "Start selected task"),
        ("v", "View task details"),
        ("d", "Delete task"),
        ("h / Left", "Previous column"),
        ("l / Right", "Next column"),
        ("j / Down", "Next task"),
        ("k / Up", "Previous task"),
        ("r", "Retry failed task"),
        ("c", "Cancel running task"),
        ("?", "Show this help"),
        ("q", "Quit"),
    ]

    def compose(self) -> ComposeResult:
        with Container():
            yield Static("Keyboard Shortcuts", classes="modal-title")
            for key, action in self.SHORTCUTS:
                with Horizontal(classes="help-row"):
                    yield Static(key, classes="key")
                    yield Static(action, classes="action")
            yield Button("Close", id="close-btn")

    def on_button_pressed(self, event: Button.Pressed) -> None:
        self.dismiss(None)

    def action_close(self) -> None:
        self.dismiss(None)


class KanbanApp(App):
    """Kanban AI Management TUI."""

    CSS = """
    Screen {
        background: #0d0d0d;
    }

    #header {
        dock: top;
        height: 1;
        background: #1a1a1a;
        color: #61afef;
        padding: 0 1;
    }

    #header-title {
        text-style: bold;
    }

    #header-help {
        dock: right;
        color: #666666;
    }

    #status-bar {
        dock: bottom;
        height: 1;
        background: #1a1a1a;
        color: #666666;
        padding: 0 1;
    }

    KanbanBoard {
        height: 1fr;
    }
    """

    BINDINGS = [
        Binding("a", "add_task", "Add Task"),
        Binding("enter", "start_task", "Start"),
        Binding("v", "view_task", "View"),
        Binding("d", "delete_task", "Delete"),
        Binding("h", "prev_column", "Prev Column", show=False),
        Binding("l", "next_column", "Next Column", show=False),
        Binding("left", "prev_column", "Prev Column", show=False),
        Binding("right", "next_column", "Next Column", show=False),
        Binding("j", "next_task", "Next Task", show=False),
        Binding("k", "prev_task", "Prev Task", show=False),
        Binding("down", "next_task", "Next Task", show=False),
        Binding("up", "prev_task", "Prev Task", show=False),
        Binding("r", "retry_task", "Retry", show=False),
        Binding("c", "cancel_task", "Cancel", show=False),
        Binding("question_mark", "show_help", "Help"),
        Binding("q", "quit", "Quit"),
        Binding("ctrl+c", "quit", "Quit", show=False),
    ]

    # Track current selection
    _current_column: reactive[int] = reactive(0)
    _current_task_idx: reactive[int] = reactive(0)
    _selected_task_id: reactive[str | None] = reactive(None)

    def __init__(self, on_execute=None, **kwargs):
        """Initialize the Kanban app.

        Args:
            on_execute: Async callback for task execution.
                       Signature: async def execute(task: Task) -> AsyncIterator[event]
        """
        super().__init__(**kwargs)
        self._state = BoardState()
        self._on_execute = on_execute
        self._running_tasks: dict[str, asyncio.Task] = {}

    def compose(self) -> ComposeResult:
        with Horizontal(id="header"):
            yield Static("EMDASH KANBAN", id="header-title")
            yield Static("[a]dd  [?]help  [q]uit", id="header-help")
        yield KanbanBoard(self._state, id="board")
        yield Static("", id="status-bar")

    def on_mount(self) -> None:
        """Initialize state and focus."""
        self._state.subscribe(self._on_state_change)
        self._update_status_bar()
        # Focus first task if exists
        self._focus_current_task()

    def _on_state_change(self, event_type: str, task: Task | None) -> None:
        """Handle state changes."""
        # Refresh the board
        board = self.query_one("#board", KanbanBoard)
        board.refresh_all()
        self._update_status_bar()

    def _update_status_bar(self) -> None:
        """Update the status bar."""
        try:
            status = self.query_one("#status-bar", Static)
            total = len(self._state.get_all_tasks())
            running = sum(
                1 for t in self._state.get_all_tasks()
                if t.ai_status in (AIStatus.PLANNING, AIStatus.IMPLEMENTING, AIStatus.REVIEWING)
            )
            done = len(self._state.get_tasks_by_column(ColumnId.DONE))

            parts = [f"Tasks: {total}"]
            if running > 0:
                parts.append(f"Running: {running}")
            if done > 0:
                parts.append(f"Done: {done}")

            if self._selected_task_id:
                task = self._state.get_task(self._selected_task_id)
                if task:
                    parts.append(f"Selected: {task.title[:30]}")

            status.update("  |  ".join(parts))
        except Exception:
            pass

    def _get_column_order(self) -> list[ColumnId]:
        """Get ordered list of columns."""
        return self._state.board.column_order

    def _focus_current_task(self) -> None:
        """Focus the task at current position."""
        columns = self._get_column_order()
        if not columns:
            return

        col_idx = self._current_column % len(columns)
        column_id = columns[col_idx]
        tasks = self._state.get_tasks_by_column(column_id)

        if not tasks:
            self._selected_task_id = None
            self._update_status_bar()
            return

        task_idx = self._current_task_idx % len(tasks)
        task = tasks[task_idx]
        self._selected_task_id = task.id

        # Focus the card widget
        try:
            card = self.query_one(f"#card-{task.id}", TaskCard)
            card.focus()
        except Exception:
            pass

        self._update_status_bar()

    def on_task_card_selected(self, event: TaskCard.Selected) -> None:
        """Handle card selection."""
        self._selected_task_id = event.task_id
        self._update_status_bar()

    # ─── Actions ───────────────────────────────────────────────────────

    async def action_add_task(self) -> None:
        """Open add task modal."""
        result = await self.push_screen_wait(AddTaskModal())
        if result:
            title, desc = result
            self._state.add_task(title, desc)
            # Move focus to the new task
            self._current_column = 0  # Backlog
            backlog_tasks = self._state.get_tasks_by_column(ColumnId.BACKLOG)
            self._current_task_idx = len(backlog_tasks) - 1
            # Need to remount to show new card
            board = self.query_one("#board", KanbanBoard)
            board.remove()
            self.mount(KanbanBoard(self._state, id="board"), after="#header")
            self._focus_current_task()

    async def action_view_task(self) -> None:
        """View task details."""
        if self._selected_task_id:
            task = self._state.get_task(self._selected_task_id)
            if task:
                await self.push_screen_wait(TaskDetailModal(task))

    async def action_delete_task(self) -> None:
        """Delete selected task."""
        if self._selected_task_id:
            task = self._state.get_task(self._selected_task_id)
            if task:
                confirmed = await self.push_screen_wait(DeleteConfirmModal(task.title))
                if confirmed:
                    # Cancel if running
                    if self._selected_task_id in self._running_tasks:
                        self._running_tasks[self._selected_task_id].cancel()
                        del self._running_tasks[self._selected_task_id]
                    self._state.delete_task(self._selected_task_id)
                    self._selected_task_id = None
                    # Remount board
                    board = self.query_one("#board", KanbanBoard)
                    board.remove()
                    self.mount(KanbanBoard(self._state, id="board"), after="#header")
                    self._focus_current_task()

    async def action_start_task(self) -> None:
        """Start selected task."""
        if not self._selected_task_id:
            return

        task = self._state.get_task(self._selected_task_id)
        if not task:
            return

        # Only start tasks in backlog
        if task.column == ColumnId.BACKLOG:
            # Move to planning
            self._state.update_task(
                task.id,
                column=ColumnId.PLANNING,
                ai_status=AIStatus.QUEUED
            )
            # Remount board
            board = self.query_one("#board", KanbanBoard)
            board.remove()
            self.mount(KanbanBoard(self._state, id="board"), after="#header")

            # Start execution if handler provided
            if self._on_execute:
                task = self._state.get_task(task.id)
                self._running_tasks[task.id] = asyncio.create_task(
                    self._execute_task(task)
                )

    async def _execute_task(self, task: Task) -> None:
        """Execute a task with the provided handler."""
        try:
            self._state.update_task(task.id, ai_status=AIStatus.PLANNING)

            async for event in self._on_execute(task):
                event_type = event.get("type", "")
                data = event.get("data", {})

                if event_type == "thinking":
                    content = data.get("content", "")
                    if content:
                        current_log = self._state.get_task(task.id).thinking_log
                        self._state.update_task(
                            task.id,
                            thinking_log=[*current_log[-20:], content[:100]]
                        )

                elif event_type == "tool_start":
                    tool_name = data.get("name", "")
                    args = data.get("args", {})
                    activity = self._format_activity(tool_name, args)
                    current_task = self._state.get_task(task.id)
                    self._state.update_task(
                        task.id,
                        current_activity=activity,
                        tools_used=current_task.tools_used + 1
                    )

                elif event_type == "tool_result":
                    if data.get("name") in ("edit", "write", "create_file"):
                        path = data.get("args", {}).get("path", "")
                        if path:
                            current_task = self._state.get_task(task.id)
                            files = current_task.files_modified
                            if path not in files:
                                self._state.update_task(
                                    task.id,
                                    files_modified=[*files, path]
                                )

                elif event_type == "plan_complete":
                    plan = data.get("plan", "")
                    self._state.update_task(
                        task.id,
                        plan=plan,
                        column=ColumnId.IN_PROGRESS,
                        ai_status=AIStatus.IMPLEMENTING
                    )

                elif event_type == "response":
                    summary = data.get("content", "")[:200]
                    self._state.update_task(
                        task.id,
                        column=ColumnId.DONE,
                        ai_status=AIStatus.COMPLETE,
                        summary=summary,
                        current_activity=""
                    )

                elif event_type == "error":
                    self._state.update_task(
                        task.id,
                        ai_status=AIStatus.FAILED,
                        error=data.get("message", "Unknown error"),
                        current_activity=""
                    )

                # Update board display
                self._refresh_board()

        except asyncio.CancelledError:
            self._state.update_task(
                task.id,
                ai_status=AIStatus.IDLE,
                current_activity=""
            )
        except Exception as e:
            self._state.update_task(
                task.id,
                ai_status=AIStatus.FAILED,
                error=str(e),
                current_activity=""
            )
        finally:
            if task.id in self._running_tasks:
                del self._running_tasks[task.id]
            self._refresh_board()

    def _format_activity(self, tool_name: str, args: dict) -> str:
        """Format tool activity for display."""
        if "path" in args:
            return f"{tool_name}: {args['path']}"
        elif "pattern" in args:
            return f"{tool_name}: {args['pattern']}"
        elif "query" in args:
            return f"{tool_name}: {args['query'][:30]}"
        elif "command" in args:
            return f"{tool_name}: {args['command'][:30]}"
        return tool_name

    def _refresh_board(self) -> None:
        """Refresh the board display."""
        try:
            board = self.query_one("#board", KanbanBoard)
            board.refresh_all()
        except Exception:
            pass

    def action_retry_task(self) -> None:
        """Retry a failed task."""
        if not self._selected_task_id:
            return
        task = self._state.get_task(self._selected_task_id)
        if task and task.ai_status == AIStatus.FAILED:
            self._state.update_task(
                task.id,
                column=ColumnId.BACKLOG,
                ai_status=AIStatus.IDLE,
                error=None,
                current_activity=""
            )
            self._refresh_board()

    def action_cancel_task(self) -> None:
        """Cancel a running task."""
        if not self._selected_task_id:
            return
        if self._selected_task_id in self._running_tasks:
            self._running_tasks[self._selected_task_id].cancel()

    # ─── Navigation ────────────────────────────────────────────────────

    def action_prev_column(self) -> None:
        """Move to previous column."""
        columns = self._get_column_order()
        self._current_column = (self._current_column - 1) % len(columns)
        self._current_task_idx = 0
        self._focus_current_task()

    def action_next_column(self) -> None:
        """Move to next column."""
        columns = self._get_column_order()
        self._current_column = (self._current_column + 1) % len(columns)
        self._current_task_idx = 0
        self._focus_current_task()

    def action_prev_task(self) -> None:
        """Move to previous task in column."""
        columns = self._get_column_order()
        column_id = columns[self._current_column % len(columns)]
        tasks = self._state.get_tasks_by_column(column_id)
        if tasks:
            self._current_task_idx = (self._current_task_idx - 1) % len(tasks)
            self._focus_current_task()

    def action_next_task(self) -> None:
        """Move to next task in column."""
        columns = self._get_column_order()
        column_id = columns[self._current_column % len(columns)]
        tasks = self._state.get_tasks_by_column(column_id)
        if tasks:
            self._current_task_idx = (self._current_task_idx + 1) % len(tasks)
            self._focus_current_task()

    async def action_show_help(self) -> None:
        """Show help modal."""
        await self.push_screen_wait(HelpModal())

    def action_quit(self) -> None:
        """Quit the application."""
        # Cancel all running tasks
        for task_future in self._running_tasks.values():
            task_future.cancel()
        self.exit()


def run_kanban(on_execute=None):
    """Run the Kanban TUI.

    Args:
        on_execute: Async callback for task execution.
                   Signature: async def execute(task: Task) -> AsyncIterator[event]
    """
    app = KanbanApp(on_execute=on_execute)
    app.run()


if __name__ == "__main__":
    # Demo mode
    async def demo_execute(task):
        """Demo executor that simulates AI work."""
        import asyncio

        yield {"type": "thinking", "data": {"content": f"Analyzing task: {task.title}"}}
        await asyncio.sleep(1)

        yield {"type": "tool_start", "data": {"name": "read_file", "args": {"path": "src/main.py"}}}
        await asyncio.sleep(0.5)
        yield {"type": "tool_result", "data": {"name": "read_file", "success": True}}

        yield {"type": "plan_complete", "data": {"plan": "1. Read files\n2. Make changes\n3. Test"}}
        await asyncio.sleep(1)

        yield {"type": "tool_start", "data": {"name": "edit_file", "args": {"path": "src/feature.py"}}}
        await asyncio.sleep(0.5)
        yield {"type": "tool_result", "data": {"name": "edit_file", "success": True, "args": {"path": "src/feature.py"}}}

        yield {"type": "response", "data": {"content": f"Completed: {task.title}\n\nMade the requested changes."}}

    run_kanban(on_execute=demo_execute)
