import requests  # type: ignore
from typing import Any
from urllib.parse import urlparse, unquote

from .base import BaseSource, ResolvedSource, ResolutionResult


class DirectURLSource(BaseSource):
    """Direct URL source for resolving assets from direct download links."""
    
    @property
    def name(self) -> str:
        return "direct_url"
    
    def is_available(self, config: dict[str, Any]) -> bool:
        """
        Direct URL source is always available.
        
        Args:
            config: Configuration dictionary
            
        Returns:
            Always True
        """
        return True
    
    def search(self, filename: str, asset_type: str) -> list[ResolutionResult]:
        """
        Direct URL source doesn't support search.
        Use resolve_url() instead for direct URL resolution.
        
        Args:
            filename: The asset filename to search for
            asset_type: The type of asset
            
        Returns:
            Empty list (direct URLs don't support search)
        """
        return []
    
    def resolve_url(self, url: str) -> ResolutionResult:
        """
        Resolve a direct URL to get file metadata.
        
        Args:
            url: Direct download URL
            
        Returns:
            ResolutionResult with file metadata
        """
        try:
            # Make a HEAD request to get metadata without downloading
            response = requests.head(url, allow_redirects=True, timeout=10)
            
            if response.status_code == 404:
                return ResolutionResult(
                    input_name=url,
                    resolved_name=url,
                    source=None,
                    confidence="unknown",
                    error="URL not found (404)",
                )
            
            if response.status_code != 200:
                return ResolutionResult(
                    input_name=url,
                    resolved_name=url,
                    source=None,
                    confidence="unknown",
                    error=f"HTTP error: {response.status_code}",
                )
            
            # Extract filename from URL or Content-Disposition header
            filename = self._extract_filename(url, response.headers)
            
            # Get file size from Content-Length header
            file_size_bytes = None
            if "Content-Length" in response.headers:
                try:
                    file_size_bytes = int(response.headers["Content-Length"])
                except ValueError:
                    pass
            
            source = ResolvedSource(
                source_type="direct_url",
                repo=url,
                file=filename,
                download_url=url,
                sha256=None,  # Direct URLs don't provide SHA-256
                file_size_bytes=file_size_bytes,
            )
            
            return ResolutionResult(
                input_name=url,
                resolved_name=filename,
                source=source,
                confidence="high",  # Direct URL is always high confidence
                error=None,
            )
        
        except requests.exceptions.RequestException as e:
            return ResolutionResult(
                input_name=url,
                resolved_name=url,
                source=None,
                confidence="unknown",
                error=f"Network error: {str(e)}",
            )
        except Exception as e:
            return ResolutionResult(
                input_name=url,
                resolved_name=url,
                source=None,
                confidence="unknown",
                error=f"Unexpected error: {str(e)}",
            )
    
    def _extract_filename(self, url: str, headers: Any) -> str:
        """
        Extract filename from URL or Content-Disposition header.
        
        Args:
            url: The URL
            headers: Response headers
            
        Returns:
            Extracted filename
        """
        # Try Content-Disposition header first
        content_disposition = headers.get("Content-Disposition", "")
        if content_disposition:
            # Parse filename from Content-Disposition
            # Format: attachment; filename="filename.ext"
            parts = content_disposition.split("filename=")
            if len(parts) > 1:
                filename = parts[1].strip().strip('"').strip("'")
                if filename:
                    return unquote(filename)
        
        # Fall back to extracting from URL path
        parsed_url = urlparse(url)
        path = parsed_url.path
        
        # Get the last part of the path
        if "/" in path:
            filename = path.split("/")[-1]
        else:
            filename = path
        
        # Decode URL encoding
        filename = unquote(filename)
        
        # If still no filename, use a default
        if not filename or filename == "":
            filename = "downloaded_file"
        
        return filename
