# -*- coding: utf-8 -*-.
import re
import warnings
import os
import logging


from pygsheets.drive import DriveAPIWrapper
from pygsheets.sheet import SheetAPIWrapper
from pygsheets.spreadsheet import Spreadsheet
from pygsheets.exceptions import SpreadsheetNotFound, NoValidUrlKeyFound
from pygsheets.custom_types import ValueRenderOption, DateTimeRenderOption

from google_auth_httplib2 import AuthorizedHttp

GOOGLE_SHEET_CELL_UPDATES_LIMIT = 50000

_url_key_re_v1 = re.compile(r'key=([^&#]+)')
_url_key_re_v2 = re.compile(r"/spreadsheets/d/([a-zA-Z0-9-_]+)")
_email_patttern = re.compile(r"\"?([-a-zA-Z0-9.`?{}]+@[-a-zA-Z0-9.]+\.\w+)\"?")
# _domain_pattern = re.compile("(?!-)[A-Z\d-]{1,63}(?<!-)$", re.IGNORECASE)

_deprecated_keyword_mapping = {
    'parent_id': 'folder',
}


class Client(object):
    """Create or access Google spreadsheets.

    Exposes members to create new spreadsheets or open existing ones. Use `authorize` to instantiate an instance of this
    class.

    >>> import pygsheets
    >>> c = pygsheets.authorize()

    The sheet API service object is stored in the sheet property and the drive API service object in the drive property.

    >>> c.sheet.get('<SPREADSHEET ID>')
    >>> c.drive.delete('<FILE ID>')

    :param credentials:             The credentials object returned by google-auth or google-auth-oauthlib.
    :param retries:                 (Optional) Number of times to retry a connection before raising a TimeOut error.
                                    Default: 3
    :param http:                    The underlying HTTP object to use to make requests. If not specified, a
                                    :class:`httplib2.Http` instance will be constructed.
    """

    spreadsheet_cls = Spreadsheet

    def __init__(self, credentials, retries=3, http=None):
        self.oauth = credentials
        self.logger = logging.getLogger(__name__)

        http = AuthorizedHttp(credentials, http=http)
        data_path = os.path.join(os.path.dirname(os.path.abspath(__file__)), "data")

        self.sheet = SheetAPIWrapper(http, data_path, retries=retries)
        self.drive = DriveAPIWrapper(http, data_path)

    @property
    def teamDriveId(self):
        """ Enable team drive support

            Deprecated: use client.drive.enable_team_drive(team_drive_id=?)
        """
        return self.drive.team_drive_id

    @teamDriveId.setter
    def teamDriveId(self, value):
        warnings.warn("Depricated  please use drive.enable_team_drive")
        self.drive.enable_team_drive(value)

    def spreadsheet_ids(self, query=None):
        """Get a list of all spreadsheet ids present in the Google Drive or TeamDrive accessed."""
        return [x['id'] for x in self.drive.spreadsheet_metadata(query)]

    def spreadsheet_titles(self, query=None):
        """Get a list of all spreadsheet titles present in the Google Drive or TeamDrive accessed."""
        return [x['name'] for x in self.drive.spreadsheet_metadata(query)]

    def create(self, title, template=None, folder=None, **kwargs):
        """Create a new spreadsheet.

        The title will always be set to the given value (even overwriting the templates title). The template
        can either be a `spreadsheet resource <https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets#resource-spreadsheet>`_
        or an instance of :class:`~pygsheets.Spreadsheet`. In both cases undefined values will be ignored.

        :param title:       Title of the new spreadsheet.
        :param template:    A template to create the new spreadsheet from.
        :param folder:      The Id of the folder this sheet will be stored in.
        :param kwargs:      Standard parameters (see reference for details).
        :return: :class:`~pygsheets.Spreadsheet`
        """
        result = self.sheet.create(title, template=template, **kwargs)
        if folder:
            self.drive.move_file(result['spreadsheetId'],
                                 old_folder=self.drive.spreadsheet_metadata(query="name = '" + title + "'")[0]['parents'][0],
                                 new_folder=folder)
        return self.spreadsheet_cls(self, jsonsheet=result)

    def open(self, title):
        """Open a spreadsheet by title.

        In a case where there are several sheets with the same title, the first one found is returned.

        >>> import pygsheets
        >>> c = pygsheets.authorize()
        >>> c.open('TestSheet')

        :param title:                           A title of a spreadsheet.

        :returns:                               :class:`~pygsheets.Spreadsheet`
        :raises pygsheets.SpreadsheetNotFound:  No spreadsheet with the given title was found.
        """
        try:
            spreadsheet = list(filter(lambda x: x['name'] == title, self.drive.spreadsheet_metadata()))[0]
            return self.open_by_key(spreadsheet['id'])
        except (KeyError, IndexError):
            raise SpreadsheetNotFound('Could not find a spreadsheet with title %s.' % title)

    def open_by_key(self, key):
        """Open a spreadsheet by key.

        >>> import pygsheets
        >>> c = pygsheets.authorize()
        >>> c.open_by_key('0BmgG6nO_6dprdS1MN3d3MkdPa142WFRrdnRRUWl1UFE')

        :param key:                             The key of a spreadsheet. (can be found in the sheet URL)
        :returns:                               :class:`~pygsheets.Spreadsheet`
        :raises pygsheets.SpreadsheetNotFound:  The given spreadsheet ID was not found.
        """
        response = self.sheet.get(key,
                                  fields='properties,sheets/properties,spreadsheetId,namedRanges',
                                  includeGridData=False)
        return self.spreadsheet_cls(self, response)

    def open_by_url(self, url):
        """Open a spreadsheet by URL.

        >>> import pygsheets
        >>> c = pygsheets.authorize()
        >>> c.open_by_url('https://docs.google.com/spreadsheet/ccc?key=0Bm...FE&hl')

        :param url:                             URL of a spreadsheet as it appears in a browser.
        :returns:                               :class:`~pygsheets.Spreadsheet`
        :raises pygsheets.SpreadsheetNotFound:  No spreadsheet was found with the given URL.
        """
        m1 = _url_key_re_v1.search(url)
        if m1:
            return self.open_by_key(m1.group(1))

        else:
            m2 = _url_key_re_v2.search(url)
            if m2:
                return self.open_by_key(m2.group(1))
            else:
                raise NoValidUrlKeyFound

    def open_all(self, query=''):
        """Opens all available spreadsheets.

        Result can be filtered when specifying the query parameter. On the details on how to form the query:

        `Reference <https://developers.google.com/drive/v3/web/search-parameters>`_

        :param query:   (Optional) Can be used to filter the returned metadata.
        :returns:       A list of :class:`~pygsheets.Spreadsheet`.
        """
        return [self.open_by_key(key) for key in self.spreadsheet_ids(query=query)]

    def open_as_json(self, key):
        """Return a json representation of the spreadsheet.

        See `Reference <https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets#Spreadsheet>`__ for details.
        """
        return self.sheet.get(key, fields='properties,sheets/properties,sheets/protectedRanges,'
                                          'spreadsheetId,namedRanges',
                              includeGridData=False)

    def get_range(self, spreadsheet_id,
                  value_range,
                  major_dimension='ROWS',
                  value_render_option=ValueRenderOption.FORMATTED_VALUE,
                  date_time_render_option=DateTimeRenderOption.SERIAL_NUMBER):
        """Returns a range of values from a spreadsheet. The caller must specify the spreadsheet ID and a range.

        Reference: `request <https://developers.google.com/sheets/api/reference/rest/v4/spreadsheets.values/get>`__

        :param spreadsheet_id:              The ID of the spreadsheet to retrieve data from.
        :param value_range:                 The A1 notation of the values to retrieve.
        :param major_dimension:             The major dimension that results should use.
                                            For example, if the spreadsheet data is: A1=1,B1=2,A2=3,B2=4, then
                                            requesting range=A1:B2,majorDimension=ROWS will return [[1,2],[3,4]],
                                            whereas requesting range=A1:B2,majorDimension=COLUMNS will return
                                            [[1,3],[2,4]].
        :param value_render_option:         How values should be represented in the output. The default
                                            render option is `ValueRenderOption.FORMATTED_VALUE`.
        :param date_time_render_option:     How dates, times, and durations should be represented in the output.
                                            This is ignored if `valueRenderOption` is `FORMATTED_VALUE`. The default
                                            dateTime render option is [`DateTimeRenderOption.SERIAL_NUMBER`].
        :return:                            An array of arrays with the values fetched. Returns an empty array if no
                                            values were fetched. Values are dynamically typed as int, float or string.
        """
        result = self.sheet.values_get(spreadsheet_id, value_range, major_dimension, value_render_option,
                                       date_time_render_option)
        try:
            return result['values']
        except KeyError:
            return [['']]
