# coding: utf-8

from __future__ import absolute_import
from __future__ import division
from __future__ import unicode_literals

import logging
from six import iteritems

from sandbox.common.rest import Client
from sandbox.common.auth import OAuth

from saas.library.python.token_store import PersistentTokenStore

from saas.library.python.sandbox.task import SandboxTask
from saas.library.python.sandbox.resource import SandboxResource
from saas.library.python.sandbox.scheduler import SandboxScheduler, SchedulerStatus


class SandboxApi(object):
    LOGGER = logging.getLogger(__name__)

    def __init__(self, oauth_token=None):
        oauth_token = oauth_token if oauth_token else PersistentTokenStore.get_token_from_store_env_or_file('sandbox')
        self.sandbox_client = Client(auth=OAuth(oauth_token))

    def task_by_id(self, task_id):
        return SandboxTask(self.sandbox_client, task_id)

    def resource_by_id(self, resource_id):
        return SandboxResource(self.sandbox_client, resource_id)

    def scheduler_by_id(self, scheduler_id):
        return SandboxScheduler(self.sandbox_client, scheduler_id)

    def find_resources(self, resource_type=None, state=None, **kwargs):
        """
        :param resource_type: resource type in SCREAMING_SNAKE form
        :rtype: List[SandboxResource]
        """
        if state and not isinstance(state, list):
            state = [state, ]
        kwargs.update({'type': resource_type, 'state': state})
        request_params = {k: v for k, v in iteritems(kwargs) if v is not None}
        response = self.sandbox_client.resource.read(**request_params)
        return [SandboxResource.from_resource_info(self.sandbox_client, r) for r in response['items']]

    def find_schedulers(self, task_type=None, tags=None, status=None, owner=None, author=None, all_tags=False,
                        order=None, limit=20, full_info=False, **kwargs):

        if isinstance(status, str):
            status = status
        elif isinstance(status, SchedulerStatus):
            status = status.value
        elif isinstance(status, list):
            status = [s.value for s in status]

        request = dict(
            limit=limit if limit else 20,
            order=order,
            task_type=task_type,
            status=status,
            owner=owner,
            author=author,
            tags=tags,
            all_tags=all_tags
        )
        kwargs.update(request)
        request_params = {k: v for k, v in kwargs.items() if v is not None}
        response = self.sandbox_client.scheduler.read(**request_params)

        total_cnt = 0
        while len(response['items']) > 0 and total_cnt < limit:
            max_items = max(limit - total_cnt, 0)

            for scheduler in response['items'][:max_items]:
                if not full_info:
                    yield SandboxScheduler.from_scheduler_info(self.sandbox_client, scheduler)
                else:
                    yield SandboxScheduler(self.sandbox_client, scheduler['id'])

            total_cnt += len(response['items'])
            if total_cnt >= limit:
                break

            request_params['offset'] = total_cnt
            response = self.sandbox_client.scheduler.read(**request_params)

    def get_last_released_resource(self, resource_type):
        resources = self.find_resources(resource_type=resource_type, state='READY', attrs={'released': 'stable'}, limit=1)
        if len(resources) == 0:
            return None
        return resources[0]

    def add_task(self, task_type, task_owner, task_params, description='', notifications=None):
        if not description:
            import socket
            import sys
            import os
            description = 'SandboxApi in "{}" by "{}@{}"'.format(sys.argv[0], os.getlogin(), socket.gethostname())

        custom_fields = [{'name': k, 'value': v} for k, v in iteritems(task_params)]

        sandbox_task_info = self.sandbox_client.task(
            type=task_type,
            description=description,
            owner=task_owner,
            custom_fields=custom_fields,
            notifications=notifications
        )
        return SandboxTask.from_task_info(self.sandbox_client, sandbox_task_info)

    def add_scheduler(
            self, task_type, owner, scheduler_params, task_params, description='',
            scheduler_notifications=None, task_notifications=None, task_priority='BACKGROUND:LOW', task_tags=None
    ):
        priority_class, priority_subclass = task_priority.split(':')

        scheduler_info = self.sandbox_client.scheduler.create({
            'task_type': task_type,
            'data': {
                'owner': owner,
                'schedule': scheduler_params,
                'scheduler_notifications': scheduler_notifications,
                'task': {
                    'custom_fields': [{'name': k, 'value': v} for k, v in iteritems(task_params)],
                    'description': description,
                    'notifications': task_notifications,
                    'priority': {
                        'class': priority_class,
                        'subclass': priority_subclass
                    },
                    'tags': task_tags or []
                }
            }
        })
        return SandboxScheduler.from_scheduler_info(self.sandbox_client, scheduler_info)

    def update_scheduler(
            self, scheduler_id, scheduler_params, task_params, description='',
            scheduler_notifications=None, task_notifications=None, task_tags=None
    ):
        scheduler = {
            'schedule': scheduler_params,
            'scheduler_notifications': scheduler_notifications,
            'task': {
                'custom_fields': [{'name': k, 'value': v} for k, v in iteritems(task_params)],
                'description': description,
                'notifications': task_notifications,
                'tags': task_tags or []
            }
        }
        self.sandbox_client.scheduler[scheduler_id] = scheduler

    def delete_scheduler(self, scheduler_id):
        self.sandbox_client.batch.schedulers['delete'].update([scheduler_id])
