# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function

from polyaxon_client.api.base import BaseApiHandler
from polyaxon_client.exceptions import PolyaxonClientException
from polyaxon_client.schemas import (
    ExperimentConfig,
    ExperimentGroupConfig,
    JobConfig,
    ProjectConfig,
    TensorboardJobConfig
)


class ProjectApi(BaseApiHandler):
    """
    Api handler to get projects from the server.
    """
    ENDPOINT = "/"

    def list_projects(self, username, page=1):
        request_url = self.build_url(self._get_http_url(), username)
        try:
            response = self.transport.get(request_url, params=self.get_page(page=page))
            return self.prepare_list_results(response.json(), page, ProjectConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while retrieving projects.')
            return []

    def get_project(self, username, project_name):
        request_url = self.build_url(self._get_http_url(), username, project_name)
        try:
            response = self.transport.get(request_url)
            return self.prepare_results(response_json=response.json(), config=ProjectConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while retrieving project.')
            return None

    def create_project(self, project_config):
        project_config = self.validate_config(config=project_config, config_schema=ProjectConfig)
        try:
            response = self.transport.post(self._get_http_url('/projects'),
                                           json_data=project_config.to_dict())
            return self.prepare_results(response_json=response.json(), config=ProjectConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while creating project.')
            return None

    def update_project(self, username, project_name, patch_dict, background=False):
        request_url = self.build_url(self._get_http_url(), username, project_name)

        if background:
            self.transport.async_patch(request_url, json_data=patch_dict)
            return None

        try:
            response = self.transport.patch(request_url, json_data=patch_dict)
            return self.prepare_results(response_json=response.json(), config=ProjectConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while updating project.')
            return None

    def delete_project(self, username, project_name, background=False):
        request_url = self.build_url(self._get_http_url(), username, project_name)

        if background:
            self.transport.async_delete(request_url)
            return None

        try:
            response = self.transport.delete(request_url)
            return response
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while deleting project.')
            return None

    def upload_repo(self, username, project_name, files, files_size=None, background=False):
        """Uploads code data related for this project from the current dir."""
        request_url = self.build_url(
            self._get_http_url(), username, project_name, 'repo', 'upload')

        if background:
            self.transport.async_upload(request_url, files=files, files_size=files_size)
            return None

        try:
            response = self.transport.upload(request_url, files=files, files_size=files_size)
            return response
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while updating project repo.')
            return None

    def download_repo(self, username, project_name):
        """Downloads code for this project to the current dir."""
        request_url = self.build_url(
            self._get_http_url(), username, project_name, 'repo', 'download')

        try:
            response = self.transport.download(request_url, 'repo.tar.gz')
            return response
        except PolyaxonClientException as e:
            self.transport.handle_exception(
                e=e, log_message='Error while downloading project repo.')
            return None

    def list_experiment_groups(self, username, project_name, query=None, sort=None, page=1):
        """Fetch list of experiment groups related to this project."""
        request_url = self.build_url(
            self._get_http_url(), username, project_name, 'groups')

        try:
            params = self.get_page(page=page)
            if query:
                params['query'] = query
            if sort:
                params['sort'] = sort
            response = self.transport.get(request_url, params=params)
            return self.prepare_list_results(response.json(), page, ExperimentGroupConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(
                e=e, log_message='Error while retrieving experiment groups.')
            return []

    def create_experiment_group(self,
                                username,
                                project_name,
                                experiment_group_config,
                                background=False):
        experiment_group_config = self.validate_config(config=experiment_group_config,
                                                       config_schema=ExperimentGroupConfig)
        request_url = self.build_url(self._get_http_url(), username, project_name, 'groups')

        if background:
            self.transport.async_post(request_url, json_data=experiment_group_config.to_dict())
            return None

        try:
            response = self.transport.post(request_url, json_data=experiment_group_config.to_dict())
            return self.prepare_results(response_json=response.json(), config=ExperimentGroupConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(
                e=e, log_message='Error while creating experiment group.')
            return None

    def list_experiments(self,
                         username,
                         project_name,
                         independent=None,
                         group=None,
                         metrics=None,
                         declarations=None,
                         query=None,
                         sort=None,
                         page=1):
        """Fetch list of experiments related to this project."""
        request_url = self.build_url(self._get_http_url(), username, project_name, 'experiments')

        try:
            params = self.get_page(page=page)
            if independent:
                params['independent'] = independent
            if group:
                params['group'] = group
            if metrics:
                params['metrics'] = metrics
            if declarations:
                params['declarations'] = declarations
            if query:
                params['query'] = query
            if sort:
                params['sort'] = sort
            response = self.transport.get(request_url, params=params)
            return self.prepare_list_results(response.json(), page, ExperimentConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while retrieving experiments.')
            return []

    def create_experiment(self,
                          username,
                          project_name,
                          experiment_config,
                          group=None,
                          background=False):
        experiment_config = self.validate_config(config=experiment_config,
                                                 config_schema=ExperimentConfig)
        experiment_data = experiment_config.to_dict()
        if group:
            experiment_data['experiment_group'] = group
        request_url = self.build_url(self._get_http_url(), username, project_name, 'experiments')

        if background:
            self.transport.async_post(request_url, json_data=experiment_data)
            return None

        try:
            response = self.transport.post(request_url, json_data=experiment_data)
            return self.prepare_results(response_json=response.json(), config=ExperimentConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while creating experiment.')
            return None

    def list_jobs(self, username, project_name, query=None, sort=None, page=1):
        """Fetch list of jobs related to this project."""
        request_url = self.build_url(
            self._get_http_url(), username, project_name, 'jobs')

        try:
            params = self.get_page(page=page)
            if query:
                params['query'] = query
            if sort:
                params['sort'] = sort
            response = self.transport.get(request_url, params=params)
            return self.prepare_list_results(response.json(), page, JobConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while retrieving jobs.')
            return []

    def create_job(self, username, project_name, job_config, background=False):
        job_config = self.validate_config(config=job_config, config_schema=JobConfig)
        request_url = self.build_url(self._get_http_url(), username, project_name, 'jobs')

        if background:
            self.transport.async_post(request_url, json_data=job_config.to_dict())
            return None

        try:
            response = self.transport.post(request_url, json_data=job_config.to_dict())
            return self.prepare_results(response_json=response.json(), config=JobConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while creating job.')
            return None

    def list_builds(self, username, project_name, query=None, sort=None, page=1):
        """Fetch list of build jobs related to this project."""
        request_url = self.build_url(
            self._get_http_url(), username, project_name, 'builds')

        try:
            params = self.get_page(page=page)
            if query:
                params['query'] = query
            if sort:
                params['sort'] = sort
            response = self.transport.get(request_url, params=params)
            return self.prepare_list_results(response.json(), page, JobConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while retrieving build jobs.')
            return []

    def create_build(self, username, project_name, build_config, background=False):
        build_config = self.validate_config(config=build_config, config_schema=JobConfig)
        request_url = self.build_url(self._get_http_url(), username, project_name, 'builds')

        if background:
            self.transport.async_post(request_url, json_data=build_config.to_dict())
            return None

        try:
            response = self.transport.post(request_url, json_data=build_config.to_dict())
            return self.prepare_results(response_json=response.json(), config=JobConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while creating build job.')
            return None

    def list_tensorboards(self, username, project_name, query=None, sort=None, page=1):
        """Fetch list of tensorboard jobs related to this project."""
        request_url = self.build_url(
            self._get_http_url(), username, project_name, 'tensorboards')

        try:
            params = self.get_page(page=page)
            if query:
                params['query'] = query
            if sort:
                params['sort'] = sort
            response = self.transport.get(request_url, params=params)
            return self.prepare_list_results(response.json(), page, TensorboardJobConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(
                e=e, log_message='Error while retrieving tensorboard jobs.')
            return []

    def start_tensorboard(self, username, project_name, job_config=None, background=False):
        request_url = self.build_url(self._get_http_url(),
                                     username,
                                     project_name,
                                     'tensorboard',
                                     'start')

        job_config = {'config': job_config} if job_config else {}

        if background:
            self.transport.async_post(request_url, json_data=job_config)
            return None

        try:
            return self.transport.post(request_url, json_data=job_config)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while starting tensorboard.')
            return None

    def stop_tensorboard(self, username, project_name, background=False):
        request_url = self.build_url(self._get_http_url(),
                                     username,
                                     project_name,
                                     'tensorboard',
                                     'stop')

        if background:
            self.transport.async_post(request_url)
            return None

        try:
            return self.transport.post(request_url)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while stopping tensorboard.')
            return None

    def start_notebook(self, username, project_name, job_config=None, background=False):
        request_url = self.build_url(self._get_http_url(),
                                     username,
                                     project_name,
                                     'notebook',
                                     'start')

        job_config = {'config': job_config} if job_config else {}

        if background:
            self.transport.async_post(request_url, json_data=job_config)
            return None

        try:
            return self.transport.post(request_url, json_data=job_config)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while starting notebook.')
            return None

    def stop_notebook(self, username, project_name, commit=True, background=False):
        request_url = self.build_url(self._get_http_url(),
                                     username,
                                     project_name,
                                     'notebook',
                                     'stop')
        json_data = None
        if commit is False:
            json_data = {'commit': commit}

        if background:
            self.transport.async_post(request_url, json_data=json_data)
            return None

        try:
            return self.transport.post(request_url, json_data=json_data)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while stopping notebook.')
            return None

    def bookmark(self, username, project_name, background=False):
        request_url = self.build_url(self._get_http_url(),
                                     username,
                                     project_name,
                                     'bookmark')

        if background:
            self.transport.async_post(request_url)
            return None

        try:
            return self.transport.post(request_url)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while bookmarking project.')
            return None

    def unbookmark(self, username, project_name, background=False):
        request_url = self.build_url(self._get_http_url(),
                                     username,
                                     project_name,
                                     'unbookmark')

        if background:
            self.transport.async_delete(request_url)
            return None

        try:
            return self.transport.delete(request_url)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while unbookmarking project.')
            return None

# -*- coding: utf-8 -*-
from __future__ import absolute_import, division, print_function

from polyaxon_client.api.base import BaseApiHandler
from polyaxon_client.exceptions import PolyaxonClientException
from polyaxon_client.schemas import (
    ExperimentConfig,
    ExperimentGroupConfig,
    JobConfig,
    ProjectConfig,
    TensorboardJobConfig
)


class ProjectApi(BaseApiHandler):
    """
    Api handler to get projects from the server.
    """
    ENDPOINT = "/"

    def list_projects(self, username, page=1):
        request_url = self.build_url(self._get_http_url(), username)
        try:
            response = self.transport.get(request_url, params=self.get_page(page=page))
            return self.prepare_list_results(response.json(), page, ProjectConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while retrieving projects.')
            return []

    def get_project(self, username, project_name):
        request_url = self.build_url(self._get_http_url(), username, project_name)
        try:
            response = self.transport.get(request_url)
            return self.prepare_results(response_json=response.json(), config=ProjectConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while retrieving project.')
            return None

    def create_project(self, project_config):
        project_config = self.validate_config(config=project_config, config_schema=ProjectConfig)
        try:
            response = self.transport.post(self._get_http_url('/projects'),
                                           json_data=project_config.to_dict())
            return self.prepare_results(response_json=response.json(), config=ProjectConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while creating project.')
            return None

    def update_project(self, username, project_name, patch_dict, background=False):
        request_url = self.build_url(self._get_http_url(), username, project_name)

        if background:
            self.transport.async_patch(request_url, json_data=patch_dict)
            return None

        try:
            response = self.transport.patch(request_url, json_data=patch_dict)
            return self.prepare_results(response_json=response.json(), config=ProjectConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while updating project.')
            return None

    def delete_project(self, username, project_name, background=False):
        request_url = self.build_url(self._get_http_url(), username, project_name)

        if background:
            self.transport.async_delete(request_url)
            return None

        try:
            response = self.transport.delete(request_url)
            return response
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while deleting project.')
            return None

    def upload_repo(self, username, project_name, files, files_size=None, background=False):
        """Uploads code data related for this project from the current dir."""
        request_url = self.build_url(
            self._get_http_url(), username, project_name, 'repo', 'upload')

        if background:
            self.transport.async_upload(request_url, files=files, files_size=files_size)
            return None

        try:
            response = self.transport.upload(request_url, files=files, files_size=files_size)
            return response
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while updating project repo.')
            return None

    def download_repo(self, username, project_name):
        """Downloads code for this project to the current dir."""
        request_url = self.build_url(
            self._get_http_url(), username, project_name, 'repo', 'download')

        try:
            response = self.transport.download(request_url, 'repo.tar.gz')
            return response
        except PolyaxonClientException as e:
            self.transport.handle_exception(
                e=e, log_message='Error while downloading project repo.')
            return None

    def list_experiment_groups(self, username, project_name, query=None, sort=None, page=1):
        """Fetch list of experiment groups related to this project."""
        request_url = self.build_url(
            self._get_http_url(), username, project_name, 'groups')

        try:
            params = self.get_page(page=page)
            if query:
                params['query'] = query
            if sort:
                params['sort'] = sort
            response = self.transport.get(request_url, params=params)
            return self.prepare_list_results(response.json(), page, ExperimentGroupConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(
                e=e, log_message='Error while retrieving experiment groups.')
            return []

    def create_experiment_group(self,
                                username,
                                project_name,
                                experiment_group_config,
                                background=False):
        experiment_group_config = self.validate_config(config=experiment_group_config,
                                                       config_schema=ExperimentGroupConfig)
        request_url = self.build_url(self._get_http_url(), username, project_name, 'groups')

        if background:
            self.transport.async_post(request_url, json_data=experiment_group_config.to_dict())
            return None

        try:
            response = self.transport.post(request_url, json_data=experiment_group_config.to_dict())
            return self.prepare_results(response_json=response.json(), config=ExperimentGroupConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(
                e=e, log_message='Error while creating experiment group.')
            return None

    def list_experiments(self,
                         username,
                         project_name,
                         independent=None,
                         group=None,
                         metrics=None,
                         declarations=None,
                         query=None,
                         sort=None,
                         page=1):
        """Fetch list of experiments related to this project."""
        request_url = self.build_url(self._get_http_url(), username, project_name, 'experiments')

        try:
            params = self.get_page(page=page)
            if independent:
                params['independent'] = independent
            if group:
                params['group'] = group
            if metrics:
                params['metrics'] = metrics
            if declarations:
                params['declarations'] = declarations
            if query:
                params['query'] = query
            if sort:
                params['sort'] = sort
            response = self.transport.get(request_url, params=params)
            return self.prepare_list_results(response.json(), page, ExperimentConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while retrieving experiments.')
            return []

    def create_experiment(self,
                          username,
                          project_name,
                          experiment_config,
                          group=None,
                          background=False):
        experiment_config = self.validate_config(config=experiment_config,
                                                 config_schema=ExperimentConfig)
        experiment_data = experiment_config.to_dict()
        if group:
            experiment_data['experiment_group'] = group
        request_url = self.build_url(self._get_http_url(), username, project_name, 'experiments')

        if background:
            self.transport.async_post(request_url, json_data=experiment_data)
            return None

        try:
            response = self.transport.post(request_url, json_data=experiment_data)
            return self.prepare_results(response_json=response.json(), config=ExperimentConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while creating experiment.')
            return None

    def list_jobs(self, username, project_name, query=None, sort=None, page=1):
        """Fetch list of jobs related to this project."""
        request_url = self.build_url(
            self._get_http_url(), username, project_name, 'jobs')

        try:
            params = self.get_page(page=page)
            if query:
                params['query'] = query
            if sort:
                params['sort'] = sort
            response = self.transport.get(request_url, params=params)
            return self.prepare_list_results(response.json(), page, JobConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while retrieving jobs.')
            return []

    def create_job(self, username, project_name, job_config, background=False):
        job_config = self.validate_config(config=job_config, config_schema=JobConfig)
        request_url = self.build_url(self._get_http_url(), username, project_name, 'jobs')

        if background:
            self.transport.async_post(request_url, json_data=job_config.to_dict())
            return None

        try:
            response = self.transport.post(request_url, json_data=job_config.to_dict())
            return self.prepare_results(response_json=response.json(), config=JobConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while creating job.')
            return None

    def list_builds(self, username, project_name, query=None, sort=None, page=1):
        """Fetch list of build jobs related to this project."""
        request_url = self.build_url(
            self._get_http_url(), username, project_name, 'builds')

        try:
            params = self.get_page(page=page)
            if query:
                params['query'] = query
            if sort:
                params['sort'] = sort
            response = self.transport.get(request_url, params=params)
            return self.prepare_list_results(response.json(), page, JobConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while retrieving build jobs.')
            return []

    def create_build(self, username, project_name, build_config, background=False):
        build_config = self.validate_config(config=build_config, config_schema=JobConfig)
        request_url = self.build_url(self._get_http_url(), username, project_name, 'builds')

        if background:
            self.transport.async_post(request_url, json_data=build_config.to_dict())
            return None

        try:
            response = self.transport.post(request_url, json_data=build_config.to_dict())
            return self.prepare_results(response_json=response.json(), config=JobConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while creating build job.')
            return None

    def list_tensorboards(self, username, project_name, query=None, sort=None, page=1):
        """Fetch list of tensorboard jobs related to this project."""
        request_url = self.build_url(
            self._get_http_url(), username, project_name, 'tensorboards')

        try:
            params = self.get_page(page=page)
            if query:
                params['query'] = query
            if sort:
                params['sort'] = sort
            response = self.transport.get(request_url, params=params)
            return self.prepare_list_results(response.json(), page, TensorboardJobConfig)
        except PolyaxonClientException as e:
            self.transport.handle_exception(
                e=e, log_message='Error while retrieving tensorboard jobs.')
            return []

    def start_tensorboard(self, username, project_name, job_config=None, background=False):
        request_url = self.build_url(self._get_http_url(),
                                     username,
                                     project_name,
                                     'tensorboard',
                                     'start')

        job_config = {'config': job_config} if job_config else {}

        if background:
            self.transport.async_post(request_url, json_data=job_config)
            return None

        try:
            return self.transport.post(request_url, json_data=job_config)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while starting tensorboard.')
            return None

    def stop_tensorboard(self, username, project_name, background=False):
        request_url = self.build_url(self._get_http_url(),
                                     username,
                                     project_name,
                                     'tensorboard',
                                     'stop')

        if background:
            self.transport.async_post(request_url)
            return None

        try:
            return self.transport.post(request_url)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while stopping tensorboard.')
            return None

    def start_notebook(self, username, project_name, job_config=None, background=False):
        request_url = self.build_url(self._get_http_url(),
                                     username,
                                     project_name,
                                     'notebook',
                                     'start')

        job_config = {'config': job_config} if job_config else {}

        if background:
            self.transport.async_post(request_url, json_data=job_config)
            return None

        try:
            return self.transport.post(request_url, json_data=job_config)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while starting notebook.')
            return None

    def stop_notebook(self, username, project_name, commit=True, background=False):
        request_url = self.build_url(self._get_http_url(),
                                     username,
                                     project_name,
                                     'notebook',
                                     'stop')
        json_data = None
        if commit is False:
            json_data = {'commit': commit}

        if background:
            self.transport.async_post(request_url, json_data=json_data)
            return None

        try:
            return self.transport.post(request_url, json_data=json_data)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while stopping notebook.')
            return None

    def bookmark(self, username, project_name, background=False):
        request_url = self.build_url(self._get_http_url(),
                                     username,
                                     project_name,
                                     'bookmark')

        if background:
            self.transport.async_post(request_url)
            return None

        try:
            return self.transport.post(request_url)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while bookmarking project.')
            return None

    def unbookmark(self, username, project_name, background=False):
        request_url = self.build_url(self._get_http_url(),
                                     username,
                                     project_name,
                                     'unbookmark')

        if background:
            self.transport.async_delete(request_url)
            return None

        try:
            return self.transport.delete(request_url)
        except PolyaxonClientException as e:
            self.transport.handle_exception(e=e, log_message='Error while unbookmarking project.')
            return None

# -*- coding: utf-8 -*- Api handler to get projects from the server. Uploads code data related for this project from the current dir. Downloads code for this project to the current dir. Fetch list of experiment groups related to this project. Fetch list of experiments related to this project. Fetch list of jobs related to this project. Fetch list of build jobs related to this project. Fetch list of tensorboard jobs related to this project.