[((18, 17, 18, 44), 're.compile', 're.compile', ({(18, 28, 18, 43): '"""key=([^&#]+)"""'}, {}), "('key=([^&#]+)')", False, 'import re\n'), ((19, 17, 19, 64), 're.compile', 're.compile', ({(19, 28, 19, 63): '"""/spreadsheets/d/([a-zA-Z0-9-_]+)"""'}, {}), "('/spreadsheets/d/([a-zA-Z0-9-_]+)')", False, 'import re\n'), ((20, 18, 20, 79), 're.compile', 're.compile', ({(20, 29, 20, 78): '"""\\\\"?([-a-zA-Z0-9.`?{}]+@[-a-zA-Z0-9.]+\\\\.\\\\w+)\\\\"?"""'}, {}), '(\'\\\\"?([-a-zA-Z0-9.`?{}]+@[-a-zA-Z0-9.]+\\\\.\\\\w+)\\\\"?\')', False, 'import re\n'), ((53, 22, 53, 49), 'logging.getLogger', 'logging.getLogger', ({(53, 40, 53, 48): '__name__'}, {}), '(__name__)', False, 'import logging\n'), ((55, 15, 55, 53), 'google_auth_httplib2.AuthorizedHttp', 'AuthorizedHttp', (), '', False, 'from google_auth_httplib2 import AuthorizedHttp\n'), ((58, 21, 58, 70), 'pygsheets.sheet.SheetAPIWrapper', 'SheetAPIWrapper', (), '', False, 'from pygsheets.sheet import SheetAPIWrapper\n'), ((59, 21, 59, 53), 'pygsheets.drive.DriveAPIWrapper', 'DriveAPIWrapper', ({(59, 37, 59, 41): 'http', (59, 43, 59, 52): 'data_path'}, {}), '(http, data_path)', False, 'from pygsheets.drive import DriveAPIWrapper\n'), ((71, 8, 71, 71), 'warnings.warn', 'warnings.warn', ({(71, 22, 71, 70): '"""Depricated  please use drive.enable_team_drive"""'}, {}), "('Depricated  please use drive.enable_team_drive')", False, 'import warnings\n'), ((56, 49, 56, 74), 'os.path.abspath', 'os.path.abspath', ({(56, 65, 56, 73): '__file__'}, {}), '(__file__)', False, 'import os\n'), ((120, 18, 120, 92), 'pygsheets.exceptions.SpreadsheetNotFound', 'SpreadsheetNotFound', ({(120, 38, 120, 91): "('Could not find a spreadsheet with title %s.' % title)"}, {}), "('Could not find a spreadsheet with title %s.' % title)", False, 'from pygsheets.exceptions import SpreadsheetNotFound, NoValidUrlKeyFound\n')]