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

import re
from typing import 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)
        else:
            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"
            )
        else:
            # 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)
            else:
                # 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"
                        )
                    elif response.status_code >= 500:
                        return DownloadResult(
                            skip_reason="bioRxiv/medRxiv server temporarily unavailable"
                        )
                except requests.RequestException:
                    logger.debug("Failed to check bioRxiv/medRxiv URL: %s", url)
                return DownloadResult(
                    skip_reason="Failed to download PDF from bioRxiv/medRxiv"
                )

    def _download_pdf(self, url: str) -> 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
        pdf_url = pdf_url.replace("/content/early/", "/content/")

        return pdf_url

    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
