"""
Created on 2024-01-03

@author: wf
"""
import asyncio
from nicegui import ui
from wd.wdsearch import WikidataSearch
from ngwidgets.webserver import NiceGuiWebserver
from ngwidgets.widgets import Lang,Link
from ngwidgets.lod_grid import ListOfDictsGrid

class WikidataItemSearch():
    """
    wikidata item search 
    """
    
    def __init__(self,webserver:NiceGuiWebserver):
        """
        Initialize the WikidataItemSearch with the given webserver.

        Args:
            webserver (NiceGuiWebserver): The webserver to attach the search UI.
        """
        self.webserver=webserver
        self.lang="en"
        self.limit=9
        self.wd_search=WikidataSearch(self.lang)
        self.search_debounce_task = None
        self.keyStrokeTime=0.65 # minimum time in seconds to wait between keystrokes before starting searching
        self.languages = Lang.get_language_dict()
        self.search_result_row=None
        self.setup()
        
    def setup(self):
        """
        setup the user interface
        """
        with ui.card().style('width: 25%'):
            with ui.grid(rows=1,columns=4):
                ui.label("lang:")
                # Create a dropdown for language selection with the default language selected
                # Bind the label text to the selection's value, so it updates automatically
                ui.select(self.languages,with_input=True, value=self.lang).bind_value(self, 'lang')
                ui.label("limit:")
                self.limit_slider = ui.slider(min=2, max=50, value=self.limit).props('label-always').bind_value(self, 'limit')
            with ui.row():
                self.search_input=ui.input(label='search',on_change=self.on_search_change).props("size=80")
        with ui.row() as self.search_result_row:         
            self.search_result_grid=ListOfDictsGrid()
          
    async def on_search_change(self,_args):
        """
        react on changes in the search input
        """
        # Cancel the existing search task if it's still waiting
        if self.search_debounce_task:
            self.search_debounce_task.cancel()

        # Create a new task for the new search
        self.search_debounce_task = asyncio.create_task(self.debounced_search())
       
    async def debounced_search(self):
        """
        Waits for a period of inactivity and then performs the search.
        """
        try:
            # Wait for the debounce period (keyStrokeTime)
            await asyncio.sleep(self.keyStrokeTime)
            search_for=self.search_input.value
            if self.search_result_row:
                with self.search_result_row:
                    ui.notify(f"searching wikidata for {search_for} ({self.lang})...")
                    self.wd_search.language=self.lang
                    wd_search_result=self.wd_search.searchOptions(search_for,limit=self.limit)
                    view_lod=self.get_selection_view_lod(wd_search_result)
                    self.search_result_grid.load_lod(view_lod)
                    self.search_result_grid.set_checkbox_selection("#")
                    self.search_result_grid.update()
        except asyncio.CancelledError:
            # The search was cancelled because of new input, so just quietly exit
            pass
        except BaseException as ex:
            self.webserver.handle_exception(ex,self.webserver)
 

    def get_selection_view_lod(self,wd_search_result:list)->dict:
        """
        Convert the Wikidata search result list of dict to a selection.

        Args:
            wd_search_result (List[Dict[str, Any]]): The search results from Wikidata.

        Returns:
            List[Dict[str, Any]]: The list of dictionaries formatted for view.
        """
        view_lod=[]
        for qid,itemLabel,desc in wd_search_result:
            url=f"https://www.wikidata.org/wiki/{qid}"
            link=Link.create(url,qid)
            row={
                "#":len(view_lod)+1,
                "qid": link,
                "label": itemLabel,
                "desc": desc
            }
            view_lod.append(row)
        return view_lod
