import time
import threading
import logging
from typing import Optional, Callable

from .client import SSLAPIClient
from .manager import CertificateManager

logger = logging.getLogger(__name__)

class SSLMonitor:
    """
    Background monitor that checks and updates SSL certificates periodically.
    """
    def __init__(
        self,
        api_url: str,
        domains: list,
        cert_dir: str,
        check_interval_hours: int = 12,
        api_key: Optional[str] = None,
        on_update_callback: Optional[Callable] = None
    ):
        self.client = SSLAPIClient(api_url, api_key)
        self.manager = CertificateManager(cert_dir, on_update_callback)
        self.domains = domains
        self.interval_seconds = check_interval_hours * 3600
        self._stop_event = threading.Event()
        self._thread = None

    def start(self, block: bool = False):
        """
        Start the monitoring loop.
        If block is True, runs in the main thread (blocking).
        If block is False, runs in a background daemon thread.
        """
        if block:
            self._run_loop()
        else:
            self._thread = threading.Thread(target=self._run_loop, daemon=True)
            self._thread.start()
            logger.info(f"SSL Monitor started in background for domains: {self.domains}")

    def stop(self):
        """Stop the monitoring loop."""
        self._stop_event.set()
        if self._thread:
            self._thread.join(timeout=5)
        logger.info("SSL Monitor stopped.")

    def check_now(self):
        """
        Run a check immediately.
        """
        logger.info("Running immediate certificate check...")
        self._check_domains()

    def _run_loop(self):
        logger.info("SSL Monitor loop started.")
        # Run immediately on start
        self._check_domains()
        
        while not self._stop_event.wait(self.interval_seconds):
            self._check_domains()

    def _check_domains(self):
        for domain in self.domains:
            try:
                logger.info(f"Checking certificate for {domain}...")
                
                # 1. Validate and (auto-renew on server if needed)
                result = self.client.validate_certificate(domain, auto_renew=True)
                
                action = result.get("action")
                validation = result.get("validation", {})
                is_valid = validation.get("valid")
                
                # 2. If renewed or valid but we want to sync, check/download files
                # Simpler logic: Always get files and let Manager decide if they changed
                # Or only if 'action' == 'renewed' or if we force sync.
                # To be safe and self-healing, we should check if we have local files first.
                
                # If server says it renewed, we MUST download
                should_download = (action == "renewed")
                
                # If we don't assume we have them, or just want to ensure sync:
                if not should_download:
                     # Optional: Check if local files exist?
                     # For now, let's rely on the server's validation.
                     pass

                # However, the user requirement is: "if expired, auto pull latest".
                # The validate endpoint already renews if expired.
                # So if action is 'renewed', we fetch.
                
                if action == "renewed":
                    logger.info(f"Certificate for {domain} was renewed remotely. Downloading...")
                    files_data = self.client.get_certificate_files(domain)
                    files = files_data.get("files", {})
                    self.manager.update_certificates(domain, files)
                    
                elif is_valid:
                    # Even if valid, we might not have them locally (fresh install)
                    # We can check if files exist in manager logic, but here let's just
                    # try to sync if it's the first run or we are missing files.
                    # For simplicity in this lightweight lib, we can just try to sync
                    # if the manager reports files are missing, or we can just fetch always
                    # and let manager filter duplicates (it does SHA/content check).
                    
                    # Let's fetch always to ensure consistency (Self-healing)
                    # This adds network overhead but guarantees correct state.
                    logger.debug(f"Verifying local consistency for {domain}...")
                    files_data = self.client.get_certificate_files(domain)
                    files = files_data.get("files", {})
                    self.manager.update_certificates(domain, files)
                    
                else:
                    logger.warning(f"Certificate for {domain} is invalid and server could not renew it.")

            except Exception as e:
                logger.error(f"Error checking {domain}: {e}")

