"""
Generic PDF Downloader for unspecified sources
"""

from typing import Dict, Optional
import requests
from urllib.parse import urlparse
from loguru import logger

from .base import BaseDownloader, ContentType, DownloadResult


class GenericDownloader(BaseDownloader):
    """Generic downloader for any URL - attempts basic PDF download."""

    def can_handle(self, url: str) -> bool:
        """Generic downloader can handle any URL as a fallback."""
        return True

    def download(
        self, url: str, content_type: ContentType = ContentType.PDF
    ) -> Optional[bytes]:
        """Attempt to download content from any URL."""
        if content_type == ContentType.TEXT:
            # For generic sources, we can only extract text from PDF
            pdf_content = self._download_pdf(url)
            if pdf_content:
                text = self.extract_text_from_pdf(pdf_content)
                if text:
                    return text.encode("utf-8")
            return None
        # Try to download as PDF
        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:
            # For generic sources, we can only extract text from PDF
            pdf_content = self._download_pdf(url)
            if pdf_content:
                text = self.extract_text_from_pdf(pdf_content)
                if text:
                    return DownloadResult(
                        content=text.encode("utf-8"), is_success=True
                    )
                return DownloadResult(
                    skip_reason="PDF downloaded but text extraction failed"
                )
            return DownloadResult(skip_reason="Could not download PDF from URL")
        # Try to download as PDF
        logger.info(f"Attempting generic download from {url}")

        # Try direct download
        pdf_content = super()._download_pdf(url)

        if pdf_content:
            logger.info(f"Successfully downloaded PDF from {url}")
            return DownloadResult(content=pdf_content, is_success=True)

        # If the URL doesn't end with .pdf, try adding it
        try:
            parsed = urlparse(url)
            if not parsed.path.endswith(".pdf"):
                pdf_url = url.rstrip("/") + ".pdf"
                logger.debug(f"Trying with .pdf extension: {pdf_url}")
                pdf_content = super()._download_pdf(pdf_url)
            else:
                pdf_content = None
        except (ValueError, AttributeError):
            # urlparse can raise ValueError for malformed URLs
            pdf_content = None

        if pdf_content:
            logger.info(f"Successfully downloaded PDF from {pdf_url}")
            return DownloadResult(content=pdf_content, is_success=True)

        # Diagnostic request: determine WHY the download failed.
        #
        # IMPORTANT: stream=True is intentional here. DO NOT remove it.
        # This block only inspects response.status_code and headers
        # to determine why a download failed (404, 403, paywall, etc.).
        # Without stream=True, the full response body would be downloaded
        # into memory. Since GenericDownloader.can_handle() returns True
        # for ALL URLs, this could mean downloading multi-GB files just
        # to check a status code.
        #
        # The context manager (with ... as response) ensures the streamed
        # connection is properly closed on all code paths, preventing
        # file descriptor leaks (each unclosed stream=True response
        # holds an open socket FD).
        try:
            with self.session.get(
                url, timeout=5, allow_redirects=True, stream=True
            ) as response:
                # Check status code
                if response.status_code == 200:
                    # Check if it's HTML instead of PDF
                    response_content_type = response.headers.get(
                        "content-type", ""
                    ).lower()
                    if "text/html" in response_content_type:
                        return DownloadResult(
                            skip_reason="Article page requires login or subscription - no direct PDF link available",
                            status_code=response.status_code,
                        )
                    return DownloadResult(
                        skip_reason=f"Unexpected content type: {response_content_type} - expected PDF",
                        status_code=response.status_code,
                    )
                if response.status_code == 404:
                    return DownloadResult(
                        skip_reason="Article not found (404) - may have been removed or URL is incorrect",
                        status_code=404,
                    )
                if response.status_code == 403:
                    return DownloadResult(
                        skip_reason="Access denied (403) - article requires subscription or special permissions",
                        status_code=403,
                    )
                if response.status_code == 401:
                    return DownloadResult(
                        skip_reason="Authentication required - please login to access this article",
                        status_code=401,
                    )
                if response.status_code >= 500:
                    return DownloadResult(
                        skip_reason=f"Server error ({response.status_code}) - website is experiencing technical issues",
                        status_code=response.status_code,
                    )
                return DownloadResult(
                    skip_reason=f"Unable to access article - server returned error code {response.status_code}",
                    status_code=response.status_code,
                )
        except requests.exceptions.Timeout:
            return DownloadResult(
                skip_reason="Connection timed out - server took too long to respond"
            )
        except requests.exceptions.ConnectionError:
            return DownloadResult(
                skip_reason="Could not connect to server - website may be down"
            )
        except requests.RequestException:
            logger.warning("Unexpected error checking URL: {}", url)
            return DownloadResult(
                skip_reason="Network error - could not reach the website"
            )

    def _download_pdf(
        self, url: str, headers: Optional[Dict[str, str]] = None
    ) -> Optional[bytes]:
        """Attempt to download PDF from URL."""
        logger.info(f"Attempting generic download from {url}")

        # Try direct download
        pdf_content = super()._download_pdf(url)

        if pdf_content:
            logger.info(f"Successfully downloaded PDF from {url}")
            return pdf_content

        # If the URL doesn't end with .pdf, try adding it
        try:
            parsed = urlparse(url)
            if not parsed.path.endswith(".pdf"):
                pdf_url = url.rstrip("/") + ".pdf"
                logger.debug(f"Trying with .pdf extension: {pdf_url}")
                pdf_content = super()._download_pdf(pdf_url)
            else:
                pdf_content = None
        except (ValueError, AttributeError):
            # urlparse can raise ValueError for malformed URLs
            pdf_content = None

        if pdf_content:
            logger.info(f"Successfully downloaded PDF from {pdf_url}")
            return pdf_content

        logger.warning(f"Failed to download PDF from {url}")
        return None
