# -*- coding: utf-8 -*-
"""
Это REST api на базе tastypie
Оно особо не нужно, но используется в скриптах переливки лунапарковых стрельб.
В принципе. если переливаться будет каким-то иным способом, то tastypie можно выпилить.
К тому же этот tastypie до сих пор не поддерживает django2
После выпиливания можно переехать на django2

Created on Aug 8, 2016

@author: noob
"""
from django.db import OperationalError

from .auth import NullAuthentication, NullAuthorization
from tastypie.resources import ModelResource
from tastypie.serializers import Serializer
from common.models import Job, JobMeta, Data, DataMeta
import logging
import yaml
import uuid
from tastypie import fields


class JobResource(ModelResource):

    class Meta:
        list_allowed_methods = ['get', 'post', 'patch', 'put']
        queryset = Job.objects.all()
        resource_name = 'jobs'
        authentication = NullAuthentication()
        authorization = NullAuthorization()
        always_return_data = True
        serializer = Serializer()
        filtering = {
            'id': ('exact',),
            'status': ('exact', 'startswith'),
        }
        ordering = ('id',)

    def dehydrate(self, bundle):
        bundle.data['meta'] = {m.key: m.value for m in JobMeta.objects.filter(job_id=bundle.obj.pk)}
        return bundle

    def __handle_post(self, bundle, **kwargs):
        """
        Принимаем конфиг в виде yaml .
        :param bundle: Tastypie bundle
        """
        config = bundle.data
        # =======================================================================
        # TODO: CONFIG VALIDATION
        # =======================================================================

        # ===================================================================
        # SAVE JOB
        # ===================================================================
        bundle.data = {'status': 'new'}

        job_create = super(JobResource, self).obj_create(bundle, **kwargs)
        job = job_create.obj

        # ===================================================================
        # CONVERT CONFIG INTO JOB META DATA
        # ===================================================================

        JobMeta.objects.create(
            job=job,
            key='configinitial',
            value=yaml.dump(config)
        )

        for k, v in config.get('uploader', {}).items():
            JobMeta.objects.create(
                job=job,
                key=k,
                value=repr(v)
            )

        logging.error('API Created job {}'.format(job.id))
        # ===================================================================
        # TANKS ALLOWED TO CLAIM JOB
        # ===================================================================
        return job_create


class JobMetaResource(ModelResource):
    job = fields.ToOneField(JobResource, 'job', full=False, null=False, blank=False)

    class Meta:
        list_allowed_methods = ['get', 'post', 'patch']
        queryset = JobMeta.objects.all()
        resource_name = 'job_meta'
        authentication = NullAuthentication()
        authorization = NullAuthorization()
        serializer = Serializer()
        always_return_data = True
        filtering = {
            'id': ('exact',),
            'job': ('exact', 'startswith'),
            'key': ('exact', 'startswith'),
        }
        ordering = ('id',)

    def obj_create(self, bundle, **kwargs):
        """
        :param bundle:
        :param kwargs:
        :return:
        """
        bundle.data['job'] = '/api/v1/jobs/{}/'.format(bundle.data['job'])
        print(bundle.data)
        return super(JobMetaResource, self).obj_create(bundle, **kwargs)


class DataResource(ModelResource):
    job = fields.ToOneField(JobResource, 'job', full=False, null=False, blank=False)

    class Meta:
        list_allowed_methods = ['get', 'post', 'patch']
        queryset = Data.objects.all()
        resource_name = 'data'
        authentication = NullAuthentication()
        authorization = NullAuthorization()
        serializer = Serializer()
        always_return_data = True
        filtering = {
            'id': ('exact',),
            'uniq_id': ('exact',),
            'job': ('exact', 'startswith'),
        }
        ordering = ('id', )

    def dehydrate(self, bundle):
        bundle.data['meta'] = {m.key: m.value for m in DataMeta.objects.filter(data_id=bundle.obj.pk)}
        return bundle

    def obj_create(self, bundle, **kwargs):
        """
        d_types format:
        {
            'job': <number>,
            'type': 'metric',
            'name': 'cpu_cpu9_user',
            'meta_1': 'metaval_1',
            'meta_2': 'metaval_2',
        }
        :param bundle:
        :param kwargs:
        :return:
        """
        bundle.data['uniq_id'] = uuid.uuid4().hex
        bundle.data['job'] = '/api/v1/jobs/{}/'.format(bundle.data['job'])
        try:
            data_obj = super(DataResource, self).obj_create(bundle, **kwargs)
        except OperationalError:  # 1 retry on unique uuid
            bundle.data['uniq_id'] = uuid.uuid4().hex
            data_obj = super(DataResource, self).obj_create(bundle, **kwargs)

        for k, v in bundle.data.items():
            if k not in ('job', 'uniq_id', 'offset', 'type'):
                DataMeta.objects.create(
                    data=data_obj.obj,
                    key=k,
                    value=v,
                )
        return data_obj


class DataMetaResource(ModelResource):
    data = fields.ToOneField(DataResource, 'data', full=False, null=False, blank=False)

    class Meta:
        list_allowed_methods = ['get', 'post', 'patch']
        queryset = DataMeta.objects.all()
        resource_name = 'data_meta'
        authentication = NullAuthentication()
        authorization = NullAuthorization()
        serializer = Serializer()
        always_return_data = True
        filtering = {
            'id': ('exact',),
            'data': ('exact', 'startswith'),
            'key': ('exact', 'startswith'),
        }
        ordering = ('id',)

    def obj_create(self, bundle, **kwargs):
        """
        :param bundle:
        :param kwargs:
        :return:
        """
        bundle.data['data'] = '/api/v1/data/{}/'.format(bundle.data['data'])
        print(bundle.data)
        return super(DataMetaResource, self).obj_create(bundle, **kwargs)
