"""
bioRxiv/medRxiv PDF and Text Downloader
"""

import re
from typing import Dict, Optional
from urllib.parse import urlparse

import requests
from loguru import logger

from .base import BaseDownloader, ContentType, DownloadResult


class BioRxivDownloader(BaseDownloader):
    """Downloader for bioRxiv and medRxiv preprints."""

    def can_handle(self, url: str) -> bool:
        """Check if URL is from bioRxiv or medRxiv."""
        try:
            hostname = urlparse(url).hostname
            if not hostname:
                return False
            return (
                hostname == "biorxiv.org"
                or hostname.endswith(".biorxiv.org")
                or hostname == "medrxiv.org"
                or hostname.endswith(".medrxiv.org")
            )
        except Exception:
            return False

    def download(
        self, url: str, content_type: ContentType = ContentType.PDF
    ) -> Optional[bytes]:
        """Download content from bioRxiv/medRxiv."""
        if content_type == ContentType.TEXT:
            return self._download_text(url)
        return self._download_pdf(url)

    def download_with_result(
        self, url: str, content_type: ContentType = ContentType.PDF
    ) -> DownloadResult:
        """Download content and return detailed result with skip reason."""
        if content_type == ContentType.TEXT:
            # Try to get text from page
            text = self._fetch_abstract_from_page(url)
            if text:
                return DownloadResult(
                    content=text.encode("utf-8"), is_success=True
                )

            # Fallback to PDF extraction
            pdf_content = self._download_pdf(url)
            if pdf_content:
                extracted_text = self.extract_text_from_pdf(pdf_content)
                if extracted_text:
                    return DownloadResult(
                        content=extracted_text.encode("utf-8"), is_success=True
                    )

            return DownloadResult(
                skip_reason="Could not extract text from bioRxiv/medRxiv article"
            )
        # Try to download PDF
        pdf_url = self._convert_to_pdf_url(url)
        if not pdf_url:
            return DownloadResult(
                skip_reason="Invalid bioRxiv/medRxiv URL format"
            )

        logger.info(f"Downloading bioRxiv/medRxiv PDF from {pdf_url}")
        pdf_content = super()._download_pdf(pdf_url)

        if pdf_content:
            return DownloadResult(content=pdf_content, is_success=True)
        # Check if it's a server issue or article doesn't exist
        try:
            response = self.session.head(url, timeout=5)
            if response.status_code == 404:
                return DownloadResult(
                    skip_reason="Article not found on bioRxiv/medRxiv",
                    status_code=404,
                )
            if response.status_code >= 500:
                return DownloadResult(
                    skip_reason="bioRxiv/medRxiv server temporarily unavailable",
                    status_code=response.status_code,
                )
        except requests.RequestException:
            logger.debug("Failed to check bioRxiv/medRxiv URL: {}", url)
        return DownloadResult(
            skip_reason="Failed to download PDF from bioRxiv/medRxiv"
        )

    def _download_pdf(
        self, url: str, headers: Optional[Dict[str, str]] = None
    ) -> Optional[bytes]:
        """Download PDF from bioRxiv/medRxiv."""
        # Convert URL to PDF format
        pdf_url = self._convert_to_pdf_url(url)

        if not pdf_url:
            logger.error(f"Could not convert to PDF URL: {url}")
            return None

        logger.info(f"Downloading bioRxiv/medRxiv PDF from {pdf_url}")
        return super()._download_pdf(pdf_url)

    def _download_text(self, url: str) -> Optional[bytes]:
        """Get text content from bioRxiv/medRxiv."""
        # Try to get abstract and metadata from the HTML page
        text = self._fetch_abstract_from_page(url)
        if text:
            return text.encode("utf-8")

        # Fallback: Download PDF and extract text
        pdf_content = self._download_pdf(url)
        if pdf_content:
            extracted_text = self.extract_text_from_pdf(pdf_content)
            if extracted_text:
                return extracted_text.encode("utf-8")

        return None

    def _convert_to_pdf_url(self, url: str) -> Optional[str]:
        """Convert bioRxiv/medRxiv URL to PDF URL."""
        # Handle different URL patterns
        # Example: https://www.biorxiv.org/content/10.1101/2024.01.01.123456v1
        # Becomes: https://www.biorxiv.org/content/10.1101/2024.01.01.123456v1.full.pdf

        # Remove any existing .full or .full.pdf
        base_url = re.sub(r"\.full(\.pdf)?$", "", url)

        # Check if it's already a PDF URL
        if base_url.endswith(".pdf"):
            return base_url

        # Add .full.pdf
        pdf_url = base_url.rstrip("/") + ".full.pdf"

        # Handle content vs. content/early URLs
        return pdf_url.replace("/content/early/", "/content/")

    def _fetch_abstract_from_page(self, url: str) -> Optional[str]:
        """Fetch abstract and metadata from bioRxiv/medRxiv page."""
        try:
            # Request the HTML page
            response = self.session.get(url, timeout=10)

            if response.status_code == 200:
                # Simple extraction using regex (avoiding BeautifulSoup dependency)
                html = response.text
                text_parts = []

                # Extract title
                title_match = re.search(
                    r'<meta\s+name="DC\.Title"\s+content="([^"]+)"', html
                )
                if title_match:
                    text_parts.append(f"Title: {title_match.group(1)}")

                # Extract authors
                author_match = re.search(
                    r'<meta\s+name="DC\.Creator"\s+content="([^"]+)"', html
                )
                if author_match:
                    text_parts.append(f"Authors: {author_match.group(1)}")

                # Extract abstract
                abstract_match = re.search(
                    r'<meta\s+name="DC\.Description"\s+content="([^"]+)"',
                    html,
                    re.DOTALL,
                )
                if abstract_match:
                    abstract = abstract_match.group(1)
                    # Clean up HTML entities
                    abstract = abstract.replace("&lt;", "<").replace(
                        "&gt;", ">"
                    )
                    abstract = abstract.replace("&quot;", '"').replace(
                        "&#39;", "'"
                    )
                    abstract = abstract.replace("&amp;", "&")
                    text_parts.append(f"\nAbstract:\n{abstract}")

                if text_parts:
                    logger.info(
                        "Retrieved text content from bioRxiv/medRxiv page"
                    )
                    return "\n".join(text_parts)

        except Exception as e:
            logger.debug(f"Failed to fetch abstract from bioRxiv/medRxiv: {e}")

        return None
