"""Job inventory state persistence for diffing."""

import json
import logging
from pathlib import Path
from typing import Dict, List, Any

logger = logging.getLogger(__name__)


INVENTORY_DIR = Path("/var/lib/runsentry")
INVENTORY_FILE = INVENTORY_DIR / "inventory.json"


def load_inventory() -> Dict[str, Dict[str, Any]]:
    """
    Load previous job inventory from disk.
    
    Returns:
        Dictionary mapping externalId -> job dict
        Empty dict if file doesn't exist or is invalid
    """
    if not INVENTORY_FILE.exists():
        return {}
    
    try:
        with open(INVENTORY_FILE, "r") as f:
            data = json.load(f)
            # Convert list to dict if needed (backward compatibility)
            if isinstance(data, list):
                return {job.get("externalId"): job for job in data if job.get("externalId")}
            elif isinstance(data, dict):
                # If already a dict, ensure it's keyed by externalId
                if data and "externalId" not in list(data.values())[0] if data else True:
                    return data
                # If values are job dicts, use externalId as key
                result = {}
                for key, job in data.items():
                    if isinstance(job, dict) and "externalId" in job:
                        result[job["externalId"]] = job
                    else:
                        result[key] = job
                return result
            return {}
    except (json.JSONDecodeError, IOError, KeyError) as e:
        logger.warning(f"Failed to load inventory: {e}")
        return {}


def save_inventory(jobs: Dict[str, Dict[str, Any]]) -> None:
    """
    Save current job inventory to disk.
    
    Args:
        jobs: Dictionary mapping externalId -> job dict
    """
    INVENTORY_DIR.mkdir(parents=True, exist_ok=True)
    
    try:
        # Save as dict keyed by externalId for efficient lookup
        with open(INVENTORY_FILE, "w") as f:
            json.dump(jobs, f, indent=2, sort_keys=True)
    except IOError as e:
        logger.warning(f"Failed to save inventory: {e}")


def diff_inventory(old: Dict[str, Dict[str, Any]], new: Dict[str, Dict[str, Any]]) -> Dict[str, List[Dict[str, Any]]]:
    """
    Compare old and new inventory to detect changes.
    
    Args:
        old: Previous inventory (externalId -> job dict)
        new: Current inventory (externalId -> job dict)
    
    Returns:
        Dictionary with keys:
        - "added": List of new jobs
        - "updated": List of jobs that changed
        - "deleted": List of jobs that were removed
    """
    result = {
        "added": [],
        "updated": [],
        "deleted": [],
    }
    
    # Convert new list to dict if needed
    if isinstance(new, list):
        new_dict = {job.get("externalId"): job for job in new if job.get("externalId")}
    else:
        new_dict = new
    
    # Find added and updated jobs
    for external_id, job in new_dict.items():
        if external_id not in old:
            result["added"].append(job)
        else:
            # Compare jobs to detect updates
            old_job = old[external_id]
            # Compare key fields that indicate a change
            if _job_changed(old_job, job):
                result["updated"].append(job)
    
    # Find deleted jobs
    for external_id, job in old.items():
        if external_id not in new_dict:
            result["deleted"].append(job)
    
    return result


def _job_changed(old_job: Dict[str, Any], new_job: Dict[str, Any]) -> bool:
    """
    Check if a job has changed between old and new versions.
    
    Compares key fields: schedule, command, location, enabled, user.
    """
    key_fields = ["schedule", "command", "location", "enabled", "user", "name"]
    
    for field in key_fields:
        if old_job.get(field) != new_job.get(field):
            return True
    
    return False
