"""Content importer for profiles and specs from URLs."""

from __future__ import annotations

import logging
from datetime import datetime
from pathlib import Path
from typing import TYPE_CHECKING, Any

from gaol.sharing.exceptions import (
    ContentTypeDetectionError,
    ContentValidationError,
    FetchError,
    ImportError,
)
from gaol.sharing.models import (
    ContentType,
    ImportedContentMetadata,
    ImportResult,
    SecurityScanResult,
    TrustLevel,
)
from gaol.sharing.resolver import URLResolver, get_url_resolver
from gaol.sharing.scanner import SecurityScanner, get_security_scanner

if TYPE_CHECKING:
    from gaol.models.profile import Profile
    from gaol.specs import ContainerSpec
    from gaol.templates.fetcher import TemplateFetcher

logger = logging.getLogger(__name__)


class ContentImporter:
    """Import profiles and specs from URLs.

    Handles fetching, validation, security scanning, and storage of
    imported content.

    Example:
        >>> importer = ContentImporter()
        >>> result = importer.import_url("https://example.com/profile.yaml")
        >>> print(result.success, result.name)
    """

    def __init__(
        self,
        fetcher: TemplateFetcher | None = None,
        scanner: SecurityScanner | None = None,
        resolver: URLResolver | None = None,
    ) -> None:
        """Initialize the content importer.

        Args:
            fetcher: HTTP fetcher (uses TemplateFetcher if None)
            scanner: Security scanner (uses default if None)
            resolver: URL resolver (uses default if None)
        """
        self._fetcher = fetcher
        self._scanner = scanner or get_security_scanner()
        self._resolver = resolver or get_url_resolver()

    @property
    def fetcher(self) -> TemplateFetcher:
        """Get the HTTP fetcher (lazy initialization)."""
        if self._fetcher is None:
            from gaol.templates.fetcher import TemplateFetcher

            self._fetcher = TemplateFetcher()
        return self._fetcher

    def import_url(
        self,
        url: str,
        content_type: ContentType | None = None,
        name: str | None = None,
        save_locally: bool = True,
        skip_security_scan: bool = False,
    ) -> ImportResult:
        """Import content from a URL.

        Args:
            url: URL or reference to import from
            content_type: Content type (auto-detect if None)
            name: Override name for the content
            save_locally: Whether to save to local store
            skip_security_scan: Skip security scanning

        Returns:
            ImportResult with status and details

        Raises:
            ImportError: If import fails
            FetchError: If fetching fails
            ContentValidationError: If content is invalid
        """
        warnings: list[str] = []
        errors: list[str] = []

        # Resolve URL if it's a shorthand reference
        try:
            resolved_url = self._resolver.resolve(url)
        except Exception as e:
            raise ImportError(url, f"Failed to resolve URL: {e}", e)

        # Fetch content
        try:
            data = self.fetcher.fetch_yaml(resolved_url)
        except Exception as e:
            raise FetchError(resolved_url, str(e), e)

        # Detect content type if not specified
        if content_type is None:
            content_type = self._detect_content_type(data, url)

        # Extract name from content if not provided
        if name is None:
            name = self._extract_name(data, url)

        # Validate content
        if content_type == ContentType.PROFILE:
            validated = self._validate_profile(data)
            content_name = name or validated.name
        else:
            validated = self._validate_spec(data)
            content_name = name or validated.name

        # Security scan
        scan_result: SecurityScanResult | None = None
        if not skip_security_scan:
            if content_type == ContentType.PROFILE:
                scan_result = self._scanner.scan_profile(data)
            else:
                scan_result = self._scanner.scan_spec(data)

            if scan_result.has_critical:
                for finding in scan_result.get_by_severity(
                    scan_result.findings[0].severity.__class__.CRITICAL
                ):
                    errors.append(str(finding))

            for finding in scan_result.findings:
                if finding.severity.value == "warning":
                    warnings.append(str(finding))

        # Save locally if requested
        local_path: Path | None = None
        if save_locally:
            if content_type == ContentType.PROFILE:
                local_path = self._save_profile(validated, content_name, url)
            else:
                local_path = self._save_spec(validated, content_name, url)

        return ImportResult(
            success=True,
            content_type=content_type,
            name=content_name,
            source_url=resolved_url,
            local_path=local_path,
            trust_level=TrustLevel.REMOTE,
            security_scan=scan_result,
            warnings=warnings,
            errors=errors,
        )

    def import_profile(
        self,
        url: str,
        name: str | None = None,
        save_locally: bool = True,
        skip_security_scan: bool = False,
    ) -> ImportResult:
        """Import a profile from a URL.

        Args:
            url: URL to import from
            name: Override name for the profile
            save_locally: Whether to save to local store
            skip_security_scan: Skip security scanning

        Returns:
            ImportResult with status and details
        """
        return self.import_url(
            url,
            content_type=ContentType.PROFILE,
            name=name,
            save_locally=save_locally,
            skip_security_scan=skip_security_scan,
        )

    def import_spec(
        self,
        url: str,
        name: str | None = None,
        save_locally: bool = True,
        skip_security_scan: bool = False,
    ) -> ImportResult:
        """Import a spec from a URL.

        Args:
            url: URL to import from
            name: Override name for the spec
            save_locally: Whether to save to local store
            skip_security_scan: Skip security scanning

        Returns:
            ImportResult with status and details
        """
        return self.import_url(
            url,
            content_type=ContentType.SPEC,
            name=name,
            save_locally=save_locally,
            skip_security_scan=skip_security_scan,
        )

    def _detect_content_type(self, data: dict[str, Any], url: str) -> ContentType:
        """Auto-detect content type from data.

        Profiles typically have: packages, services, setup_commands, depends_on
        Specs typically have: runtime, distro, network, mounts

        Args:
            data: Parsed content data
            url: Original URL for error messages

        Returns:
            Detected ContentType

        Raises:
            ContentTypeDetectionError: If type cannot be determined
        """
        # Profile indicators
        profile_keys = {"packages", "services", "setup_commands", "depends_on", "files"}
        profile_score = sum(1 for k in profile_keys if k in data)

        # Spec indicators
        spec_keys = {"runtime", "distro", "network", "mounts", "profiles", "image"}
        spec_score = sum(1 for k in spec_keys if k in data)

        # Strong indicators
        if "depends_on" in data and isinstance(data.get("depends_on"), list):
            # Profile dependency format
            if data["depends_on"] and isinstance(data["depends_on"][0], (str, dict)):
                profile_score += 2

        if "runtime" in data or "distro" in data:
            spec_score += 2

        if profile_score > spec_score:
            return ContentType.PROFILE
        elif spec_score > profile_score:
            return ContentType.SPEC
        else:
            raise ContentTypeDetectionError(url)

    def _extract_name(self, data: dict[str, Any], url: str) -> str:
        """Extract name from content or URL.

        Args:
            data: Parsed content data
            url: Original URL

        Returns:
            Extracted or generated name
        """
        # Try to get name from content
        if "name" in data and data["name"]:
            return str(data["name"])

        # Extract from URL filename
        filename = self._resolver.extract_filename(url)
        if filename:
            # Remove extension
            name = filename.rsplit(".", 1)[0]
            # Sanitize
            name = name.replace(" ", "-").lower()
            if name:
                return name

        # Generate from URL hash
        import hashlib

        url_hash = hashlib.sha256(url.encode()).hexdigest()[:8]
        return f"imported-{url_hash}"

    def _validate_profile(self, data: dict[str, Any]) -> Profile:
        """Validate profile data.

        Args:
            data: Profile data dict

        Returns:
            Validated Profile object

        Raises:
            ContentValidationError: If validation fails
        """
        from gaol.models.profile import Profile

        try:
            return Profile.from_yaml(data)
        except Exception as e:
            raise ContentValidationError("profile", str(e))

    def _validate_spec(self, data: dict[str, Any]) -> ContainerSpec:
        """Validate spec data.

        Args:
            data: Spec data dict

        Returns:
            Validated ContainerSpec object

        Raises:
            ContentValidationError: If validation fails
        """
        from gaol.specs import ContainerSpec

        try:
            return ContainerSpec(**data)
        except Exception as e:
            raise ContentValidationError("spec", str(e))

    def _save_profile(self, profile: Profile, name: str, source_url: str) -> Path:
        """Save profile to local store.

        Args:
            profile: Validated profile
            name: Name for the profile
            source_url: Original source URL

        Returns:
            Path where profile was saved
        """
        from gaol.profiles.store import get_profile_store

        store = get_profile_store()

        # Create metadata
        metadata = ImportedContentMetadata(
            source_url=source_url,
            imported_at=datetime.now().isoformat(),
            trust_level=TrustLevel.REMOTE,
            content_type=ContentType.PROFILE,
            original_name=profile.name,
        )

        return store.save(profile, name=name, metadata=metadata)

    def _save_spec(self, spec: ContainerSpec, name: str, source_url: str) -> Path:
        """Save spec to local store.

        Args:
            spec: Validated spec
            name: Name for the spec
            source_url: Original source URL

        Returns:
            Path where spec was saved
        """
        from gaol.specs.store import get_spec_store

        store = get_spec_store()

        # Create metadata
        metadata = ImportedContentMetadata(
            source_url=source_url,
            imported_at=datetime.now().isoformat(),
            trust_level=TrustLevel.REMOTE,
            content_type=ContentType.SPEC,
            original_name=spec.name,
        )

        return store.save(spec, name=name, metadata=metadata)


# Module-level importer instance
_importer: ContentImporter | None = None


def get_content_importer() -> ContentImporter:
    """Get the global content importer instance.

    Returns:
        ContentImporter instance
    """
    global _importer
    if _importer is None:
        _importer = ContentImporter()
    return _importer
