from copy import deepcopy
from plone.app.iterate.interfaces import IWorkingCopy
from plone.dexterity import content
from plone.supermodel import model
from plone.uuid.interfaces import IUUID
from ploneintranet.core import _
from ploneintranet.layout.app import AbstractAppContainer
from ploneintranet.layout.app import App
from ploneintranet.layout.app import IApp
from ploneintranet.layout.interfaces import IAppContainer
from ploneintranet.news.browser.interfaces import INewsContentLayer
from ploneintranet.news.browser.interfaces import INewsLayer
from ploneintranet.search.interfaces import ISiteSearch
from ploneintranet.search.solr.solr_search import SiteSearch
from typing import Any
from zope import schema
from zope.component import getUtility
from zope.deferredimport import deprecated
from zope.interface import Attribute
from zope.interface import implementer
from zope.schema.vocabulary import SimpleTerm
from zope.schema.vocabulary import SimpleVocabulary

import logging

log = logging.getLogger(__name__)

NEWS_SECTION_TYPES = ["ploneintranet.news.section", "ploneintranet.news.syndication"]


deprecated(
    "This stuff has gone forever, you might want to clean the DB",
    INewsSectionContainer="ploneintranet.patches.missing_interfaces:INewsSectionContainer",  # noqa: E501
)


class INewsApp(IApp, IAppContainer):
    """Toplevel News singleton to contain all news content (IAppContainer)
    that also provides an IApp tile in the apps listing.
    """


class INewsSection(model.Schema):
    """News Sections can contain News Items"""

    uuid = Attribute("Stable unique id")

    navigation = schema.Choice(
        title=_("navigation", default="Navigation"),
        vocabulary=SimpleVocabulary(
            [
                SimpleTerm(value="main", title=_("Main")),
                SimpleTerm(value="other", title=_("Other")),
                SimpleTerm(value="exclude", title=_("Exclude")),
            ]
        ),
        default="exclude",
    )

    nav_visible_group_list = schema.Set(
        title="A list of groups which see this section in the main navigation",
        required=False,
        defaultFactory=set,
    )

    description_visible = schema.Bool(
        title="Show section description",
        description=_(
            "description_description_visible",
            "Show the section description on the section page",
        ),
        required=False,
        default=True,
    )

    show_descriptions = schema.Bool(
        title="Show Article Descriptions", required=False, default=True
    )
    show_images = schema.Bool(title="Show article images", required=False, default=True)
    grid = schema.TextLine(title="Grid", default="3")
    color = schema.TextLine(title="Color")


@implementer(INewsApp, IAppContainer)
class NewsApp(AbstractAppContainer, content.Container, App):

    # IAppContainer
    app_name = "news"
    app_layers = (INewsLayer, INewsContentLayer)

    # IApp
    app = "publisher"  # bloody awkward API in ploneintranet.layout
    css_class = "news"
    devices = "desktop tablet"

    def sections(self):
        contentFilter = dict(portal_type=NEWS_SECTION_TYPES)
        return self.listFolderContents(contentFilter=contentFilter)

    def news_items(
        self,
        section=None,
        start: int | None = None,
        limit: int | None = None,
        pinned: bool = False,
        sort: list | None = None,
        **query: dict[str, Any],
    ):
        """This is the method used to consistently query the news items
        throughout the news app.

        It uses solr to do the querying, and ensures that no working copies
        are returned (unless you explicitly override this in the query).

        Default sorting is by effective date descending, with pinned items
        first when the pinned argument is True.
        """
        query = deepcopy(query) if query else {}
        query["portal_type"] = "News Item"

        if section and not query.get("path"):
            query["path"] = "/".join(section.getPhysicalPath())

        if "-object_provides" not in query:
            query["-object_provides"] = [IWorkingCopy.__identifier__]

        if sort is None:
            sort = ["-effective"]

        if pinned:
            if "-pinned" not in sort:
                sort = ["-pinned"] + sort

        search_util: SiteSearch = getUtility(ISiteSearch)
        return search_util.query(
            filters=query,
            start=start,
            step=limit,
            sort=sort,
        )


@implementer(INewsSection)
class NewsSection(content.Container):
    @property
    def uuid(self):
        return IUUID(self)
