# AUTOGENERATED! DO NOT EDIT! File to edit: ../../nbs/google/GSheet.ipynb.

# %% auto 0
__all__ = ['get_spreadsheet_by_id', 'get_sheets', 'get_sheet_values_df', 'find_row', 'append_rows', 'insert_rows', 'replace_row',
           'GSheet', 'GSpreadsheet']

# %% ../../nbs/google/GSheet.ipynb 1
from dataclasses import dataclass, field
from typing import Any, List, Tuple

import pandas as pd

import domolibrary_extensions.google.GAuth as ga

# %% ../../nbs/google/GSheet.ipynb 4
def get_spreadsheet_by_id(spreadsheet_id, service):
    return (
        service.spreadsheets()
        # .values()
        .get(spreadsheetId=spreadsheet_id).execute()
    )


def get_sheets(spreadsheet_id=None, service=None, spreadsheet=None):
    spreadsheet = (
        spreadsheet
        or service.spreadsheets().get(spreadsheetId=spreadsheet_id).execute()
    )

    return spreadsheet.get("sheets")

# %% ../../nbs/google/GSheet.ipynb 6
def _data_to_df(data):
    rows = data["values"]
    cols = data["values"].pop(0)

    return pd.DataFrame(columns=cols, data=rows)


def get_sheet_values_df(sheet_title, spreadsheet_id, service, return_raw: bool = False):
    data = (
        service.spreadsheets()
        .values()
        .get(spreadsheetId=spreadsheet_id, range=sheet_title)
        .execute()
    )

    if return_raw:
        return data

    return _data_to_df(data)


def find_row(
    sheet_title, spreadsheet_id, service, col_idx, search_val
) -> Tuple[
    int, List[Any]
]:  # tuple with index of row and row value, returns (-1, None) if row not found in data

    data = get_sheet_values_df(
        sheet_title=sheet_title,
        spreadsheet_id=spreadsheet_id,
        service=service,
        return_raw=True,
    )["values"]

    return next(
        ((idx, ele) for idx, ele in enumerate(data) if ele[col_idx] == search_val),
        (-1, None),
    )

# %% ../../nbs/google/GSheet.ipynb 8
def _to_excel(data_ls, delimiter):
    def _convert_rows(row_ls, delimiter):
        return delimiter.join([str(val) for val in row_ls])

    if not isinstance(data_ls[0], list):
        return _convert_rows(data_ls, delimiter)

    return "\n".join([_convert_rows(row_ls, delimiter) for row_ls in data_ls])

# %% ../../nbs/google/GSheet.ipynb 9
def append_rows(
    service,
    spreadsheet_id,
    sheet_title,
    data_ls: List[List[Any]],
    input_option="USER_ENTERED",
):
    return (
        service.spreadsheets()
        .values()
        .append(
            spreadsheetId=spreadsheet_id,
            range=sheet_title,
            body={"majorDimension": "ROWS", "values": data_ls},
            valueInputOption=input_option,
        )
        .execute()
    )


def insert_rows(
    sheet_id,
    service,
    spreadsheet_id,
    insert_row_idx,
    data_ls: List[Any],
    delimiter=";",
):
    batch_update_spreadsheet_request_body = {
        "requests": [
            {
                "insertRange": {
                    "range": {
                        "sheetId": sheet_id,
                        "startRowIndex": insert_row_idx,
                        "endRowIndex": insert_row_idx + len(data_ls),
                    },
                    "shiftDimension": "ROWS",
                }
            },
            {
                "pasteData": {
                    "data": _to_excel(data_ls, delimiter),
                    "type": "PASTE_NORMAL",
                    "delimiter": delimiter,
                    "coordinate": {"sheetId": sheet_id, "rowIndex": insert_row_idx},
                }
            },
        ]
    }

    request = service.spreadsheets().batchUpdate(
        spreadsheetId=spreadsheet_id, body=batch_update_spreadsheet_request_body
    )
    return request.execute()


