# -*- 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.


import abc

from xivo_dao.alchemy.extension import Extension
from xivo_dao.alchemy.linefeatures import LineFeatures as Line
from xivo_dao.alchemy.sccpline import SCCPLine as SCCP
from xivo_dao.alchemy.userfeatures import UserFeatures as User
from xivo_dao.alchemy.usersip import UserSIP as SIP
from xivo_dao.helpers.exception import NotFoundError
from xivo_dao.resources.voicemail.model import Voicemail

from xivo_confd.database import sip_update as sip_update_db


class Creator(object, metaclass=abc.ABCMeta):

    def __init__(self, service):
        self.service = service

    @abc.abstractmethod
    def find(self, fields):
        pass

    @abc.abstractmethod
    def create(self, fields):
        pass

    def update(self, fields, model):
        self.update_model(fields, model)
        self.service.edit(model)

    def update_model(self, fields, model):
        for key, value in fields.items():
            setattr(model, key, value)


class ImportCreator(Creator, metaclass=abc.ABCMeta):

    def update(self, fields, model, reload_device=True):
        self.update_model(fields, model)
        self.service.edit(model, reload_device)


class UserCreator(ImportCreator):

    def find(self, fields):
        if 'uuid' in fields:
            return self.service.get_by(uuid=fields['uuid'])

    def create(self, fields):
        if fields:
            label_names = fields.pop('labels', None)
            model = User(**fields)
            for label in self.service.get_labels_by_name(label_names):
                model.labels.append(label)
            return self.service.create_with_agent(model, None, None, None)

    def update(self, fields, model, reload_device=True):
        label_names = fields.pop('labels', None)
        if label_names is not None:
            model.labels = []
            for label in self.service.get_labels_by_name(label_names):
                model.labels.append(label)
        self.update_model(fields, model)
        self.service.edit(model)


class VoicemailCreator(Creator):

    def find(self, fields):
        number = fields.get('number')
        context = fields.get('context')
        if number or context:
            try:
                return self.service.dao.get_by_number_context(number, context)
            except NotFoundError:
                return None

    def create(self, fields):
        number = fields.get('number')
        context = fields.get('context')
        if number or context:
            return self.service.create(Voicemail(**fields))


class LineCreator(ImportCreator):

    def find(self, fields):
        return None

    def update(self, fields, line, reload_device=True):
        fields = dict(fields)
        if 'endpoint' in fields:
            del fields['endpoint']
        self.update_model(fields, line)
        self.service.edit(line, reload_device)

    def create(self, fields):
        fields = dict(fields)
        context = fields.get('context')
        endpoint = fields.pop('endpoint', None)
        if context and endpoint in ('sip', 'sccp', 'webrtc', 'ua'):
            return self.service.create(Line(**fields))


class SipCreator(ImportCreator):

    def find(self, fields):
        name = fields.get('name')
        if name:
            return self.service.find_by(name=name)

    def create(self, fields):
        fields = dict(fields)
        fields.pop('webrtc', None)
        line_protocol = fields.pop('endpoint', None)
        if line_protocol == 'webrtc':
            fields['options'] = [["webrtc", "yes"]]
        elif line_protocol == 'ua':
            fields['options'] = [["webrtc", "ua"]]
        return self.service.create(SIP(**fields))

    def update(self, fields, resource, reload_device=True):
        fields = dict(fields)
        fields.pop('webrtc', None)
        line_protocol = fields.pop('endpoint', None)

        if line_protocol in ('sip', 'webrtc', 'ua'):
            sip_options = sip_update_db.get_sip_options(resource.id)[0]
            updated_sip_options = []
            if sip_options:
                for option in sip_options:
                    if option[0] != 'webrtc':
                        updated_sip_options.append(option)

            if line_protocol == 'webrtc':
                updated_sip_options.append(["webrtc", "yes"])
            elif line_protocol == 'ua':
                updated_sip_options.append(["webrtc", "ua"])

            fields['options'] = updated_sip_options

        self.update_model(fields, resource)
        self.service.edit(resource, reload_device)


class SccpCreator(Creator):

    def find(self, fields):
        return None

    def create(self, fields):
        return self.service.create(SCCP(**fields))


class ExtensionCreator(ImportCreator):

    def find(self, fields):
        exten = fields.get('exten')
        context = fields.get('context')
        if exten and context:
            try:
                return self.service.dao.get_by(exten=exten, context=context)
            except NotFoundError:
                return None

    def create(self, fields):
        exten = fields.get('exten')
        context = fields.get('context')
        if exten and context:
            return self.service.create(Extension(**fields))


class CtiProfileCreator(Creator):

    def __init__(self, dao):
        self.dao = dao

    def find(self, fields):
        name = fields.get('name')
        if name:
            try:
                cti_profile_id = self.dao.get_id_by_name(name)
                return self.dao.get(cti_profile_id)
            except NotFoundError:
                return None

    def update(self, fields, resource):
        pass

    def create(self, fields):
        name = fields.get('name')
        if name:
            cti_profile_id = self.dao.get_id_by_name(name)
            return self.dao.get(cti_profile_id)


class IncallCreator(Creator):

    def find(self, fields):
        exten = fields.get('exten')
        context = fields.get('context')
        if exten and context:
            try:
                return self.service.dao.get_by(exten=exten, context=context)
            except NotFoundError:
                return None

    def create(self, fields):
        fields = self.extract_extension_fields(fields)
        if fields:
            extension = Extension(**fields)
            return self.service.create(extension)

    def update(self, fields, resource):
        extension_fields = self.extract_extension_fields(fields)
        self.update_model(extension_fields, resource)
        self.service.edit(resource)

    def extract_extension_fields(self, fields):
        return {key: fields[key]
                for key in ('exten', 'context')
                if fields.get(key) is not None}


class CallPermissionCreator(Creator):

    def find(self, fields):
        names = fields.get('names')
        if names is not None:
            return [self.service.get_by(name=name) for name in names]

    def create(self, fields):
        return self.find(fields)

    def update(self, fields, resource):
        pass
