from __future__ import annotations
from onegov.agency.observer import observes
from onegov.core.orm.mixins import dict_property
from onegov.core.orm.mixins import meta_property
from onegov.org.models.extensions import AccessExtension
from onegov.org.models.extensions import PublicationExtension
from onegov.org.utils import narrowest_access
from onegov.people import AgencyMembership
from sqlalchemy.orm import object_session
from sqlalchemy.orm.attributes import set_committed_value
from typing import TYPE_CHECKING
if TYPE_CHECKING:
    from datetime import datetime
    from onegov.agency.models import ExtendedAgency
    from onegov.agency.models import ExtendedPerson
    from sqlalchemy.orm import relationship
[docs]
class ExtendedAgencyMembership(AgencyMembership, AccessExtension,
                               PublicationExtension):
    """ An extended version of the standard membership from onegov.people. """
[docs]
    __mapper_args__ = {'polymorphic_identity': 'extended'} 
    @property
[docs]
    def fts_access(self) -> str:
        self._fetch_if_necessary()
        return narrowest_access(
            self.access,
            self.agency.meta.get('access', 'public'),
            self.person.meta.get('access', 'public'),
        ) 
    @property
[docs]
    def fts_publication_start(self) -> datetime | None:
        self._fetch_if_necessary()
        return max((dt for dt in (
            self.publication_start,
            self.agency.publication_start,
            self.person.publication_start
        ) if dt is not None), default=None) 
    @property
[docs]
    def fts_publication_end(self) -> datetime | None:
        self._fetch_if_necessary()
        return min((dt for dt in (
            self.publication_end,
            self.agency.publication_end,
            self.person.publication_end
        ) if dt is not None), default=None) 
[docs]
    def _fetch_if_necessary(self) -> None:
        session = object_session(self)
        if session is None:
            return
        if self.person_id is not None and self.person is None:
            # retrieve the person
            from onegov.agency.models import ExtendedPerson  # type: ignore[unreachable]
            set_committed_value(
                self,
                'person',
                session.query(ExtendedPerson).get(self.person_id)
            )
        if self.agency_id is not None and self.agency is None:
            # retrieve the agency
            from onegov.agency.models import ExtendedAgency  # type: ignore[unreachable]
            set_committed_value(
                self,
                'agency',
                session.query(ExtendedAgency).get(self.agency_id)
            ) 
    # Todo: It is very unclear how this should be used. In the PDF rendering,
    # it is placed a middle column with 0.5 cm after the title.
    # On the agency, it is placed after the membership title, so not a prefix
    # but rather a suffix and it looks. For 0.5cm, the form should validate the
    # length of this, otherwise people complain about weird pdf
    #: The prefix character.
[docs]
    prefix: dict_property[str | None] = meta_property() 
    #: A note to the membership.
[docs]
    note: dict_property[str | None] = meta_property() 
    #: An addition to the membership.
[docs]
    addition: dict_property[str | None] = meta_property() 
    if TYPE_CHECKING:
        # NOTE: We only relate extended versions
[docs]
        agency: relationship[ExtendedAgency] 
        person: relationship[ExtendedPerson]
    # force fts update when access/published of agency/person changes
    @observes(
        'agency.meta',
        'agency.publication_start',
        'agency.publication_end',
        'person.meta',
        'person.publication_start',
        'person.publication_end',
    )
[docs]
    def _force_fts_update(self, *_ignored: object) -> None:
        self.modified = self.modified