# -*- coding: UTF-8 -*-

# Copyright (C) 2015-2016 Avencall
#
# 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 3 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 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 Foundation, Inc.,
# 51 Franklin Street, Fifth Floor, Boston, MA 02110-1301 USA.


from sqlalchemy import String, Integer
from sqlalchemy.orm import aliased
from sqlalchemy.sql import cast, func, and_, case
from xivo_dao.alchemy.cti_profile import CtiProfile
from xivo_dao.alchemy.dialaction import Dialaction
from xivo_dao.alchemy.extension import Extension
from xivo_dao.alchemy.incall import Incall
from xivo_dao.alchemy.labels import Labels
from xivo_dao.alchemy.linefeatures import LineFeatures as Line
from xivo_dao.alchemy.rightcall import RightCall
from xivo_dao.alchemy.rightcallmember import RightCallMember
from xivo_dao.alchemy.user_line import UserLine
from xivo_dao.alchemy.userfeatures import UserFeatures as User
from xivo_dao.alchemy.usersip import UserSIP as SIP
from xivo_dao.alchemy.voicemail import Voicemail
from xivo_dao.helpers.db_manager import Session


def export_query(separator=";"):
    ordered_incalls = aliased(
        Session.query(
            Incall.exten.label('exten'),
            Incall.context.label('context'),
            User.id.label('user_id')
        )
            .join(Dialaction,
                  and_(Dialaction.category == 'incall',
                       Dialaction.action == 'user',
                       cast(Dialaction.categoryval, Integer) == Incall.id))
            .join(User,
                  cast(Dialaction.actionarg1, Integer) == User.id)
            .order_by(Incall.exten, Incall.context)
            .subquery()
    )

    grouped_incalls = aliased(
        Session.query(
            ordered_incalls.c.user_id,
            func.string_agg(ordered_incalls.c.exten, separator).label('exten'),
            func.string_agg(ordered_incalls.c.context, separator).label('context')
        )
            .group_by(ordered_incalls.c.user_id)
            .subquery()
    )

    ordered_call_permissions = aliased(
        Session.query(
            RightCall.name,
            cast(RightCallMember.typeval, Integer).label('user_id')
        )
            .join(RightCallMember,
                  RightCallMember.rightcallid == RightCall.id)
            .join(User,
                  and_(RightCallMember.type == 'user',
                       cast(RightCallMember.typeval, Integer) == User.id))
            .order_by(RightCall.name)
            .subquery()
    )

    grouped_call_permissions = aliased(
        Session.query(
            ordered_call_permissions.c.user_id,
            func.string_agg(ordered_call_permissions.c.name, separator).label('name')
        )
            .group_by(ordered_call_permissions.c.user_id)
            .subquery()
    )

    ordered_labels = aliased(
        Session.query(
            Labels.display_name,
            User.id.label('user_id')
        )
            .join(User.labels)
            .order_by(Labels.display_name)
            .subquery()
    )

    grouped_labels = aliased(
        Session.query(
            ordered_labels.c.user_id,
            func.string_agg(ordered_labels.c.display_name, separator).label('labels')
        )
            .group_by(ordered_labels.c.user_id)
            .subquery()
    )

    columns = (
        User.uuid,
        cast(User.entity_id, String),
        User.firstname,
        User.lastname,
        User.email,
        User.mobile_phone_number,
        User.outgoing_caller_id,
        User.language,
        User.call_permission_password,
        case([(User.enabled, '1')], else_='0'),
        cast(User.ring_seconds, String),
        cast(User.simultaneous_calls, String),
        cast(User.enablehint, String),
        cast(User.enablexfer, String),
        cast(User.callrecord, String),
        cast(User.enableonlinerec, String),
        User.userfield,
        User.username,
        User.password,
        CtiProfile.name,
        cast(User.enableclient, String),
        Voicemail.name,
        Voicemail.number,
        Voicemail.context,
        Voicemail.password,
        Voicemail.email,
        cast(Voicemail.attach, String),
        cast(Voicemail.deletevoicemail, String),
        cast(cast(Voicemail.ask_password, Integer), String),
        Line.endpoint,
        Line.registrar,
        Line.provisioning_code,
        func.coalesce(Extension.context, Line.context),
        SIP.name,
        SIP.secret,
        SIP._options,
        Extension.exten,
        grouped_incalls.c.exten,
        grouped_incalls.c.context,
        grouped_call_permissions.c.name,
        grouped_labels.c.labels
    )

    query = (
        Session.query(*columns)
            .outerjoin(User.voicemail)
            .outerjoin(User.cti_profile)
            .outerjoin(User.main_line_rel)
            .outerjoin(UserLine.main_line_rel)
            .outerjoin(Line.sip_endpoint)
            .outerjoin(UserLine.extensions)
            .outerjoin(grouped_incalls,
                       User.id == grouped_incalls.c.user_id)
            .outerjoin(grouped_call_permissions,
                       User.id == grouped_call_permissions.c.user_id)
            .outerjoin(grouped_labels,
                       User.id == grouped_labels.c.user_id)
    )

    return query
