# -*- coding: UTF-8 -*-
# vim: fdm=marker
__revision__ = '$Id$'
# XXX: database format version, remember to increase after changing data
# structures
__version__ = 6

# Copyright © 2009 Piotr Ożarowski
#
# This program is free software; you can redistribute it and/or modify
# it under the terms of the GNU General Public License as published by
# the Free Software Foundation; either version 2 of the License, or
# (at your option) any later version.
#
# This program is distributed in the hope that it will be useful,
# but WITHOUT ANY WARRANTY; without even the implied warranty of
# MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE.  See the
# GNU Library General Public License for more details.
#
# You should have received a copy of the GNU General Public License
# along with this program; if not, write to the Free Software
# 51 Franklin Street, Fifth Floor, Boston, MA  02110-1301, USA

# You may use and distribute this software under the terms of the
# GNU General Public License, version 2 or later

from sqlalchemy import MetaData, func, select, and_
from sqlalchemy.orm import deferred, column_property, synonym

metadata = MetaData()
from . import tables  # *after* metadata initialization
#from ._objects import *
from ._objects import AChannel, ACodec, Lang, Medium, Ratio, SubFormat, Tag, \
    VCodec, Filter, Collection, Volume, Loan, Person, Poster, Configuration, \
    MovieLang, MovieTag
from ._movie import Movie

try:
    from sqlalchemy.orm import relationship, registry

    mapper_registry = registry()

    mapper_registry.map_imperatively(Configuration, tables.configuration)
    mapper_registry.map_imperatively(Volume, tables.volumes, properties={
        'loaned': synonym('_loaned', map_column=True),
        'movies': relationship(Movie, backref='volume',
                               order_by=tables.volumes.c.name)
        })
    mapper_registry.map_imperatively(
        Collection, tables.collections,
        properties={
            'loaned': synonym('_loaned', map_column=True),
            'movies': relationship(Movie, backref='collection',
                                   order_by=tables.collections.c.name)})
    mapper_registry.map_imperatively(Medium, tables.media, properties={
        'movies': relationship(Movie, backref='medium')})
    mapper_registry.map_imperatively(Ratio, tables.ratios, properties={
        'movies': relationship(Movie, backref='ratio')})
    mapper_registry.map_imperatively(VCodec, tables.vcodecs, properties={
        'movies': relationship(Movie, backref='vcodec')})
    mapper_registry.map_imperatively(Person, tables.people, properties={
        'loans': relationship(Loan, backref='person',
                              cascade='all, delete-orphan'),
        'loaned_movies_count': column_property(
            select(func.count(tables.loans.c.loan_id))
            .where(
                and_(
                    tables.people.c.person_id == tables.loans.c.person_id,
                    tables.loans.c.return_date.is_(None),
                )
            )
            .correlate_except(tables.loans)
            .scalar_subquery(),
            deferred=True,
        ),
        'returned_movies_count': column_property(
            select(func.count(tables.loans.c.loan_id))
            .where(
                and_(
                    tables.people.c.person_id == tables.loans.c.person_id,
                    tables.loans.c.return_date.is_not(None),
                )
            )
            .correlate_except(tables.loans)
            .scalar_subquery(),
            deferred=True,
        )
        })
    mapper_registry.map_imperatively(MovieLang, tables.movie_lang,
                                     primary_key=[tables.movie_lang.c.ml_id],
                                     properties={
                                         'movie': relationship(Movie),
                                         'language': relationship(Lang),
                                         'achannel': relationship(AChannel),
                                         'acodec': relationship(ACodec),
                                         'subformat': relationship(SubFormat)
                                         })
    mapper_registry.map_imperatively(ACodec, tables.acodecs, properties={
        'movielangs': relationship(MovieLang)})
    mapper_registry.map_imperatively(AChannel, tables.achannels, properties={
        'movielangs': relationship(MovieLang)})
    mapper_registry.map_imperatively(SubFormat, tables.subformats, properties={
        'movielangs': relationship(MovieLang)})
    mapper_registry.map_imperatively(Lang, tables.languages, properties={
        'movielangs': relationship(MovieLang)})
    mapper_registry.map_imperatively(MovieTag, tables.movie_tag)
    mapper_registry.map_imperatively(
        Tag, tables.tags,
        properties={'movietags': relationship(MovieTag, backref='tag')})
    mapper_registry.map_imperatively(Loan, tables.loans, properties={
        'volume': relationship(Volume),
        'collection': relationship(Collection)})
    mapper_registry.map_imperatively(Movie, tables.movies, properties={
        'loans': relationship(Loan, backref='movie',
                              cascade='all, delete-orphan'),
        # 'tags': relation(Tag, cascade='all, delete-orphan',
        # secondary=movie_tag,
        'tags': relationship(
            Tag, secondary=tables.movie_tag,
            primaryjoin=tables.movies.c.movie_id == tables.movie_tag.c.movie_id,
            secondaryjoin=tables.movie_tag.c.tag_id == tables.tags.c.tag_id),
        'languages': relationship(MovieLang, cascade='all, delete-orphan')
        })
    mapper_registry.map_imperatively(Poster, tables.posters, properties={
        'movies': relationship(Movie),
        'data': deferred(tables.posters.c.data)})
    mapper_registry.map_imperatively(Filter, tables.filters)


