from .browser.event import get_invitees
from .case import ICase
from .utils import guess_mimetype
from datetime import datetime
from logging import getLogger
from plone import api
from plone.app.contenttypes.indexers import SearchableText as SearchableText_base
from plone.app.contenttypes.interfaces import IDocument
from plone.app.contenttypes.interfaces import IEvent
from plone.app.contenttypes.interfaces import IFile
from plone.app.contenttypes.interfaces import IImage
from plone.app.contenttypes.interfaces import ILink
from plone.app.contenttypes.interfaces import INewsItem
from plone.base.interfaces import INonStructuralFolder
from plone.dexterity.interfaces import IDexterityContent
from plone.dexterity.utils import datify
from plone.event.interfaces import IEventAccessor
from plone.indexer.decorator import indexer
from ploneintranet.workspace.behaviors.subspace import ISubspace
from ploneintranet.workspace.interfaces import ITrashed
from ploneintranet.workspace.workspacefolder import IWorkspaceFolder
from Products.CMFCore.utils import getToolByName
from zope.component import getMultiAdapter
from zope.component.hooks import getSite
from zope.interface import Interface

logger = getLogger(__name__)


@indexer(IDocument)
def mimetype_document(obj, **kw):
    return obj.format


@indexer(IFile)
def mimetype_file(obj, **kw):
    if hasattr(obj, "file") and hasattr(obj.file, "filename"):
        mimetype = guess_mimetype(obj.file.filename)
        if mimetype.strip():
            return mimetype
    return "application/octet-stream"


@indexer(IImage)
def mimetype_image(obj, **kw):
    if hasattr(obj, "image") and hasattr(obj.image, "filename"):
        mimetype = guess_mimetype(obj.image.filename)
        if mimetype.strip():
            return mimetype
    return "application/octet-stream"


@indexer(ILink)
def mimetype_link(obj, **kw):
    return obj.content_type()


@indexer(INewsItem)
def mimetype_newsitem(obj, **kw):
    return "message/news"


@indexer(IDexterityContent)
def due_dexterity(obj):
    """
    dummy to prevent indexing child objects
    """
    raise AttributeError("This field should not indexed here!")


@indexer(ICase)
def due_case(obj):
    """
    :return: value of field due for cases
    """
    date = getattr(obj, "due", None)
    date = datify(date)
    return date is None and datetime.max or date


@indexer(IDexterityContent)
def is_division_dexterity(obj):
    """
    dummy to prevent indexing child objects
    """
    raise AttributeError("This field should not indexed here!")


@indexer(IWorkspaceFolder)
def is_division(obj, **kw):
    """Indexes if this object represents a division"""
    return getattr(obj, "is_division", False)


@indexer(IDexterityContent)
def is_archived_dexterity(obj):
    """Alias the outdated index from the slc.outdated package"""
    cat = getToolByName(getSite(), "portal_catalog")
    outdated = getMultiAdapter((obj, cat), name="outdated")
    return outdated()


@indexer(IWorkspaceFolder)
def is_archived_workspace(obj, **kw):
    """Indexes if this object is not archived

    Return False both when a workspace has no 'archival_date' attribute, and
    also when it is set to None.
    """
    return bool(getattr(obj, "archival_date"))


@indexer(IDexterityContent)
def division_dexterity(obj):
    """
    dummy to prevent indexing child objects
    """
    raise AttributeError("This field should not indexed here!")


@indexer(IWorkspaceFolder)
def division(obj, **kw):
    """Indexes the division UID if present

    Since this index is a UUIDIndex it needs to return either a UID or None
    """
    return getattr(obj, "division", None) or None


@indexer(IDexterityContent)
def superspace(obj):
    """Indexes the superspace UID if a relation is present"""
    if not ISubspace.providedBy(obj):
        raise AttributeError("This field should not indexed here!")
    if not obj.superspace:
        return ""
    try:
        return obj.superspace.to_object.UID()
    except BaseException:
        logger.exception("Broken superspace relation for %r", obj)
        return ""


@indexer(IEvent)
def invitees(obj, **kw):
    """Indexes the invitees as a list"""
    return [invitee.getId() for invitee in get_invitees(obj)]


@indexer(IEvent)
def whole_day(obj, **kw):
    """Indexes if this a whole day event"""
    return IEventAccessor(obj).whole_day


@indexer(IWorkspaceFolder)
def ws_type_workspace(obj, **kw):
    """Indexes the type of this workspace for marking"""
    return getattr(obj, "ws_type", "workspace")


@indexer(IEvent)
def ws_type_event(obj, **kw):
    """Indexes the type of this event based on the workspace it is contained in
    for marking in the calendar"""
    return getattr(obj, "ws_type", "workspace")


@indexer(IEvent)
def location(obj, **kw):
    """Indexes the location"""
    return IEventAccessor(obj).location


@indexer(IEvent)
def timezone(obj):
    if obj.start is None:
        return
    timezone = obj.start.tzinfo
    if timezone:
        return timezone.zone


@indexer(IEvent)
def shared_calendar(obj):
    """Indexes the shared calendar UID if a relation is present"""
    if not obj.shared_calendar:
        return ""
    try:
        return obj.shared_calendar.to_object.UID()
    except BaseException:
        logger.warning("Broken shared calendar relation for %r", obj)
        return ""


@indexer(IEvent)
def Description(obj):
    if obj.description:
        return obj.description
    else:
        info = obj.info
        if info:
            pt = api.portal.get_tool("portal_transforms")
            plain = pt.convertToData("text/plain", info.output)
            data = " ".join(plain.strip().split())
            return data


@indexer(Interface)
def trashed(obj):
    try:
        return ITrashed.providedBy(obj)
    except BaseException:
        return False


@indexer(INonStructuralFolder)
def SearchableText(obj):
    text = SearchableText_base(obj)
    for child in obj.objectValues():
        text = " ".join((text, SearchableText_base(child)))
    return text
