# coding: utf-8
import logging
import sqlalchemy as sa
import re

from yandex.maps.wiki.utils import require, string_to_bool
from yandex.maps.wiki import db, fastcgihelpers as fh
from yandex.maps.wiki import tasks
from yandex.maps.wiki import config
from yandex.maps.wiki import pgpool3
from yandex.maps.wiki.tasks import EM
from yandex.maps.wiki.tasks import models

from maps.wikimap.mapspro.libs.python import acl
from maps.wikimap.mapspro.libs.python.social import feedback

TASK_NAME = 'import_feedback'
ACL_PATH = 'mpro/tasks/import-feedback'


@tasks.register_task_type(name=TASK_NAME)
class ImportFeedback:
    @staticmethod
    def capabilities_ET():
        return EM.import_feedback_task_type(
            EM.types(
                *[EM.type(t) for t in feedback.all_types()]
            ),
            EM.workflows(
                *[EM.workflow(w) for w in feedback.all_workflows()]
            )
        )

    @staticmethod
    def create(uid, request):
        try:
            require(
                acl.is_permission_granted(pgpool3.get_pgpool(db.CORE_DB), ACL_PATH, uid, None),
                fh.ServiceException('forbidden', status='ERR_FORBIDDEN')
            )

            for param in 'source', 'feedback_type', 'workflow', 'hidden':
                require(
                    param in request.args,
                    fh.ServiceException('param {0!r} required'.format(param), status='ERR_BAD_REQUEST')
                )

            task = ImportFeedbackTask()
            task.source = request.args['source']
            require(
                re.match(r'^[a-z\d_-]+$', task.source),
                fh.ServiceException(
                    "source must contain only low register letters, digits, and '-' as separator",
                    status='ERR_BAD_REQUEST'
                )
            )
            task.feedback_type = request.args['feedback_type']
            require(
                task.feedback_type in feedback.all_types(),
                fh.ServiceException('feedback type {0!r} is not supported'.format(task.feedback_type), status='ERR_BAD_REQUEST')
            )
            task.workflow = request.args['workflow']
            require(
                task.workflow in feedback.all_workflows(),
                fh.ServiceException('workflow {0!r} is not supported'.format(task.workflow), status='ERR_BAD_REQUEST')
            )
            task.hidden = string_to_bool(request.args['hidden'])
            require(
                request.files.values(),
                fh.ServiceException(
                    'File is not posted',
                    status='ERR_IMPORT_FILE_NOT_POSTED'
                )
            )
            uploaded_file = request.files.values()[0]
            task.file = uploaded_file.read()
        except fh.ServiceException:
            raise
        except Exception:
            logging.exception('invalid request')
            raise fh.ServiceException('error while parsing request',
                                      status='ERR_BAD_REQUEST')

        task.on_create(uid)
        return task

    @staticmethod
    def launch(session, task_id, request):
        task = session.query(ImportFeedbackTask).get(task_id)
        gateway = tasks.grinder.GrinderGateway(config.get_config().grinder_params.host)
        return gateway.submit(task.get_grinder_args())


class ImportFeedbackTask(models.Task):
    __tablename__ = 'import_feedback_task'
    __table_args__ = {'schema': 'service'}
    __mapper_args__ = {'polymorphic_identity': 'import_feedback'}

    id = sa.Column(sa.BigInteger, sa.ForeignKey('service.task.id'), primary_key=True)
    file = sa.orm.deferred(sa.Column(sa.types.LargeBinary))
    source = sa.Column(sa.String, nullable=False)
    feedback_type = sa.Column(sa.String, nullable=False)
    workflow = sa.Column(sa.String, nullable=False)
    hidden = sa.Column(sa.Boolean, nullable=False)

    def context_ET_brief(self, *args, **kwargs):
        return self.context_ET_full(*args, **kwargs)

    def context_ET_full(self, *args, **kwargs):
        return EM.import_feedback_context(
            EM.source(self.source),
            EM.type(self.feedback_type),
            EM.workflow(self.workflow),
            EM.hidden(self.hidden)
        )

    def get_grinder_args(self):
        return {
            'type': TASK_NAME,
            'taskId': self.id,
        }
