from dataclasses import dataclass

from reactivex import operators as ops, Observable

from clochette.application.store.ProviderStore import ProviderStore
from clochette.application.usecase.calendar.AddCalendarUseCase import AddCalendarUseCase
from clochette.application.usecase.calendar.UpdateCalendarUseCase import UpdateCalendarUseCase
from clochette.domain.entity.configuration.CalendarConfiguration import (
    CalendarConfiguration,
)
from clochette.domain.factory.CalendarConfigurationFactory import (
    CalendarConfigurationFactory,
)
from clochette.framework.qt.Link import LightLink
from clochette.framework.qt.QComponent import QComponent
from clochette.framework.rx.Scheduler import scheduler
from clochette.presentation.settings.calendar.CalendarNavigationModel import (
    CalendarNavigationModel,
)
from clochette.presentation.settings.calendar.CalendarSettingsModel import (
    CalendarSettingsModel,
)
from clochette.presentation.settings.calendar.dto.CalendarFormValuesDTO import CalendarFormValuesDTO
from clochette.presentation.settings.calendar.tabs.AuthenticationConfigurationModel import (
    AuthenticationConfigurationModel,
)
from clochette.presentation.settings.calendar.tabs.QCalendarConfigurationView import QCalendarConfigurationView
from clochette.provider.public.dto.PublicProviderType import PublicProviderType


@dataclass
class QCalendarConfigurationComponent(QComponent[QCalendarConfigurationView]):
    """Coordinator for calendar configuration that wires navigation and use cases"""

    _view: QCalendarConfigurationView
    _provider_store: ProviderStore
    _auth_model: AuthenticationConfigurationModel
    _settings_model: CalendarSettingsModel
    _navigation_model: CalendarNavigationModel
    _add_calendar_usecase: AddCalendarUseCase
    _update_calendar_usecase: UpdateCalendarUseCase
    _calendar_configuration_factory: CalendarConfigurationFactory

    def __post_init__(self):
        super().__init__(self._view)

        LightLink(
            observable=self._provider_store.providers,
            handler=self._view.set_providers,
            widget=self._view,
        )

        # Connect OK/Cancel buttons
        self._view.on_ok.link(self._save_calendar)
        self._view.on_cancel.link(lambda: self._navigation_model.show_calendar_list.on_next(True))

        LightLink(
            observable=self._navigation_model.add_calendar,
            handler=lambda _: self._on_add_calendar(),
            widget=self._view,
        )

        LightLink(
            observable=self._navigation_model.edit_calendar,
            handler=self._on_edit_calendar,
            widget=self._view,
        )

    def _on_add_calendar(self):
        """Handle add calendar navigation event"""
        self._clear()
        self._auth_model.edit_calendar = None
        self._settings_model.edit_calendar = None
        self._view.set_selected_provider_type(PublicProviderType())

    def _on_edit_calendar(self, calendar: CalendarConfiguration):
        """Handle edit calendar navigation event (authentication tab)"""
        self._clear()
        self._auth_model.edit_calendar = calendar
        self._settings_model.edit_calendar = calendar
        self._view.set_configuration(calendar)
        self._view.set_selected_provider_type(calendar.source.provider_type)

    def _clear(self):
        """Clear all form fields"""
        self._view.clear()

    def _save_calendar(self):
        """Save the calendar (add or update)"""

        def save_or_update(form_value: CalendarFormValuesDTO) -> Observable[None]:
            # Check if we're editing or adding
            existing_calendar = self._auth_model.edit_calendar or self._settings_model.edit_calendar

            if existing_calendar is not None:
                # Update existing calendar using factory
                calendar = self._calendar_configuration_factory.update_from_form_values(existing_calendar, form_value)
                return self._update_calendar_usecase.update_calendar(calendar, form_value.credentials)
            else:
                # Add new calendar using factory
                calendar = self._calendar_configuration_factory.create_from_form_values(form_value)
                return self._add_calendar_usecase.add_calendar(calendar, form_value.credentials)

        if self._view.validate():
            save_or_update(self._view.form_values).pipe(
                ops.do_action(on_next=lambda _: self._navigation_model.show_calendar_list.on_next(True)),
            ).subscribe(scheduler=scheduler)
