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

from sqlalchemy.dialects.postgresql import JSONB
from yandex.maps.wiki.utils import require
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

TASK_NAME = 'guide_pedestrian'
ACL_PATH = 'mpro/tasks/guide-pedestrian'


@tasks.register_task_type(name=TASK_NAME)
class GuidePedestrian:
    @staticmethod
    def capabilities_ET():
        return EM.guide_pedestrian_task_type()

    @staticmethod
    def validateBodyJson(jsonValue):
        require(
            jsonValue['type'] == "GeometryCollection",
            fh.ServiceException("'type' == 'GeometryCollection' expected for root json object", status='ERR_BAD_REQUEST')
        )
        for jsonPoint in jsonValue['geometries']:
            require(
                jsonPoint['type'] == "Point",
                fh.ServiceException("'type' == 'Point' expected for point object", status='ERR_BAD_REQUEST')
            )
            float(jsonPoint['coordinates'][0])  # parse lon
            float(jsonPoint['coordinates'][1])  # parse lat
        return jsonValue['geometries']

    @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')
            )

            task = GuidePedestrianTask()

            revisionStr = request.values['revision']
            revisionArray = revisionStr.split(":")
            task.params_object_id = int(revisionArray[0])
            task.params_commit_id = int(revisionArray[1])

            jsonValue = json.loads(request.values['points'])
            pointsJson = GuidePedestrian.validateBodyJson(jsonValue)

            task.points = pointsJson
        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(GuidePedestrianTask).get(task_id)
        gateway = tasks.grinder.GrinderGateway(config.get_config().grinder_params.host)
        return gateway.submit(task.get_grinder_args())


class GuidePedestrianTask(models.Task):
    __tablename__ = 'guide_pedestrian_task'
    __table_args__ = {'schema': 'service'}
    __mapper_args__ = {'polymorphic_identity': 'guide_pedestrian'}

    id = sa.Column(sa.BigInteger, sa.ForeignKey('service.task.id'), primary_key=True)
    params_object_id = sa.Column(sa.BigInteger, nullable=False)
    params_commit_id = sa.Column(sa.BigInteger, nullable=False)
    points = sa.Column(JSONB, 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.guide_pedestrian_context(
            EM.revision(str(self.params_object_id) + ":" + str(self.params_commit_id)),
        )

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