def replace_row(
    sheet_id,
    spreadsheet_id,
    service,
    row_idx,
    row_ls,
    delimiter=";",
):
    batch_update_spreadsheet_request_body = {
        "requests": [
            {
                "pasteData": {
                    "data": _to_excel(row_ls, delimiter),
                    "type": "PASTE_NORMAL",
                    "delimiter": delimiter,
                    "coordinate": {"sheetId": sheet_id, "rowIndex": row_idx},
                }
            }
        ]
    }

    request = service.spreadsheets().batchUpdate(
        spreadsheetId=spreadsheet_id, body=batch_update_spreadsheet_request_body
    )
    return request.execute()

# %% ../../nbs/google/GSheet.ipynb 12
@dataclass
class GSheet:
    id: int
    title: str
    index: int

    service: Any
    spreadsheet_id: str

    data: List[List[Any]] = None
    df: pd.DataFrame = None

    @classmethod
    def _from_json(cls, obj, service, spreadsheet_id):
        obj = obj["properties"]
        return cls(
            spreadsheet_id=spreadsheet_id,
            service=service,
            id=obj["sheetId"],
            title=obj["title"],
            index=obj["index"],
        )

    def get_data(self, return_raw: bool = False) -> pd.DataFrame:
        self.data = get_sheet_values_df(
            sheet_title=self.title,
            spreadsheet_id=self.spreadsheet_id,
            service=self.service,
            return_raw=True,
        )

        if return_raw:
            return self.data

        self.df = _data_to_df(self.data)
        return self.df

    def append_rows(self, data_ls: List[List[Any]], input_option="USER_ENTERED"):
        append_rows(
            service=self.service,
            spreadsheet_id=self.spreadsheet_id,
            sheet_title=self.title,
            data_ls=data_ls,
            input_option=input_option,
        )

        self.get_data()

    def _find_row(self, col_idx, search_val):
        return find_row(
            sheet_title=self.title,
            spreadsheet_id=self.spreadsheet_id,
            service=self.service,
            col_idx=col_idx,
            search_val=search_val,
        )

    def _replace_row(self, row_idx, row_ls, delimiter=";"):
        return replace_row(
            sheet_id=self.id,
            spreadsheet_id=self.spreadsheet_id,
            service=self.service,
            row_idx=row_idx,
            row_ls=row_ls,
            delimiter=delimiter,
        )

    def update_row(self, col_idx, search_val, new_row_ls, delimiter=";"):
        row_idx = self._find_row(col_idx=col_idx, search_val=search_val)[0]

        if row_idx == -1:
            self.append_rows([new_row_ls])

        else:
            self._replace_row(row_idx, new_row_ls, delimiter)

        return self.get_data()


@dataclass
class GSpreadsheet:
    id: str
    spreadsheet: Any = field(repr=False)
    service: Any = field(repr=False)

    auth: Any = field(default=None, repr=False)

    gsheets: List[dict] = None

    def __post_init__(self):
        self.get_sheets()

    @classmethod
    def get_by_id(
        cls, spreadsheet_id, service=None, auth=None, return_raw: bool = False
    ):

        require_base_url = "https://sheets.googleapis.com/"

        if not auth and not service:
            raise ga.GAuth_Required()

        if not service or service._baseUrl != require_base_url:
            if not auth:
                raise ga.GAuth_Required()

            service = auth.generate_service("sheets", "v4")

        spreadsheet = get_spreadsheet_by_id(
            service=service, spreadsheet_id=spreadsheet_id
        )

        if return_raw:
            return spreadsheet

        return cls(
            auth=auth,
            service=service,
            id=spreadsheet_id,
            spreadsheet=spreadsheet,
        )

    def get_sheets(self, return_raw: bool = False):
        sheets = get_sheets(spreadsheet=self.spreadsheet)

        if return_raw:
            return sheets

        self.gsheets = [
            GSheet._from_json(obj, service=self.service, spreadsheet_id=self.id)
            for obj in sheets
        ]
        return self.gsheets