except Exception as ex:
    log.error(
        f"[E010]Caught too broad try-exception {type(ex).__name__} "
        f"with arguments '{ex.args}'")
    from sqlalchemy.orm import relation, mapper

    mapper(Configuration, tables.configuration)
    mapper(Volume, tables.volumes, order_by=tables.volumes.c.name, properties={
        'loaned': synonym('_loaned', map_column=True),
        'movies': relation(Movie, backref='volume')})
    mapper(Collection, tables.collections, order_by=tables.collections.c.name,
           properties={
               'loaned': synonym('_loaned', map_column=True),
               'movies': relation(Movie, backref='collection')
               })
    mapper(Medium, tables.media, properties={
        'movies': relation(Movie, backref='medium')})
    mapper(Ratio, tables.ratios, properties={
        'movies': relation(Movie, backref='ratio')})
    mapper(VCodec, tables.vcodecs, properties={
        'movies': relation(Movie, backref='vcodec')})
    mapper(Person, tables.people, properties={
        'loans': relation(Loan, backref='person',
                          cascade='all, delete-orphan'),
        'loaned_movies_count': column_property(
            select(func.count(tables.loans.c.loan_id))
            .where(
                and_(
                    tables.people.c.person_id == tables.loans.c.person_id,
                    tables.loans.c.return_date.is_(None),
                )
            )
            .correlate_except(tables.loans)
            .scalar_subquery(),
            deferred=True,
        ),
        'returned_movies_count': column_property(
            select(func.count(tables.loans.c.loan_id))
            .where(
                and_(
                    tables.people.c.person_id == tables.loans.c.person_id,
                    tables.loans.c.return_date.is_not(None),
                )
            )
            .correlate_except(tables.loans)
            .scalar_subquery(),
            deferred=True,
        ),
        })
    mapper(MovieLang, tables.movie_lang,
           primary_key=[tables.movie_lang.c.ml_id], properties={
            'movie': relation(Movie),
            'language': relation(Lang),
            'achannel': relation(AChannel),
            'acodec': relation(ACodec),
            'subformat': relation(SubFormat)
            })
    mapper(ACodec, tables.acodecs, properties={
        'movielangs': relation(MovieLang)})
    mapper(AChannel, tables.achannels, properties={
        'movielangs': relation(MovieLang)})
    mapper(SubFormat, tables.subformats, properties={
        'movielangs': relation(MovieLang)})
    mapper(Lang, tables.languages, properties={
        'movielangs': relation(MovieLang)})
    mapper(MovieTag, tables.movie_tag)
    mapper(Tag, tables.tags,
           properties={'movietags': relation(MovieTag, backref='tag')})
    mapper(Loan, tables.loans, properties={
        'volume': relation(Volume),
        'collection': relation(Collection)})
    mapper(Movie, tables.movies, order_by=tables.movies.c.number, properties={
        'loans': relation(Loan, backref='movie', cascade='all, delete-orphan'),
        # 'tags': relation(Tag, cascade='all, delete-orphan',
        # secondary=movie_tag,
        'tags': relation(
            Tag, secondary=tables.movie_tag,
            primaryjoin=tables.movies.c.movie_id == tables.movie_tag.c.movie_id,
            secondaryjoin=tables.movie_tag.c.tag_id == tables.tags.c.tag_id),
        'languages': relation(MovieLang, cascade='all, delete-orphan')
        })
    mapper(Poster, tables.posters, properties={
        'movies': relation(Movie),
        'data': deferred(tables.posters.c.data)})
    mapper(Filter, tables.filters)
