import shutil

import pytest
from fasthtml.components import *
from fasthtml.xtend import Script

from myfasthtml.controls.TabsManager import TabsManager
from myfasthtml.core.instances import InstancesManager
from myfasthtml.test.matcher import matches, NoChildren
from .conftest import session


@pytest.fixture()
def tabs_manager(root_instance):
  shutil.rmtree(".myFastHtmlDb", ignore_errors=True)
  yield TabsManager(root_instance)
  
  InstancesManager.reset()
  shutil.rmtree(".myFastHtmlDb", ignore_errors=True)


class TestTabsManagerBehaviour:
  def test_tabs_manager_is_registered(self, session, tabs_manager):
    from_instance_manager = InstancesManager.get(session, tabs_manager.get_id())
    assert from_instance_manager == tabs_manager
  
  def test_i_can_add_tab(self, tabs_manager):
    tab_id = tabs_manager.add_tab("Tab1", Div("Content 1"))
    
    assert tab_id is not None
    assert tab_id in tabs_manager.get_state().tabs
    assert tabs_manager.get_state().tabs[tab_id]["label"] == "Tab1"
    assert tabs_manager.get_state().tabs[tab_id]["id"] == tab_id
    assert tabs_manager.get_state().tabs[tab_id]["component_type"] is None  # Div is not BaseInstance
    assert tabs_manager.get_state().tabs[tab_id]["component_id"] is None  # Div is not BaseInstance
    assert tabs_manager.get_state().tabs_order == [tab_id]
    assert tabs_manager.get_state().active_tab == tab_id
  
  def test_i_can_add_multiple_tabs(self, tabs_manager):
    tab_id1 = tabs_manager.add_tab("Users", Div("Content 1"))
    tab_id2 = tabs_manager.add_tab("User2", Div("Content 2"))
    
    assert len(tabs_manager.get_state().tabs) == 2
    assert tabs_manager.get_state().tabs_order == [tab_id1, tab_id2]
    assert tabs_manager.get_state().active_tab == tab_id2
  
  def test_i_can_show_tab(self, tabs_manager):
    tab_id1 = tabs_manager.add_tab("Tab1", Div("Content 1"))
    tab_id2 = tabs_manager.add_tab("Tab2", Div("Content 2"))
    
    assert tabs_manager.get_state().active_tab == tab_id2  # last crated tab is active
    
    tabs_manager.show_tab(tab_id1)
    assert tabs_manager.get_state().active_tab == tab_id1
  
  def test_i_can_close_tab(self, tabs_manager):
    tab_id1 = tabs_manager.add_tab("Tab1", Div("Content 1"))
    tab_id2 = tabs_manager.add_tab("Tab2", Div("Content 2"))
    tab_id3 = tabs_manager.add_tab("Tab3", Div("Content 3"))
    
    tabs_manager.close_tab(tab_id2)
    
    assert len(tabs_manager.get_state().tabs) == 2
    assert [tab_id for tab_id in tabs_manager.get_state().tabs] == [tab_id1, tab_id3]
    assert tabs_manager.get_state().tabs_order == [tab_id1, tab_id3]
    assert tabs_manager.get_state().active_tab == tab_id3  # last tab stays active
  
  def test_i_still_have_an_active_tab_after_close(self, tabs_manager):
    tab_id1 = tabs_manager.add_tab("Tab1", Div("Content 1"))
    tab_id2 = tabs_manager.add_tab("Tab2", Div("Content 2"))
    tab_id3 = tabs_manager.add_tab("Tab3", Div("Content 3"))
    
    tabs_manager.close_tab(tab_id3)  # close the currently active tab
    assert tabs_manager.get_state().active_tab == tab_id1  # default to the first tab


class TestTabsManagerRender:
  def test_i_can_render_when_no_tabs(self, tabs_manager):
    res = tabs_manager.render()
    
    expected = Div(
      Div(
        Div(id=f"{tabs_manager.get_id()}-controller"),
        Script(f'updateTabs("{tabs_manager.get_id()}-controller");'),
      ),
      Div(
        Div(NoChildren(), id=f"{tabs_manager.get_id()}-header"),
        id=f"{tabs_manager.get_id()}-header-wrapper"
      ),
      Div(
        Div(id=f"{tabs_manager.get_id()}-None-content"),
        id=f"{tabs_manager.get_id()}-content-wrapper"
      ),
      id=tabs_manager.get_id(),
    )
    
    assert matches(res, expected)
  
  def test_i_can_render_when_multiple_tabs(self, tabs_manager):
    tabs_manager.add_tab("Users1", Div("Content 1"))
    tabs_manager.add_tab("Users2", Div("Content 2"))
    tabs_manager.add_tab("Users3", Div("Content 3"))
    res = tabs_manager.render()
    
    expected = Div(
      Div(
        Div(id=f"{tabs_manager.get_id()}-controller"),
        Script(f'updateTabs("{tabs_manager.get_id()}-controller");'),
      ),
      Div(
        Div(
          Div(),  # tab_button
          Div(),  # tab_button
          Div(),  # tab_button
          id=f"{tabs_manager.get_id()}-header"
        ),
        id=f"{tabs_manager.get_id()}-header-wrapper"
      ),
      Div(
        Div("Content 3"), # active tab content
        # Lasy loading for the other contents
        id=f"{tabs_manager.get_id()}-content-wrapper"
      ),
      id=tabs_manager.get_id(),
    )
    assert matches(res, expected)
