from datetime import datetime, timedelta
from typing import Dict, List, Optional, Tuple

import gspread
from google.auth import default

from openhands.app_server.utils.logger import openhands_logger as logger


class GoogleSheetsClient:
    def __init__(self):
        """Initialize Google Sheets client using workload identity.
        Uses application default credentials which supports workload identity when running in GCP.
        """
        logger.info('Initializing Google Sheets client with workload identity')
        self.client = None
        self._cache: Dict[Tuple[str, str], Tuple[List[str], datetime]] = {}
        self._cache_ttl = timedelta(seconds=15)
        try:
            credentials, project = default(
                scopes=['https://www.googleapis.com/auth/spreadsheets.readonly']
            )
            logger.info(f'Successfully obtained credentials for project: {project}')
            self.client = gspread.authorize(credentials)
            logger.info('Successfully initialized Google Sheets API service')
        except Exception:
            logger.exception('Failed to initialize Google Sheets client')
            self.client = None

    def _get_from_cache(
        self, spreadsheet_id: str, range_name: str
    ) -> Optional[List[str]]:
        """Get usernames from cache if available and not expired.
        Args:
            spreadsheet_id: The ID of the Google Sheet
            range_name: The A1 notation of the range to fetch
        Returns:
            List of usernames if cache hit and not expired, None otherwise
        """
        cache_key = (spreadsheet_id, range_name)
        if cache_key not in self._cache:
            return None

        usernames, timestamp = self._cache[cache_key]
        if datetime.now() - timestamp > self._cache_ttl:
            logger.info('Cache expired, will fetch fresh data')
            return None

        logger.info(
            f'Using cached data from {timestamp.isoformat()} '
            f'({len(usernames)} usernames)'
        )
        return usernames

    def _update_cache(
        self, spreadsheet_id: str, range_name: str, usernames: List[str]
    ) -> None:
        """Update cache with new usernames and current timestamp.
        Args:
            spreadsheet_id: The ID of the Google Sheet
            range_name: The A1 notation of the range to fetch
            usernames: List of usernames to cache
        """
        cache_key = (spreadsheet_id, range_name)
        self._cache[cache_key] = (usernames, datetime.now())

    def get_usernames(self, spreadsheet_id: str, range_name: str = 'A:A') -> List[str]:
        """Get list of usernames from specified Google Sheet.
        Uses cached data if available and less than 15 seconds old.
        Args:
            spreadsheet_id: The ID of the Google Sheet
            range_name: The A1 notation of the range to fetch
        Returns:
            List of usernames from the sheet
        """
        if not self.client:
            logger.error('Google Sheets client not initialized')
            return []

        # Try to get from cache first
        cached_usernames = self._get_from_cache(spreadsheet_id, range_name)
        if cached_usernames is not None:
            return cached_usernames

        try:
            logger.info(
                f'Fetching usernames from sheet {spreadsheet_id}, range {range_name}'
            )
            spreadsheet = self.client.open_by_key(spreadsheet_id)
            worksheet = spreadsheet.sheet1  # Get first worksheet
            values = worksheet.get(range_name)

            usernames = [
                str(cell[0]).strip() for cell in values if cell and cell[0].strip()
            ]
            logger.info(
                f'Successfully fetched {len(usernames)} usernames from Google Sheet'
            )

            # Update cache with new data
            self._update_cache(spreadsheet_id, range_name, usernames)
            return usernames

        except gspread.exceptions.APIError:
            logger.exception(f'Error accessing Google Sheet {spreadsheet_id}')
            return []
        except Exception:
            logger.exception(
                f'Unexpected error accessing Google Sheet {spreadsheet_id}'
            )
            return []
