"""Asset Downloader for k4s.

Handles downloading assets (files, archives, etc.) from specified URLs.
"""

import logging
import shlex
import os
import re
from .executor import Executor

logger = logging.getLogger(__name__)

class DownloaderError(Exception):
    """Custom exception for downloader errors."""
    pass

class AssetDownloader:
    """
    Downloads assets on a target server using an Executor.
    Supports checksum verification (sha256) using commands on the target server.
    """

    def __init__(self, executor: Executor):
        self.executor = executor
        logger.debug(f"AssetDownloader initialized for host: {self.executor.host or 'localhost'}")

    def download(
        self,
        url: str,
        destination_path: str,
        checksum_config: dict | None = None,
        *,
        sudo: bool = False,
    ):
        """
        Downloads a file to the destination_path on the target server and verifies its checksum.
        """
        logger.info(f"Preparing to download on target: {url} -> {destination_path}")
        
        # Ensure destination directory exists on target.
        dest_dir = os.path.dirname(destination_path)
        self.executor.execute(f"mkdir -p {shlex.quote(dest_dir)}", use_sudo=sudo)

        # Download the file using curl.
        # -f: fail on HTTP errors (4xx/5xx) so we don't save an HTML error page
        # and then attempt checksum verification on it.
        download_cmd = f"curl -fSL --output {shlex.quote(destination_path)} {shlex.quote(url)}"
        logger.info(f"Executing download command on target: {download_cmd}")
        rc, _, stderr = self.executor.execute(download_cmd, use_sudo=sudo)
        if rc != 0:
            raise DownloaderError(f"Download failed for {url}. Stderr: {stderr}")

        logger.info(f"Download completed for {destination_path}.")

        if checksum_config:
            self._verify_checksum(destination_path, checksum_config, sudo=sudo)
        else:
            logger.info("No checksum config provided. Skipping verification.")

    def _verify_checksum(self, file_path: str, config: dict, *, sudo: bool = False):
        """
        Verifies the checksum of the downloaded file on the target server.
        The expected checksum can be a direct value or a URL to a checksum file.
        """
        algo = config.get("type", "sha256").lower()
        if algo != "sha256":
            raise DownloaderError(f"Unsupported checksum algorithm: {algo}. Only 'sha256' is supported.")

        expected_checksum_source = config.get("value")
        if not expected_checksum_source:
            logger.info("No 'value' provided in checksum config. Skipping verification.")
            return

        # Determine if the checksum source is a URL or a static value
        if expected_checksum_source.startswith("http://") or expected_checksum_source.startswith("https://"):
            logger.info(f"Fetching expected checksum from URL: {expected_checksum_source}")
            # Fetch from URL. Assumes the file contains the hash as the first word.
            cmd = f"curl -fsSL {shlex.quote(expected_checksum_source)} | cut -d' ' -f1"
            rc, stdout, stderr = self.executor.execute(cmd)
            if rc != 0:
                raise DownloaderError(f"Failed to fetch checksum from URL {expected_checksum_source}: {stderr}")
            expected_checksum = stdout.strip()
        else:
            # Use the value directly
            expected_checksum = expected_checksum_source

        # Basic validation: expected sha256 should be 64 hex chars.
        if not re.fullmatch(r"[0-9a-fA-F]{64}", expected_checksum or ""):
            raise DownloaderError(
                "Invalid SHA256 checksum value retrieved. "
                f"Got: {expected_checksum!r}. "
                "This usually means the checksum URL returned an error page (wrong version or URL)."
            )

        # Calculate the actual checksum of the downloaded file
        logger.info(f"Verifying {algo} checksum for {file_path}...")
        actual_checksum_cmd = f"sha256sum {shlex.quote(file_path)} | cut -d' ' -f1"
        rc, actual_checksum, stderr = self.executor.execute(actual_checksum_cmd)
        if rc != 0:
            raise DownloaderError(f"Failed to calculate {algo} checksum for {file_path}: {stderr}")
        
        actual_checksum = actual_checksum.strip()

        # Compare and raise error if mismatch
        if actual_checksum.lower() == expected_checksum.lower():
            logger.info("Checksum verification successful.")
        else:
            # Clean up the failed download before raising
            self.executor.execute(f"rm -f {shlex.quote(file_path)}", use_sudo=sudo)
            raise DownloaderError(
                f"Checksum mismatch for {file_path}. "
                f"Expected: {expected_checksum}, Got: {actual_checksum}"
            )