"""Gmail API provider implementation.

IMPORTANT: This is a STUB implementation.
- Requires valid Gmail OAuth credentials
- Credentials file should be provided in config or via command line
- When credentials are not available, this provider will raise clear errors
- Mock provider is available for testing without credentials
"""
import base64
import logging
from typing import List, Dict, Optional, Any
from datetime import datetime
from email.utils import parsedate_to_datetime

from .base import BaseProvider, Email, Attachment

logger = logging.getLogger(__name__)


class GmailProvider(BaseProvider):
    """
    Gmail API email provider.

    STUB STATUS: Requires Gmail OAuth credentials setup
    - Credentials file: credentials.json
    - Scopes: gmail.readonly, gmail.modify
    - When credentials missing: Provider will fail gracefully with clear error
    """

    def __init__(self):
        """Initialize Gmail provider."""
        super().__init__(name="gmail")
        self.service = None
        self.user_id = 'me'
        self._credentials_configured = False

    def connect(self, credentials: Dict[str, Any]) -> bool:
        """
        Connect to Gmail API using OAuth credentials.

        STUB: This requires credentials setup. When unavailable:
        - Returns False
        - Logs clear error message
        - Does not attempt connection
        """
        try:
            credentials_path = credentials.get('credentials_path')
            if not credentials_path:
                logger.error(
                    "GMAIL OAUTH NOT CONFIGURED: "
                    "credentials_path required in config. "
                    "Set up Gmail OAuth at: "
                    "https://developers.google.com/gmail/api/quickstart/python"
                )
                return False

            # TRY IMPORT - will fail if google-auth not installed properly
            try:
                from google.oauth2.credentials import Credentials
                from google_auth_oauthlib.flow import InstalledAppFlow
                from googleapiclient.discovery import build
            except ImportError as e:
                logger.error(f"GMAIL DEPENDENCIES MISSING: {e}")
                logger.error("Install with: pip install google-api-python-client google-auth-oauthlib")
                return False

            # TRY CONNECTION - will fail if credentials file invalid
            logger.info(f"Attempting Gmail OAuth with credentials from: {credentials_path}")

            SCOPES = [
                'https://www.googleapis.com/auth/gmail.readonly',
                'https://www.googleapis.com/auth/gmail.modify'
            ]

            try:
                flow = InstalledAppFlow.from_client_secrets_file(
                    credentials_path, SCOPES
                )
                creds = flow.run_local_server(port=0)
                self.service = build('gmail', 'v1', credentials=creds)
                self._credentials_configured = True
                logger.info("Successfully connected to Gmail API")
                return True

            except FileNotFoundError:
                logger.error(f"CREDENTIALS FILE NOT FOUND: {credentials_path}")
                logger.error("Set up Gmail OAuth and download credentials.json")
                return False

        except Exception as e:
            logger.error(f"GMAIL CONNECTION FAILED: {e}")
            return False

    def disconnect(self) -> bool:
        """Close Gmail connection."""
        self.service = None
        self._credentials_configured = False
        logger.info("Disconnected from Gmail")
        return True

    def fetch_emails(
        self,
        limit: Optional[int] = None,
        filters: Optional[Dict[str, Any]] = None
    ) -> List[Email]:
        """
        Fetch emails from Gmail.

        STUB: Returns empty list if not connected
        """
        if not self._credentials_configured or not self.service:
            logger.error("GMAIL NOT CONFIGURED: Cannot fetch emails without OAuth setup")
            return []

        emails = []
        try:
            query = filters.get('query', '') if filters else ''

            results = self.service.users().messages().list(
                userId=self.user_id,
                q=query,
                maxResults=min(limit or 500, 500) if limit else 500
            ).execute()

            messages = results.get('messages', [])

            for msg_info in messages:
                email = self._fetch_message(msg_info['id'])
                if email:
                    emails.append(email)
                    if limit and len(emails) >= limit:
                        break

            logger.info(f"Fetched {len(emails)} emails from Gmail")
            return emails

        except Exception as e:
            logger.error(f"GMAIL FETCH ERROR: {e}")
            return emails

    def _fetch_message(self, msg_id: str) -> Optional[Email]:
        """Fetch and parse a single message."""
        try:
            msg = self.service.users().messages().get(
                userId=self.user_id,
                id=msg_id,
                format='full'
            ).execute()
            return self._parse_message(msg)
        except Exception as e:
            logger.error(f"Error fetching message {msg_id}: {e}")
            return None

    def _parse_message(self, msg: Dict) -> Email:
        """Parse Gmail message into Email object."""
        headers = {h['name']: h['value'] for h in msg['payload'].get('headers', [])}

        body = self._get_body(msg['payload'])
        date = self._parse_date(headers.get('Date'))

        # Check attachments
        attachments = self._parse_attachments(msg['payload'])

        return Email(
            id=msg['id'],
            subject=headers.get('Subject', 'No Subject'),
            sender=headers.get('From', ''),
            date=date,
            body=body,
            has_attachments=len(attachments) > 0,
            attachments=attachments,
            headers=headers,
            labels=msg.get('labelIds', []),
            is_read='UNREAD' not in msg.get('labelIds', []),
            provider='gmail'
        )

    def _get_body(self, payload: Dict) -> str:
        """Extract email body from payload."""
        body = ""

        if 'body' in payload and 'data' in payload['body']:
            try:
                body = base64.urlsafe_b64decode(payload['body']['data']).decode('utf-8', errors='ignore')
            except Exception as e:
                logger.debug(f"Error decoding body: {e}")

        elif 'parts' in payload:
            for part in payload['parts']:
                if part.get('mimeType') == 'text/plain' and 'data' in part.get('body', {}):
                    try:
                        body = base64.urlsafe_b64decode(part['body']['data']).decode('utf-8', errors='ignore')
                        break
                    except Exception as e:
                        logger.debug(f"Error decoding part: {e}")

        return body

    def _parse_date(self, date_str: Optional[str]) -> Optional[datetime]:
        """Parse email date."""
        if not date_str:
            return None
        try:
            return parsedate_to_datetime(date_str)
        except Exception:
            return None

    def _parse_attachments(self, payload: Dict) -> List[Attachment]:
        """Extract attachment metadata."""
        attachments = []

        if 'parts' not in payload:
            return attachments

        for part in payload['parts']:
            if part.get('filename'):
                attachments.append(Attachment(
                    filename=part['filename'],
                    mime_type=part.get('mimeType', 'application/octet-stream'),
                    size=part.get('body', {}).get('size', 0),
                    attachment_id=part.get('body', {}).get('attachmentId')
                ))

        return attachments

    def update_labels(self, email_id: str, labels: List[str]) -> bool:
        """Update labels for a single email."""
        if not self._credentials_configured or not self.service:
            logger.error("GMAIL NOT CONFIGURED: Cannot update labels")
            return False

        try:
            self.service.users().messages().modify(
                userId=self.user_id,
                id=email_id,
                body={'addLabelIds': labels}
            ).execute()
            return True
        except Exception as e:
            logger.error(f"Error updating labels: {e}")
            return False

    def batch_update(self, updates: List[Dict[str, Any]]) -> bool:
        """Batch update multiple emails."""
        if not self._credentials_configured or not self.service:
            logger.error("GMAIL NOT CONFIGURED: Cannot batch update")
            return False

        try:
            batch_size = 100
            successful = 0

            for i in range(0, len(updates), batch_size):
                batch = updates[i:i+batch_size]
                email_ids = [u['email_id'] for u in batch]
                labels = list(set([l for u in batch for l in u.get('labels', [])]))

                self.service.users().messages().batchModify(
                    userId=self.user_id,
                    body={
                        'ids': email_ids,
                        'addLabelIds': labels
                    }
                ).execute()
                successful += len(batch)

            logger.info(f"Batch updated {successful} emails")
            return True

        except Exception as e:
            logger.error(f"Batch update error: {e}")
            return False

    def is_connected(self) -> bool:
        """Check if connected."""
        return self._credentials_configured and self.service is not None
