"""
Gmail API client for fetching and parsing Google Alerts emails
"""
import os
import base64
import re
from typing import List, Dict, Optional
from datetime import datetime
import logging

from google.auth.transport.requests import Request
from google.oauth2.credentials import Credentials
from google_auth_oauthlib.flow import InstalledAppFlow
from googleapiclient.discovery import build
from googleapiclient.errors import HttpError
from bs4 import BeautifulSoup

from .config import settings

# Configure logging
logger = logging.getLogger(__name__)

# Gmail API scopes
SCOPES = ['https://www.googleapis.com/auth/gmail.readonly']


class GmailClient:
    """Client for interacting with Gmail API."""

    def __init__(self):
        """Initialize Gmail client."""
        self.service = None
        self.credentials_path = settings.gmail_credentials_path
        self.token_path = settings.gmail_token_path

    def authenticate(self) -> bool:
        """
        Authenticate with Gmail API using OAuth2.

        Returns:
            True if authentication successful, False otherwise
        """
        try:
            creds = None

            # Load existing token
            if os.path.exists(self.token_path):
                creds = Credentials.from_authorized_user_file(self.token_path, SCOPES)
                logger.info("Loaded existing Gmail token")

            # Refresh or create new credentials
            if not creds or not creds.valid:
                if creds and creds.expired and creds.refresh_token:
                    logger.info("Refreshing expired Gmail token")
                    creds.refresh(Request())
                else:
                    if not os.path.exists(self.credentials_path):
                        logger.error(f"credentials.json not found at {self.credentials_path}")
                        return False

                    logger.info("Starting new OAuth flow")
                    flow = InstalledAppFlow.from_client_secrets_file(
                        self.credentials_path, SCOPES
                    )
                    creds = flow.run_local_server(port=0)

                # Save credentials
                with open(self.token_path, 'w') as token:
                    token.write(creds.to_json())
                logger.info("Saved new Gmail token")

            self.service = build('gmail', 'v1', credentials=creds)
            logger.info("Gmail authentication successful")
            return True

        except Exception as e:
            logger.error(f"Gmail authentication failed: {e}")
            return False

    def _get_email_body(self, payload: Dict) -> str:
        """
        Extract email body from MIME payload (recursive).

        Args:
            payload: Email payload from Gmail API

        Returns:
            Email body as HTML string
        """
        if 'parts' in payload:
            for part in payload['parts']:
                if part['mimeType'] == 'text/html':
                    data = part['body'].get('data', '')
                    if data:
                        return base64.urlsafe_b64decode(data).decode('utf-8', errors='ignore')
                elif part['mimeType'] == 'text/plain':
                    data = part['body'].get('data', '')
                    if data:
                        return base64.urlsafe_b64decode(data).decode('utf-8', errors='ignore')
                elif 'parts' in part:
                    result = self._get_email_body(part)
                    if result:
                        return result

        elif payload.get('mimeType') in ['text/html', 'text/plain']:
            data = payload['body'].get('data', '')
            if data:
                return base64.urlsafe_b64decode(data).decode('utf-8', errors='ignore')

        return ''

    def _parse_alert_items(self, html_body: str, email_date: str) -> List[Dict]:
        """
        Parse alert items from HTML body.

        Args:
            html_body: HTML content of email
            email_date: Date of email

        Returns:
            List of alert items with title, source, link, date
        """
        soup = BeautifulSoup(html_body, 'html.parser')
        items = []

        # Try multiple selector strategies
        selectors = [
            ('table[role="article"]', 'tr'),
            ('div[class*="alert"]', 'div'),
            ('table', 'tr'),
        ]

        containers = []
        for container_selector, item_selector in selectors:
            containers = soup.find_all(container_selector)
            if containers:
                logger.debug(f"Using selector: {container_selector}")
                break

        # Parse items
        for container in containers[:5]:  # Max 5 containers per email
            item_elements = container.find_all(item_selector)

            for elem in item_elements:
                # Find link/title
                link_elem = elem.find('a', href=True)
                if not link_elem:
                    continue

                title = link_elem.get_text(strip=True)
                link = link_elem['href']

                # Clean Google redirect
                if 'google.com/url?q=' in link:
                    match = re.search(r'q=(https?://[^&]+)', link)
                    link = match.group(1) if match else link_elem['href']

                # Find source
                source_elem = (
                    elem.find('font', color=True) or
                    elem.find('span', class_=re.compile(r'source|cite'))
                )
                source = source_elem.get_text(strip=True) if source_elem else 'Fonte desconhecida'

                # Check if Reclame Aqui
                is_reclameaqui = 'reclameaqui.com.br' in link.lower()

                if title and len(title) > 10:  # Filter very short titles
                    items.append({
                        'title': title,
                        'source': source,
                        'link': link,
                        'date': email_date,
                        'is_reclameaqui': is_reclameaqui,
                        'priority': 'HIGH' if is_reclameaqui else 'NORMAL'
                    })

        return items

    def fetch_alerts(self, num_emails: Optional[int] = None) -> List[Dict]:
        """
        Fetch and parse Google Alerts emails.

        Args:
            num_emails: Number of emails to fetch (defaults to settings)

        Returns:
            List of dictionaries containing email data and parsed alerts
        """
        if not self.service:
            logger.error("Gmail service not initialized. Call authenticate() first.")
            return []

        num_emails = num_emails or settings.num_emails
        logger.info(f"Fetching {num_emails} emails from {settings.alerts_sender}")

        try:
            # Query Gmail
            query = f'from:{settings.alerts_sender}'
            results = self.service.users().messages().list(
                userId='me',
                q=query,
                maxResults=num_emails
            ).execute()

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

            if not messages:
                logger.warning("No Google Alerts emails found")
                return []

            logger.info(f"Found {len(messages)} emails")

            alerts_data = []
            for idx, msg in enumerate(messages, 1):
                logger.info(f"Processing email {idx}/{len(messages)}")

                # Fetch email details
                msg_data = self.service.users().messages().get(
                    userId='me',
                    id=msg['id'],
                    format='full'
                ).execute()

                # Extract headers
                headers = {h['name']: h['value'] for h in msg_data['payload']['headers']}
                subject = headers.get('Subject', 'No subject')
                date_str = headers.get('Date', '')

                # Extract body
                body = self._get_email_body(msg_data['payload'])

                if not body:
                    logger.warning(f"Email {idx} has empty body")
                    continue

                # Parse alerts
                items = self._parse_alert_items(body, date_str)

                if items:
                    alerts_data.append({
                        'subject': subject,
                        'date': date_str,
                        'items': items
                    })
                    logger.info(f"Extracted {len(items)} alerts from email {idx}")

            total_items = sum(len(a['items']) for a in alerts_data)
            logger.info(f"Total: {total_items} alerts from {len(alerts_data)} emails")

            return alerts_data

        except HttpError as error:
            logger.error(f"Gmail API error: {error}")
            return []
        except Exception as e:
            logger.error(f"Unexpected error fetching alerts: {e}")
            return []

    def get_reclameaqui_urls(self, alerts_data: List[Dict]) -> List[str]:
        """
        Extract Reclame Aqui URLs from alerts data.

        Args:
            alerts_data: List of alerts data

        Returns:
            List of Reclame Aqui URLs
        """
        urls = []
        for alert in alerts_data:
            for item in alert['items']:
                if item.get('is_reclameaqui', False):
                    urls.append(item['link'])

        logger.info(f"Found {len(urls)} Reclame Aqui URLs")
        return urls
