# -*- coding: utf-8 -*-

from datetime import datetime

from pyramid.threadlocal import get_current_registry

from pytz import timezone

from sqlalchemy import orm
from sqlalchemy.orm.collections import attribute_mapped_collection
from sqlalchemy import sql
from sqlalchemy import event

from .model import Content
from .model import ContentTranslation
from amnesia.modules.account import Account
from ..state import State
from ..content_type import ContentType
from ..tag import Tag
from ..folder import Folder
from amnesia.modules.language import Language


@event.listens_for(Content, 'before_update', propagate=True)
def updated_listener(mapper, connection, target):
    registry = get_current_registry()
    tz = registry.settings.get('timezone', 'UTC')
    target.updated = datetime.now(timezone(tz))


PGSQL_FTS_WEIGHTS = frozenset(('a', 'b', 'c', 'd'))
PGSQL_FTS_DEFAULT_WEIGHT = 'd'


@event.listens_for(Content, 'before_update', propagate=True)
@event.listens_for(Content, 'before_insert', propagate=True)
def update_fts_listener(mapper, connection, target):
    """ Set the 'fts' column (full text search) """

    fts = None

    if target.is_fts:
        # Check which columns should be indexed
        for i in getattr(target.__class__, '_FTS_', ()):
            (field, weight) = i

            if weight.lower() not in PGSQL_FTS_WEIGHTS:
                weight = PGSQL_FTS_DEFAULT_WEIGHT

            _fts = sql.func.coalesce(getattr(target, field, ''), '')
            _fts = sql.func.to_tsvector(_fts)
            _fts = sql.func.setweight(_fts, weight)

            fts = _fts if fts is None else fts.op('||')(_fts)

    target.fts = fts


def includeme(config):
    tables = config.registry['metadata'].tables

    config.include('amnesia.modules.account.mapper')
    config.include('amnesia.modules.state.mapper')
    config.include('amnesia.modules.content_type.mapper')
    config.include('amnesia.modules.tag.mapper')
    config.include('amnesia.modules.language.mapper')

    _count_alias = tables['content'].alias('_count_children')

    orm.mapper(
        ContentTranslation, tables['content_translation'],
        polymorphic_on=tables['content_translation'].c.content_type_id,
        properties={
            'language': orm.relationship(
                Language,
                lazy='joined',
                innerjoin=True
            ),

            'content': orm.relationship(
                Content,
                innerjoin=True,
                back_populates='translations'
            ),

            'type': orm.relationship(
                ContentType,
                lazy='joined',
                innerjoin=True,
                viewonly=True
            ),

            #'content_type_id': orm.column_property(
            #    sql.select(
            #        [tables['content'].c.content_type_id]
            #    ).where(
            #        tables['content_translation'].c.content_id ==
            #        tables['content'].c.id
            #    ), deferred=True
            #)
        }
    )

    orm.mapper(
        Content, tables['content'],
        polymorphic_on=tables['content'].c.content_type_id,
        properties={

            #################
            # RELATIONSHIPS #
            #################

            'owner': orm.relationship(
                Account,
                lazy='joined',
                innerjoin=True,
                backref=orm.backref('contents', lazy='dynamic',
                                    cascade='all, delete-orphan')
            ),

            'state': orm.relationship(
                State,
                lazy='joined',
                innerjoin=True
            ),

            'type': orm.relationship(
                ContentType,
                lazy='joined',
                innerjoin=True
            ),

            'tags': orm.relationship(
                Tag,
                secondary=tables['content_tag'],
                back_populates='contents'
            ),

            'parent': orm.relationship(
                Folder,
                foreign_keys=tables['content'].c.container_id,
                innerjoin=True,
                uselist=False,
                backref=orm.backref('children', cascade='all, delete-orphan')
            ),

            'translations': orm.relationship(
                ContentTranslation,
                back_populates='content',
                cascade='all, delete-orphan',
                lazy='subquery',
                collection_class=attribute_mapped_collection('language_id')
            ),

            #####################
            # COLUMN PROPERTIES #
            #####################

            'position_in_container': orm.column_property(
                sql.func.row_number().
                over(partition_by=tables['content'].c.container_id,
                     order_by=tables['content'].c.weight.desc()),
                deferred=True,
                group='window_func'
            ),

            # FIXME: move to folder mapper with a LATERAL expression
            'count_children': orm.column_property(
                sql.select([sql.func.count()]).where(
                    _count_alias.c.container_id == tables['content'].c.id
                ).correlate(tables['content']).label('count_children'),
                deferred=True
            ),

        })

@@ -106,35 +106,143 @@
 try%0A
-%0Afrom pytz import timezone%0A
+from pyramid.threadlocal import get_current_request%0A%0Afrom pytz import timezone%0A%0Afrom sqlalchemy import event%0Afrom sqlalchemy import sql
 %0Afro
@@ -351,43 +351,22 @@
 hemy
- import sql%0Afrom sqlalchemy
+.types
  import 
 even
@@ -361,21 +361,22 @@
  import 
-event
+String
 %0A%0Afrom .
@@ -2430,32 +2430,63 @@
   innerjoin=True
+,%0A                uselist=False
 %0A            ),%0A
@@ -2576,32 +2576,63 @@
 innerjoin=True,%0A
+                uselist=False,%0A
                 
@@ -2840,351 +2840,54 @@
 True
-%0A            ),%0A%0A            #'content_type_id': orm.column_property(%0A            #    sql.select(%0A            #        %5Btables%5B'content'%5D.c.content_type_id%5D%0A            #    ).where(%0A            #        tables%5B'content_translation'%5D.c.content_id ==%0A            #        tables%5B'content'%5D.c.id%0A            #    ), deferred=True%0A            #)
+,%0A                uselist=False%0A            ),
 %0A   
@@ -4125,32 +4125,747 @@
             ),%0A%0A
+            # pylint: disable=no-member%0A            'current_translation': orm.relationship(%0A                ContentTranslation,%0A                primaryjoin=lambda: sql.and_(%0A                    ContentTranslation.content_id == Content.id,%0A                    ContentTranslation.language_id == sql.bindparam(%0A                        None,%0A                        callable_=lambda: get_current_request().locale_name,%0A                        type_=String()%0A                    )%0A                ),%0A                lazy='joined',%0A                uselist=False,%0A                innerjoin=True,%0A                viewonly=True,%0A                bake_queries=False,%0A                #back_populates='content'%0A            ),%0A%0A
             'tra
@@ -5030,24 +5030,25 @@
             
+#
 lazy='subque
@@ -5052,16 +5052,48 @@
 query',%0A
+                innerjoin=True,%0A
         

add current_translation