import os
import logging

from google.oauth2 import service_account
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import Flow
from google.auth.transport.requests import Request
from googleapiclient.discovery import build
from googleapiclient.http import MediaFileUpload
from googleapiclient.errors import HttpError

SCOPES = ["https://www.googleapis.com/auth/drive.file"]

# Set up logging
logger = logging.getLogger(__name__)


def authenticate(service_account_file):
    """Authenticate using service account (for Google Workspace)."""
    creds = service_account.Credentials.from_service_account_file(
        service_account_file, scopes=SCOPES
    )
    return creds


def authenticate_oauth(client_id, client_secret, refresh_token=None):
    """Authenticate using OAuth 2.0 (for personal and business accounts)."""
    if refresh_token:
        # Use existing refresh token
        creds = Credentials(
            token=None,
            refresh_token=refresh_token,
            token_uri="https://oauth2.googleapis.com/token",
            client_id=client_id,
            client_secret=client_secret,
            scopes=SCOPES
        )
        
        # Refresh the access token
        creds.refresh(Request())
        return creds
    else:
        raise ValueError("No refresh token provided. Please complete OAuth flow first.")


def create_oauth_flow(client_id, client_secret, redirect_uri):
    """Create OAuth flow for initial authentication."""
    flow = Flow.from_client_config(
        {
            "web": {
                "client_id": client_id,
                "client_secret": client_secret,
                "auth_uri": "https://accounts.google.com/o/oauth2/auth",
                "token_uri": "https://oauth2.googleapis.com/token",
                "redirect_uris": [redirect_uri]
            }
        },
        scopes=SCOPES
    )
    flow.redirect_uri = redirect_uri
    return flow


def get_oauth_authorization_url(flow):
    """Get the authorization URL for OAuth flow."""
    authorization_url, state = flow.authorization_url(
        access_type='offline',
        include_granted_scopes='true'
    )
    return authorization_url, state


def exchange_oauth_code(flow, code):
    """Exchange authorization code for tokens."""
    flow.fetch_token(code=code)
    credentials = flow.credentials
    
    return {
        'access_token': credentials.token,
        'refresh_token': credentials.refresh_token,
        'expires_in': credentials.expiry.timestamp() if credentials.expiry else None
    }


def upload_file(file_path, parent_folder_id, auth_method='service_account', **auth_params):
    """
    Upload file to Google Drive using either service account or OAuth authentication.
    
    Args:
        file_path (str): Path to the file to upload
        parent_folder_id (str): Google Drive folder ID where file will be uploaded
        auth_method (str): Either 'service_account' or 'oauth'
        **auth_params: Authentication parameters based on method:
            - For service_account: service_account_file
            - For oauth: client_id, client_secret, refresh_token
    """
    try:
        if auth_method == 'service_account':
            service_account_file = auth_params.get('service_account_file')
            if not service_account_file:
                raise ValueError("service_account_file is required for service account authentication")
            creds = authenticate(service_account_file)
            
        elif auth_method == 'oauth':
            client_id = auth_params.get('client_id')
            client_secret = auth_params.get('client_secret')
            refresh_token = auth_params.get('refresh_token')
            
            if not all([client_id, client_secret, refresh_token]):
                raise ValueError("client_id, client_secret, and refresh_token are required for OAuth authentication")
            
            creds = authenticate_oauth(client_id, client_secret, refresh_token)
        else:
            raise ValueError(f"Invalid auth_method: {auth_method}")
        
        service = build("drive", "v3", credentials=creds)
        
        file_metadata = {"name": os.path.basename(file_path), "parents": [parent_folder_id]}
        media = MediaFileUpload(file_path, resumable=True)
        file = (
            service.files()
            .create(body=file_metadata, media_body=media, fields="id")
            .execute()
        )
        
        logger.info(f"Successfully uploaded {file_path} to Google Drive with ID: {file.get('id')} using {auth_method}")
        return file.get('id')
        
    except HttpError as e:
        error_details = e.error_details[0] if e.error_details else {}
        error_reason = error_details.get('reason', 'unknown')
        
        if error_reason == 'storageQuotaExceeded' and auth_method == 'service_account':
            logger.error(f"Google Drive upload failed: Service accounts cannot upload to personal Google Drive accounts. Error: {e}")
            raise Exception("Service accounts cannot upload to personal Google Drive accounts. "
                          "Switch to OAuth authentication for personal accounts.")
        else:
            logger.error(f"Google Drive upload failed with HttpError: {e}")
            raise Exception(f"Google Drive API error: {e}")
            
    except Exception as e:
        logger.error(f"Unexpected error during Google Drive upload: {e}")
        raise Exception(f"Upload failed: {e}")


