"""IMAP email provider implementation.

STUB STATUS: Requires IMAP server credentials
- Supports any IMAP server (Gmail, Outlook, custom, etc.)
- Credentials: host, username, password, port
- When credentials missing: Provider will fail gracefully
"""
import logging
from email import message_from_bytes
from email.message import Message
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 IMAPProvider(BaseProvider):
    """
    IMAP email provider for generic IMAP servers.

    STUB STATUS: Requires IMAP server configuration
    - Can use with Gmail, Outlook, or any IMAP server
    - Credentials required: host, username, password, port (optional)
    - When credentials missing: Returns clear error
    """

    def __init__(self):
        """Initialize IMAP provider."""
        super().__init__(name="imap")
        self.client = None
        self._credentials_configured = False
        self.host = None
        self.username = None

    def connect(self, credentials: Dict[str, Any]) -> bool:
        """
        Connect to IMAP server.

        STUB: Requires credentials. When unavailable:
        - Returns False with clear error
        """
        try:
            self.host = credentials.get('host')
            self.username = credentials.get('username')
            password = credentials.get('password')
            port = credentials.get('port', 993)

            if not all([self.host, self.username, password]):
                logger.error(
                    "IMAP NOT CONFIGURED: "
                    "Required: host, username, password"
                )
                return False

            try:
                import imapclient
            except ImportError:
                logger.error("IMAP DEPENDENCIES MISSING: pip install imapclient")
                return False

            logger.info(f"Attempting IMAP connection to {self.host}")

            try:
                self.client = imapclient.IMAPClient(self.host, port=port, use_uid=True)
                self.client.login(self.username, password)
                self._credentials_configured = True
                logger.info(f"Successfully connected to IMAP server: {self.host}")
                return True

            except Exception as e:
                logger.error(f"IMAP LOGIN FAILED: {e}")
                logger.error("Check credentials and IMAP server configuration")
                return False

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

    def disconnect(self) -> bool:
        """Close IMAP connection."""
        if self.client:
            try:
                self.client.logout()
            except Exception as e:
                logger.warning(f"Error during logout: {e}")
        self.client = None
        self._credentials_configured = False
        logger.info("Disconnected from IMAP server")
        return True

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

        STUB: Returns empty if not connected
        """
        if not self._credentials_configured or not self.client:
            logger.error("IMAP NOT CONFIGURED: Cannot fetch emails")
            return []

        emails = []
        try:
            # Select INBOX
            self.client.select_folder('INBOX')

            # Search for messages
            search_criteria = filters.get('search_criteria', 'ALL') if filters else 'ALL'
            msg_ids = self.client.search(search_criteria)

            # Limit results
            if limit:
                msg_ids = msg_ids[:limit]

            logger.info(f"Found {len(msg_ids)} messages in IMAP, fetching...")

            # Fetch messages
            response = self.client.fetch(msg_ids, ['RFC822'])

            for msg_id, msg_data in response.items():
                try:
                    email_msg = email.message_from_bytes(msg_data[b'RFC822'])
                    parsed_email = self._parse_message(email_msg, msg_id)
                    if parsed_email:
                        emails.append(parsed_email)
                except Exception as e:
                    logger.debug(f"Error parsing message {msg_id}: {e}")

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

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

    def _parse_message(self, msg: Message, msg_id: int) -> Optional[Email]:
        """Parse email.message.Message into Email object."""
        try:
            subject = msg.get('subject', 'No Subject')
            sender = msg.get('from', '')
            date_str = msg.get('date')
            body = self._get_body(msg)

            # Parse date
            date = None
            if date_str:
                try:
                    date = parsedate_to_datetime(date_str)
                except Exception:
                    pass

            # Get attachments
            attachments = self._parse_attachments(msg)

            return Email(
                id=str(msg_id),
                subject=subject,
                sender=sender,
                date=date,
                body=body,
                has_attachments=len(attachments) > 0,
                attachments=attachments,
                headers=dict(msg.items()),
                provider='imap'
            )

        except Exception as e:
            logger.debug(f"Error parsing message: {e}")
            return None

    def _get_body(self, msg: Message) -> str:
        """Extract email body."""
        body = ""

        # Try text/plain first
        if msg.is_multipart():
            for part in msg.walk():
                if part.get_content_type() == 'text/plain':
                    try:
                        body = part.get_payload(decode=True).decode('utf-8', errors='ignore')
                        break
                    except Exception:
                        pass
        else:
            try:
                body = msg.get_payload(decode=True).decode('utf-8', errors='ignore')
            except Exception:
                body = msg.get_payload(decode=False)

        return body if isinstance(body, str) else str(body)

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

        if not msg.is_multipart():
            return attachments

        for part in msg.iter_attachments():
            filename = part.get_filename()
            if filename:
                try:
                    payload = part.get_payload(decode=True)
                    size = len(payload) if payload else 0
                except Exception:
                    size = 0

                attachments.append(Attachment(
                    filename=filename,
                    mime_type=part.get_content_type(),
                    size=size
                ))

        return attachments

    def update_labels(self, email_id: str, labels: List[str]) -> bool:
        """IMAP doesn't support labels like Gmail, but supports flags."""
        if not self._credentials_configured or not self.client:
            logger.error("IMAP NOT CONFIGURED: Cannot update flags")
            return False

        try:
            # Convert labels to IMAP flags
            imap_flags = self._labels_to_flags(labels)
            self.client.set_flags([int(email_id)], imap_flags)
            return True
        except Exception as e:
            logger.error(f"Error setting IMAP flags: {e}")
            return False

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

        try:
            for update in updates:
                self.update_labels(update['email_id'], update.get('labels', []))
            logger.info(f"Batch updated {len(updates)} emails")
            return True
        except Exception as e:
            logger.error(f"Batch update error: {e}")
            return False

    def _labels_to_flags(self, labels: List[str]) -> List[str]:
        """Convert label list to IMAP flags."""
        # Map common labels to IMAP flags
        flag_map = {
            'junk': '\\Junk',
            'spam': '\\Junk',
            'archive': '\\All',
            'trash': '\\Trash',
            'starred': '\\Flagged',
        }

        flags = []
        for label in labels:
            if label.lower() in flag_map:
                flags.append(flag_map[label.lower()])
            else:
                # IMAP allows custom keywords
                flags.append(label)

        return flags

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