"""Search modal screen for OpenLibrary and Soulseek."""

from textual.app import ComposeResult
from textual.screen import ModalScreen
from textual.containers import Horizontal, Vertical
from textual.widgets import Static, Button, Input, Select, DataTable, TextArea
from textual.binding import Binding
from textual.message import Message
import logging
from typing import Optional, Any, List
from pathlib import Path
import sys
import asyncio

# Add parent directory to path for imports
sys.path.insert(0, str(Path(__file__).parent.parent))
from SYS.config import load_config, resolve_output_dir
from SYS.result_table import Table
from ProviderCore.registry import get_search_provider

logger = logging.getLogger(__name__)


class SearchModal(ModalScreen):
    """Modal screen for searching OpenLibrary and Soulseek."""

    BINDINGS = [
        Binding("escape",
                "cancel",
                "Cancel"),
        Binding("enter",
                "search_focused",
                "Search"),
        Binding("ctrl+t",
                "scrape_tags",
                "Scrape Tags"),
    ]

    CSS_PATH = "search.tcss"

    class SearchSelected(Message):
        """Posted when user selects a search result."""

        def __init__(self, result: dict) -> None:
            self.result = result
            super().__init__()

    def __init__(self, app_instance=None):
        """Initialize the search modal.

        Args:
            app_instance: Reference to the main App instance for worker creation
        """
        super().__init__()
        self.app_instance = app_instance
        self.source_select: Optional[Select] = None
        self.search_input: Optional[Input] = None
        self.results_table: Optional[DataTable] = None
        self.tags_textarea: Optional[TextArea] = None
        self.library_source_select: Optional[Select] = None
        self.current_results: List[Any] = []  # List of SearchResult objects
        self.current_result_table: Optional[Table] = None
        self.is_searching = False
        self.current_worker = None  # Track worker for search operations

    def compose(self) -> ComposeResult:
        """Create child widgets for the search modal."""
        with Vertical(id="search-container"):
            yield Static("Search Books & Music", id="search-title")

            with Horizontal(id="search-controls"):
                # Source selector
                self.source_select = Select(
                    [("OpenLibrary",
                      "openlibrary"),
                     ("Soulseek",
                      "soulseek")],
                    value="openlibrary",
                    id="source-select",
                )
                yield self.source_select

                # Search input
                self.search_input = Input(
                    placeholder="Enter search query...",
                    id="search-input"
                )
                yield self.search_input

                # Search button
                yield Button("Search", id="search-button", variant="primary")

            # Results table
            self.results_table = DataTable(id="results-table")
            yield self.results_table

            # Two-column layout: tags on left, source/submit on right
            with Horizontal(id="bottom-controls"):
                # Left column: Tags textarea
                with Vertical(id="tags-column"):
                    self.tags_textarea = TextArea(
                        text="",
                        id="result-tags-textarea",
                        read_only=False
                    )
                    self.tags_textarea.border_title = "Tags [Ctrl+T: Scrape]"
                    yield self.tags_textarea

                # Right column: Library source and submit button
                with Vertical(id="source-submit-column"):
                    # Library source selector (for OpenLibrary results)
                    self.library_source_select = Select(
                        [("Local",
                          "local"),
                         ("Download",
                          "download")],
                        value="local",
                        id="library-source-select",
                    )
                    yield self.library_source_select

                    # Submit button
                    yield Button("Submit", id="submit-button", variant="primary")

            # Buttons at bottom
            with Horizontal(id="search-buttons"):
                yield Button("Select", id="select-button", variant="primary")
                yield Button("Download", id="download-button", variant="primary")
                yield Button("Cancel", id="cancel-button", variant="default")

    def on_mount(self) -> None:
        """Set up the table columns and focus."""
        # Set up results table columns
        self.results_table.add_columns(
            "Title",
            "Author/Artist",
            "Year/Album",
            "Details"
        )

        # Focus on search input
        self.search_input.focus()

    async def _perform_search(self) -> None:
        """Perform the actual search based on selected source."""
        if not self.search_input or not self.source_select or not self.results_table:
            logger.error("[search-modal] Widgets not initialized")
            return

        query = self.search_input.value.strip()
        if not query:
            logger.warning("[search-modal] Empty search query")
            return

        source = self.source_select.value
        if not source or not isinstance(source, str):
            logger.warning("[search-modal] No source selected")
            return

        # Clear existing results
        self.results_table.clear(columns=True)
        self.current_results = []
        self.current_result_table = None

        self.is_searching = True

        # Create worker for tracking
        if self.app_instance and hasattr(self.app_instance, "create_worker"):
            self.current_worker = self.app_instance.create_worker(
                source,
                title=f"{source.capitalize()} Search: {query[:40]}",
                description=f"Searching {source} for: {query}",
            )
            self.current_worker.log_step(f"Connecting to {source}...")

        try:
            provider = get_search_provider(source)
            if not provider:
                logger.error(f"[search-modal] Provider not available: {source}")
                if self.current_worker:
                    self.current_worker.finish(
                        "error",
                        f"Provider not available: {source}"
                    )
                return

            logger.info(f"[search-modal] Searching {source} for: {query}")
            results = provider.search(query, limit=20)
            self.current_results = results

            if self.current_worker:
                self.current_worker.log_step(f"Found {len(results)} results")

            # Create ResultTable
            table = Table(f"Search Results: {query}")
            for res in results:
                row = table.add_row()
                # Add columns from result.columns
                if res.columns:
                    for name, value in res.columns:
                        row.add_column(name, value)
                else:
                    # Fallback if no columns defined
                    row.add_column("Title", res.title)
                    row.add_column(
                        "Target",
                        getattr(res,
                                "path",
                                None) or getattr(res,
                                                 "url",
                                                 None) or getattr(res,
                                                                  "target",
                                                                  None) or "",
                    )

            self.current_result_table = table

            # Populate UI
            if table.rows:
                # Add headers
                headers = [col.name for col in table.rows[0].columns]
                self.results_table.add_columns(*headers)
                # Add rows
                for row_vals in table.to_datatable_rows():
                    self.results_table.add_row(*row_vals)
            else:
                self.results_table.add_columns("Message")
                self.results_table.add_row("No results found")

            # Finish worker
            if self.current_worker:
                self.current_worker.finish("completed", f"Found {len(results)} results")

        except Exception as e:
            logger.error(f"[search-modal] Search error: {e}", exc_info=True)
            if self.current_worker:
                self.current_worker.finish("error", f"Search failed: {str(e)}")

        finally:
            self.is_searching = False

    def on_button_pressed(self, event: Button.Pressed) -> None:
        """Handle button presses."""
        button_id = event.button.id

        if button_id == "search-button":
            # Run search asynchronously
            asyncio.create_task(self._perform_search())

        elif button_id == "select-button":
            # Get selected row and populate tags textarea
            if self.results_table and self.results_table.row_count > 0:
                selected_row = self.results_table.cursor_row
                if 0 <= selected_row < len(self.current_results):
                    result = self.current_results[selected_row]
                    # Populate tags textarea with result metadata
                    self._populate_tags_from_result(result)
            else:
                logger.warning("[search-modal] No results to select")

        elif button_id == "download-button":
            # Download the selected result
            if self.current_results and self.results_table.row_count > 0:
                selected_row = self.results_table.cursor_row
                if 0 <= selected_row < len(self.current_results):
                    result = self.current_results[selected_row]
                    if getattr(result, "table", "") == "openlibrary":
                        asyncio.create_task(self._download_book(result))
                    else:
                        logger.warning(
                            "[search-modal] Download only supported for OpenLibrary results"
                        )
            else:
                logger.warning("[search-modal] No result selected for download")

        elif button_id == "submit-button":
            # Submit the current result with tags and source
            if self.current_results and self.results_table.row_count > 0:
                selected_row = self.results_table.cursor_row
                if 0 <= selected_row < len(self.current_results):
                    result = self.current_results[selected_row]

                    # Convert to dict if needed for submission
                    if hasattr(result, "to_dict"):
                        result_dict = result.to_dict()
                    else:
                        result_dict = result

                    # Get tags from textarea
                    tags_text = self.tags_textarea.text if self.tags_textarea else ""
                    # Get library source (if OpenLibrary)
                    library_source = (
                        self.library_source_select.value
                        if self.library_source_select else "local"
                    )

                    # Add tags and source to result
                    result_dict["tags_text"] = tags_text
                    result_dict["library_source"] = library_source

                    # Post message and dismiss
                    self.post_message(self.SearchSelected(result_dict))
                    self.dismiss(result_dict)
            else:
                logger.warning("[search-modal] No result selected for submission")

        elif button_id == "cancel-button":
            self.dismiss(None)

    def _populate_tags_from_result(self, result: Any) -> None:
        """Populate the tags textarea from a selected result."""
        if not self.tags_textarea:
            return

        # Handle both SearchResult objects and dicts
        if hasattr(result, "full_metadata"):
            metadata = result.full_metadata or {}
            source = result.table
            title = result.title
        else:
            # Handle dict (legacy or from to_dict)
            if "full_metadata" in result:
                metadata = result["full_metadata"] or {}
            elif "raw_data" in result:
                metadata = result["raw_data"] or {}
            else:
                metadata = result

            source = result.get("table", "")
            title = result.get("title", "")

        # Format tags based on result source
        if source == "openlibrary":
            # For OpenLibrary: title, author, year
            author = (
                ", ".join(metadata.get("authors",
                                       []))
                if isinstance(metadata.get("authors"),
                              list) else metadata.get("authors",
                                                      "")
            )
            year = str(metadata.get("year", ""))
            tags = []
            if title:
                tags.append(title)
            if author:
                tags.append(author)
            if year:
                tags.append(year)
            tags_text = "\n".join(tags)
        elif source == "soulseek":
            # For Soulseek: artist, album, title, track
            tags = []
            if metadata.get("artist"):
                tags.append(metadata["artist"])
            if metadata.get("album"):
                tags.append(metadata["album"])
            if metadata.get("track_num"):
                tags.append(f"Track {metadata['track_num']}")
            if title:
                tags.append(title)
            tags_text = "\n".join(tags)
        else:
            # Generic fallback
            tags = [title]
            tags_text = "\n".join(tags)

        self.tags_textarea.text = tags_text
        logger.info("[search-modal] Populated tags textarea from result")

    async def _download_book(self, result: Any) -> None:
        """Download a book from OpenLibrary using the provider."""
        if getattr(result, "table", "") != "openlibrary":
            logger.warning(
                "[search-modal] Download only supported for OpenLibrary results"
            )
            return

        try:
            config = load_config()
            output_dir = resolve_output_dir(config)

            provider = get_search_provider("openlibrary", config=config)
            if not provider:
                logger.error("[search-modal] Provider not available: openlibrary")
                return

            title = getattr(result, "title", "")
            logger.info(f"[search-modal] Starting download for: {title}")

            downloaded = await asyncio.to_thread(provider.download, result, output_dir)
            if downloaded:
                logger.info(f"[search-modal] Download successful: {downloaded}")
            else:
                logger.warning(f"[search-modal] Download failed for: {title}")

        except Exception as e:
            logger.error(f"[search-modal] Download error: {e}", exc_info=True)

    def action_search_focused(self) -> None:
        """Action for Enter key - only search if search input is focused."""
        if self.search_input and self.search_input.has_focus and not self.is_searching:
            asyncio.create_task(self._perform_search())

    def action_scrape_tags(self) -> None:
        """Action for Ctrl+T - populate tags from selected result."""
        if self.current_results and self.results_table and self.results_table.row_count > 0:
            try:
                selected_row = self.results_table.cursor_row
                if 0 <= selected_row < len(self.current_results):
                    result = self.current_results[selected_row]
                    self._populate_tags_from_result(result)
                    logger.info(
                        f"[search-modal] Ctrl+T: Populated tags from result at row {selected_row}"
                    )
                else:
                    logger.warning(
                        f"[search-modal] Ctrl+T: Invalid row index {selected_row}"
                    )
            except Exception as e:
                logger.error(f"[search-modal] Ctrl+T error: {e}")
        else:
            logger.warning("[search-modal] Ctrl+T: No results selected")

    def action_cancel(self) -> None:
        """Action for Escape key - close modal."""
        self.dismiss(None)

    def on_input_submitted(self, event: Input.Submitted) -> None:
        """Handle Enter key in search input - only trigger search here."""
        if event.input.id == "search-input":
            if not self.is_searching:
                asyncio.create_task(self._perform_search())