# Legacy function for backward compatibility
def upload_file_legacy(file_path, service_account_file, parent_folder_id):
    """Legacy upload function for backward compatibility."""
    return upload_file(file_path, parent_folder_id, 'service_account', service_account_file=service_account_file)


def validate_shared_drive_access(service_account_file, folder_id):
    """
    Validate Google Drive access for service accounts.
    
    Args:
        service_account_file (str): Path to service account JSON file
        folder_id (str): Google Drive folder ID
        
    Returns:
        dict: Validation result with success status, message, and folder info
    """
    try:
        creds = authenticate(service_account_file)
        service = build("drive", "v3", credentials=creds)
        
        # Try to get folder information
        folder_info = service.files().get(fileId=folder_id, fields="id,name,parents,driveId").execute()
        folder_name = folder_info.get("name", "Unknown")
        
        # Check if it's in a shared drive
        if folder_info.get('driveId'):
            return {
                'success': True,
                'message': f'Valid Shared Drive folder: "{folder_name}"',
                'is_shared_drive': True
            }
        else:
            return {
                'success': False,
                'message': f'ERROR: "{folder_name}" is in a personal Google Drive account. '
                         f'Service accounts cannot upload to personal Google Drive folders. '
                         f'You need a Google Workspace account with Shared Drives, '
                         f'or use OAuth authentication instead of a service account.',
                'is_shared_drive': False
            }
            
    except HttpError as e:
        if e.resp.status == 404:
            return {
                'success': False,
                'message': 'Folder not found or service account does not have access to it.',
                'is_shared_drive': None
            }
        elif e.resp.status == 403:
            return {
                'success': False,
                'message': 'Access denied. If using personal Google Drive, service accounts are not supported.',
                'is_shared_drive': None
            }
        else:
            return {
                'success': False,
                'message': f'Error validating folder: {e}',
                'is_shared_drive': None
            }
    except Exception as e:
        return {
            'success': False,
            'message': f'Unexpected error: {e}',
            'is_shared_drive': None
        }


def validate_oauth_folder_access(client_id, client_secret, refresh_token, folder_id):
    """
    Validate Google Drive folder access using OAuth authentication.
    
    Args:
        client_id (str): OAuth client ID
        client_secret (str): OAuth client secret  
        refresh_token (str): OAuth refresh token
        folder_id (str): Google Drive folder ID
        
    Returns:
        dict: Validation result with success status and message
    """
    try:
        if not refresh_token:
            return {
                'success': False,
                'message': 'OAuth not authorized yet. Please complete OAuth authorization first.',
                'folder_accessible': False
            }
        
        creds = authenticate_oauth(client_id, client_secret, refresh_token)
        service = build("drive", "v3", credentials=creds)
        
        # Try to get folder information
        folder_info = service.files().get(fileId=folder_id, fields="id,name,parents").execute()
        folder_name = folder_info.get("name", "Unknown")
        
        return {
            'success': True,
            'message': f'OAuth access to folder "{folder_name}" verified successfully.',
            'folder_accessible': True
        }
        
    except HttpError as e:
        if e.resp.status == 404:
            return {
                'success': False,
                'message': 'Folder not found. Please check the folder ID and make sure it exists.',
                'folder_accessible': False
            }
        elif e.resp.status == 403:
            return {
                'success': False,
                'message': 'Access denied to folder. Please make sure you have permission to access this folder.',
                'folder_accessible': False
            }
        else:
            return {
                'success': False,
                'message': f'Error accessing folder: {e}',
                'folder_accessible': False
            }
    except Exception as e:
        logger.error(f"OAuth folder validation error: {e}")
        return {
            'success': False,
            'message': f'Validation error: {e}',
            'folder_accessible': False
        }


def validate_folder_access(auth_method, folder_id, **auth_params):
    """
    Universal folder validation function that works with both auth methods.
    
    Args:
        auth_method (str): Either 'service_account' or 'oauth'
        folder_id (str): Google Drive folder ID
        **auth_params: Authentication parameters based on method
        
    Returns:
        dict: Validation result
    """
    if auth_method == 'service_account':
        service_account_file = auth_params.get('service_account_file')
        if not service_account_file:
            return {
                'success': False,
                'message': 'Service account file is required for service account validation.'
            }
        return validate_shared_drive_access(service_account_file, folder_id)
        
    elif auth_method == 'oauth':
        client_id = auth_params.get('client_id')
        client_secret = auth_params.get('client_secret')
        refresh_token = auth_params.get('refresh_token')
        
        if not client_id or not client_secret:
            return {
                'success': False,
                'message': 'OAuth client credentials are required for OAuth validation.'
            }
        
        return validate_oauth_folder_access(client_id, client_secret, refresh_token, folder_id)
    else:
        return {
            'success': False,
            'message': f'Unknown authentication method: {auth_method}'
        }

