"""
Google Sheets API helpers.

Enable the Sheets API in your project:
  https://console.cloud.google.com/flows/enableapi?apiid=sheets.googleapis.com

Note: The service account must have access to the target spreadsheets.
      Share spreadsheets with the service account email.
"""

from __future__ import annotations

import logging
from typing import Any

from googleapiclient.discovery import build
from googleapiclient.errors import HttpError

from ._auth import get_credentials

logger = logging.getLogger(__name__)

SCOPES_READONLY = ["https://www.googleapis.com/auth/spreadsheets.readonly"]
SCOPES_READWRITE = ["https://www.googleapis.com/auth/spreadsheets"]
API_NAME = "sheets"
API_VERSION = "v4"


def gsheet_get_service(
    *,
    path_keyfile: str | None = None,
    keyfile_json: dict | None = None,
    credentials: Any | None = None,
    readonly: bool = True,
    scopes: list[str] | None = None,
):
    """
    Build a Google Sheets API v4 service object.

    Credential priority:
      1) ``credentials``   — pre-resolved credentials object (e.g. from toolsbq)
      2) ``keyfile_json``  — SA key as dict
      3) ``path_keyfile``  — path to SA JSON file
      4) RAM-ADC / env / ADC fallback

    Args:
        path_keyfile:  Path to a service account JSON key file.
        keyfile_json:  Parsed service account JSON as dict.
        credentials:   Pre-resolved google credentials object.
        readonly:      If True (default), use read-only scope. Set False for write access.
        scopes:        Override default scopes (overrides readonly flag).

    Returns:
        A Google Sheets v4 service object.
    """
    if scopes is None:
        scopes = SCOPES_READONLY if readonly else SCOPES_READWRITE

    creds = get_credentials(
        path_keyfile=path_keyfile,
        keyfile_json=keyfile_json,
        credentials=credentials,
        scopes=scopes,
    )
    return build(API_NAME, API_VERSION, credentials=creds)


def list_sheet_names(service, spreadsheet_id: str) -> list[str]:
    """
    Get all sheet (tab) names in a spreadsheet.

    Args:
        service:         Sheets API service object (from gsheet_get_service).
        spreadsheet_id:  The spreadsheet ID (from the URL).

    Returns:
        List of sheet name strings.
    """
    try:
        result = (
            service.spreadsheets()
            .get(
                spreadsheetId=spreadsheet_id,
                fields="sheets(properties(sheetId,title))",
            )
            .execute()
        )
        return [s["properties"]["title"] for s in result.get("sheets", [])]
    except HttpError as error:
        logger.error("An error occurred: %s", error)
        return []


def read_sheet(
    service,
    spreadsheet_id: str,
    sheet_range: str = "Sheet1",
) -> list[list]:
    """
    Read data from a single sheet range.

    Args:
        service:         Sheets API service object.
        spreadsheet_id:  The spreadsheet ID.
        sheet_range:     Range in A1 notation, e.g. "Sheet1!A1:Z100" or just "Sheet1".

    Returns:
        List of rows (each row is a list of cell values). Empty list on error.
    """
    try:
        result = (
            service.spreadsheets()
            .values()
            .get(spreadsheetId=spreadsheet_id, range=sheet_range)
            .execute()
        )
        return result.get("values", [])
    except HttpError as error:
        logger.error("An error occurred: %s", error)
        return []


def read_sheet_as_dicts(
    service,
    spreadsheet_id: str,
    sheet_range: str = "Sheet1",
) -> list[dict]:
    """
    Read data from a sheet and return as list of dicts (first row = headers).

    Args:
        service:         Sheets API service object.
        spreadsheet_id:  The spreadsheet ID.
        sheet_range:     Range in A1 notation.

    Returns:
        List of dicts keyed by header names. Empty list if no data or on error.
    """
    rows = read_sheet(service, spreadsheet_id, sheet_range)
    if len(rows) < 2:
        return []

    headers = rows[0]
    result = []
    for row in rows[1:]:
        padded = row + [None] * (len(headers) - len(row))
        result.append(dict(zip(headers, padded)))
    return result


def read_all_sheets(
    service,
    spreadsheet_id: str,
    sheet_range_data: str = "A1:AZ1000",
) -> dict[str, list[list]]:
    """
    Read all sheets in a spreadsheet and return as a dict.

    Args:
        service:           Sheets API service object.
        spreadsheet_id:    The spreadsheet ID.
        sheet_range_data:  Range to read from each sheet (e.g. "A1:Z100").

    Returns:
        Dict mapping sheet name -> list of rows.
    """
    sheet_names = list_sheet_names(service, spreadsheet_id)
    result: dict[str, list[list]] = {}

    for name in sheet_names:
        full_range = "{}!{}".format(name, sheet_range_data)
        result[name] = read_sheet(service, spreadsheet_id, full_range)

    return result
