import asyncio
import time
from typing import Optional

from .button import Button as button
from .markdown import Markdown as markdown
from .markdown import remove_indentation
from .mixins.content_element import ContentElement
from .timer import Timer as timer


class Code(ContentElement, component='code.js', default_classes='nicegui-code'):

    def __init__(self, content: str = '', *, language: Optional[str] = 'python') -> None:
        """Code

        This element displays a code block with syntax highlighting.

        In secure environments (HTTPS or localhost), a copy button is displayed to copy the code to the clipboard.

        :param content: code to display
        :param language: language of the code (default: "python")
        """
        super().__init__(content=remove_indentation(content))

        with self:
            self.markdown = markdown().classes('overflow-auto h-full') \
                .bind_content_from(self, 'content', lambda content: f'```{language}\n{content}\n```')
            self.copy_button = button(icon='content_copy', on_click=self.show_checkmark) \
                .props('round flat size=sm').classes('absolute right-2 top-2 opacity-20 hover:opacity-80') \
                .on('click', js_handler=f'() => navigator.clipboard.writeText(getElement("{self.id}").content)')

        self._props['content'] = self.content
        self._last_scroll: float = 0.0
        self.markdown.on('scroll', self._handle_scroll)
        with self:
            timer(0.1, self._update_copy_button)

    async def show_checkmark(self) -> None:
        """Show a checkmark icon for 3 seconds."""
        self.copy_button.props('icon=check')
        await asyncio.sleep(3.0)
        self.copy_button.props('icon=content_copy')

    def _handle_scroll(self) -> None:
        self._last_scroll = time.time()

    def _update_copy_button(self) -> None:
        self.copy_button.set_visibility(time.time() > self._last_scroll + 1.0)

    def _handle_content_change(self, content: str) -> None:
        self._props['content'] = content
