# pylint: disable=C0111,R0902,R0913
# Smartsheet Python SDK.
#
# Copyright 2018 Smartsheet.com, Inc.
#
# Licensed under the Apache License, Version 2.0 (the "License"): you may
# not use this file except in compliance with the License. You may obtain
# a copy of the License at
#
#    http://www.apache.org/licenses/LICENSE-2.0
#
# Unless required by applicable law or agreed to in writing, software
# distributed under the License is distributed on an "AS IS" BASIS, WITHOUT
# WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied. See the
# License for the specific language governing permissions and limitations
# under the License.

from __future__ import absolute_import

import logging
import os.path
from .models.folder import Folder
from . import fresh_operation


class Workspaces(object):

    """Class for handling Workspaces operations."""

    def __init__(self, smartsheet_obj):
        """Init Workspaces with base Smartsheet object."""
        self._base = smartsheet_obj
        self._log = logging.getLogger(__name__)

    def copy_workspace(self, workspace_id, container_destination_obj,
                       include=None, skip_remap=None):
        """Create a copy of the specified Workspace.

        Args:
            workspace_id (int): Workspace ID
            container_destination_obj (ContainerDestination): Container Destination object.
            include (list[str]): A comma-separated list of optional elements to copy.
                Valid list values: attachments, cellLinks, data, discussions, filters, forms,
                ruleRecipients, rules, shares, all (deprecated). Cell history will not be copied,
                regardless of which **include** parameter values are specified.
            skip_remap (list[str]): A comma separated list of references to NOT re-map for
                the newly created resource. Valid list items: cellLinks, reports, sheetHyperlinks, sights
        Returns:
            Result
        """
        _op = fresh_operation('copy_workspace')
        _op['method'] = 'POST'
        _op['path'] = '/workspaces/' + str(workspace_id) + '/copy'
        _op['query_params']['include'] = include
        _op['query_params']['skipRemap'] = skip_remap
        _op['json'] = container_destination_obj

        expected = ['Result', 'Workspace']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def create_folder_in_workspace(self, workspace_id, folder_obj):
        """Creates a Folder in the specified Workspace

        Args:
            workspace_id (int): Workspace ID
            folder_obj (Folder): Folder object.

        Returns:
            Result
        """
        if isinstance(folder_obj, str):
            folder_obj = Folder({
                'name': folder_obj
            })

        _op = fresh_operation('create_folder_in_workspace')
        _op['method'] = 'POST'
        _op['path'] = '/workspaces/' + str(workspace_id) + '/folders'
        _op['json'] = folder_obj

        expected = ['Result', 'Folder']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def create_sheet_in_workspace(self, workspace_id, sheet_obj):
        """Create a Sheet from scratch at the top-level of the specified
        Workspace.

        Args:
            workspace_id (int): Workspace ID
            sheet_obj (Sheet): Sheet object.

        Returns:
            Result
        """
        _op = fresh_operation('create_sheet_in_workspace')
        _op['method'] = 'POST'
        _op['path'] = '/workspaces/' + str(workspace_id) + '/sheets'
        _op['json'] = sheet_obj

        expected = ['Result', 'Sheet']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    # pylint: disable=invalid-name
    def create_sheet_in_workspace_from_template(self, workspace_id,
                                                sheet_obj, include=None):
        """Create a Sheet in the specified Workspace from the specified Template.

        The Sheet object should be limited to the following
        attributes:

        name (required): need not be unique.
        fromId (required): the ID of the Template to use in creating the
        Sheet.

        The optional Include parameter is a list of elements to copy from
        the Template. It may include: data, attachments, discussions,
        cellLinks, forms

        Args:
            workspace_id (int): Workspace ID
            sheet_obj (Sheet): Sheet object.
            include (list[str]): A list of optional elements
                to include from the source Template. Valid list values:
                data, attachments, discussions, cellLinks, forms.

        Returns:
            Result
        """
        _op = fresh_operation('create_sheet_in_workspace_from_template')
        _op['method'] = 'POST'
        _op['path'] = '/workspaces/' + str(workspace_id) + '/sheets'
        _op['query_params']['include'] = include
        _op['json'] = sheet_obj

        expected = ['Result', 'Sheet']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    # pylint: enable=invalid-name

    def create_workspace(self, workspace_obj):
        """Create a Workspace.

        Args:
            workspace_obj (Workspace): A Workspace object.

        Returns:
            Result
        """
        _op = fresh_operation('create_workspace')
        _op['method'] = 'POST'
        _op['path'] = '/workspaces'
        _op['json'] = workspace_obj

        expected = ['Result', 'Workspace']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def delete_share(self, workspace_id, share_id):
        """Delete the Share specified.

        Args:
            workspace_id (int): Workspace ID
            share_id (str): Share ID

        Returns:
            Result
        """
        _op = fresh_operation('delete_share')
        _op['method'] = 'DELETE'
        _op['path'] = '/workspaces/' + str(workspace_id) + '/shares/' + str(
            share_id)

        expected = ['Result', None]
        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def delete_workspace(self, workspace_id):
        """Delete the specified Workspace and its contents.

        Args:
            workspace_id (int): Workspace ID

        Returns:
            Result
        """
        _op = fresh_operation('delete_workspace')
        _op['method'] = 'DELETE'
        _op['path'] = '/workspaces/' + str(workspace_id)

        expected = ['Result', None]
        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def get_share(self, workspace_id, share_id):
        """Get the specified Share.

        Args:
            workspace_id (int): Workspace ID
            share_id (str): Share ID

        Returns:
            Share
        """
        _op = fresh_operation('get_share')
        _op['method'] = 'GET'
        _op['path'] = '/workspaces/' + str(workspace_id) + '/shares/' + str(
            share_id)

        expected = 'Share'
        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def get_workspace(self, workspace_id, load_all=False, include=None):
        """Get the specified Workspace and list its contents.

        Get the specified Workspace and list its contents. By
        default, this operation only returns top-level items in the
        Workspace. To load all of the contents, including nested Folders,
        include the **loadAll** parameter with a value of `true`.

        Args:
            workspace_id (int): Workspace ID
            load_all (bool): Load all contents, including
                nested items.
            include (list[str]): A comma-separated list of
                optional elements to include in the response. Valid list
                values: ownerInfo, sheetVersion, source.

        Returns:
            Workspace
        """
        _op = fresh_operation('get_workspace')
        _op['method'] = 'GET'
        _op['path'] = '/workspaces/' + str(workspace_id)
        _op['query_params']['loadAll'] = load_all
        _op['query_params']['include'] = include

        expected = 'Workspace'
        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def list_folders(self, workspace_id, page_size=None, page=None,
                     include_all=None):
        """Get a list of top-level child Folders within the specified
        Workspace.

        Args:
            workspace_id (int): Workspace ID
            page_size (int): The maximum number of items to
                return per page.
            page (int): Which page to return.
            include_all (bool): If true, include all results
                (i.e. do not paginate).

        Returns:
            IndexResult
        """
        _op = fresh_operation('list_folders')
        _op['method'] = 'GET'
        _op['path'] = '/workspaces/' + str(workspace_id) + '/folders'
        _op['query_params']['pageSize'] = page_size
        _op['query_params']['page'] = page
        _op['query_params']['includeAll'] = include_all

        expected = ['IndexResult', 'Folder']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def list_shares(self, workspace_id, page_size=None, page=None,
                    include_all=None):
        """Get a list of all Users and Groups to whom the specified Workspace
        is shared, and their access level.

        Args:
            workspace_id (int): Workspace ID
            page_size (int): The maximum number of items to
                return per page.
            page (int): Which page to return.
            include_all (bool): If true, include all results
                (i.e. do not paginate).

        Returns:
            IndexResult
        """
        _op = fresh_operation('list_shares')
        _op['method'] = 'GET'
        _op['path'] = '/workspaces/' + str(workspace_id) + '/shares'
        _op['query_params']['pageSize'] = page_size
        _op['query_params']['page'] = page
        _op['query_params']['includeAll'] = include_all
        expected = ['IndexResult', 'Share']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def list_workspaces(self, page_size=None, page=None, include_all=None):
        """Get the list of Workspaces the authenticated User may access.

        Args:
            page_size (int): The maximum number of items to
                return per page.
            page (int): Which page to return.
            include_all (bool): If true, include all results
                (i.e. do not paginate).

        Returns:
            IndexResult
        """
        _op = fresh_operation('list_workspaces')
        _op['method'] = 'GET'
        _op['path'] = '/workspaces'
        _op['query_params']['pageSize'] = page_size
        _op['query_params']['page'] = page
        _op['query_params']['includeAll'] = include_all

        expected = ['IndexResult', 'Workspace']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def share_workspace(self, workspace_id, share_obj, send_email=False):
        """Share a Workspace with the specified Users and Groups.

        Args:
            workspace_id (int): Workspace ID
            share_obj (Share): Share object.
            send_email (bool): Either true or false to
                indicate whether or not to notify the user by email. Default
                is false.

        Returns:
            Result
        """
        _op = fresh_operation('share_workspace')
        _op['method'] = 'POST'
        _op['path'] = '/workspaces/' + str(workspace_id) + '/shares'
        _op['query_params']['sendEmail'] = send_email
        _op['json'] = share_obj

        expected = ['Result', 'Share']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def update_share(self, workspace_id, share_id, share_obj):
        """Update the access level of a User or Group for the specified
        Workspace.

        Args:
            workspace_id (int): Workspace ID
            share_id (str): Share ID
            share_obj (Share): Share object.

        Returns:
            Result
        """
        if not all(val is not None for val in ['workspace_id', 'share_id',
                                               'share_obj']):
            raise ValueError(
                ('One or more required values '
                 'are missing from call to ' + __name__))

        _op = fresh_operation('update_share')
        _op['method'] = 'PUT'
        _op['path'] = '/workspaces/' + str(workspace_id) + '/shares/' + str(
            share_id)
        _op['json'] = share_obj

        expected = ['Result', 'Share']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def update_workspace(self, workspace_id, workspace_obj):
        """Update the specified Workspace.

        Args:
            workspace_id (int): Workspace ID
            workspace_obj (Workspace): A Workspace object.

        Returns:
            Result
        """
        _op = fresh_operation('update_workspace')
        _op['method'] = 'PUT'
        _op['path'] = '/workspaces/' + str(workspace_id)
        _op['json'] = workspace_obj

        expected = ['Result', 'Workspace']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response

    def import_csv_sheet(self, workspace_id, file, sheet_name=None, header_row_index=None, primary_column_index=None ):
        """Imports a sheet in the specified workspace.

        Args:
            workspace_id (int): workspace ID
            file (string): path to CSV file.
            sheet_name (string): destination sheet name
            header_row_index (int): index (0 based) of row to be used for column names
            primary_column_index (int): index (0 based) of primary column

        Returns:
            Result
            """
        if not all(val is not None for val in ['folder_id', 'file']):
            raise ValueError(
                ('One or more required values '
                 'are missing from call to ' + __name__))

        return self._import_sheet(workspace_id, file, "text/csv",
                                  sheet_name, header_row_index, primary_column_index)

    def import_xlsx_sheet(self, workspace_id, file, sheet_name=None, header_row_index=None, primary_column_index=None ):
        """Imports a sheet in the specified workspace.

        Args:
            workspace_id (int): workspace ID
            file (string): path to XLSX file.
            sheet_name (string): destination sheet name
            header_row_index (int): index (0 based) of row to be used for column names
            primary_column_index (int): index (0 based) of primary column

        Returns:
            Result
            """
        if not all(val is not None for val in ['folder_id', 'file']):
            raise ValueError(
                ('One or more required values '
                 'are missing from call to ' + __name__))

        return self._import_sheet(workspace_id, file,
                                  "application/vnd.openxmlformats-officedocument.spreadsheetml.sheet",
                                  sheet_name, header_row_index, primary_column_index)

    def _import_sheet(self, workspace_id, file, file_type, sheet_name, header_row_index, primary_column_index):
        """Internal function used to import sheet"""

        if sheet_name is None:
            head, tail = os.path.split(file)
            sheet_name = tail or os.path.basename(head)

        _data = open(file, 'rb').read()

        _op = fresh_operation('import_sheet_into_folder')
        _op['method'] = 'POST'
        _op['path'] = '/workspaces/' + str(workspace_id) + '/sheets/import'
        _op['headers'] = {'content-type': file_type,
                          'content-disposition': 'attachment'}
        _op['form_data'] = _data
        _op['query_params']['sheetName'] = sheet_name
        _op['query_params']['headerRowIndex'] = header_row_index
        _op['query_params']['primaryColumnIndex'] = primary_column_index

        expected = ['Result', 'Sheet']

        prepped_request = self._base.prepare_request(_op)
        response = self._base.request(prepped_request, expected, _op)

        return response
