#!/usr/bin/env python3
"""
Omi Auto-Sync Script

Runs periodically via LaunchAgent.
1. Scans for Omi pendant
2. If detected and not recently synced, triggers pipeline
3. Logs results

Status is tracked to avoid redundant syncs.
"""

import asyncio
import json
import logging
import subprocess
import sys
from datetime import datetime, timedelta
from pathlib import Path

logger = logging.getLogger(__name__)
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [%(levelname)s] %(message)s'
)

WORKSPACE = Path.home() / ".openclaw/workspace/projects/active/omi-direct-pipeline"
PHASE1_DIR = WORKSPACE / "phase1"
LOGS_DIR = WORKSPACE / "logs"
SYNC_STATUS_FILE = LOGS_DIR / "last-sync.json"

PIPELINE_SCRIPT = PHASE1_DIR / "omi_pipeline.py"
BLE_SCAN_TIMEOUT = 5  # seconds
SYNC_INTERVAL_MINUTES = 30  # Only sync if last sync was >30 minutes ago
BLE_SYNC_DURATION = 60  # seconds


def load_sync_status() -> dict:
    """Load last sync status."""
    if SYNC_STATUS_FILE.exists():
        try:
            with open(SYNC_STATUS_FILE) as f:
                return json.load(f)
        except Exception as e:
            logger.warning(f"Could not load sync status: {e}")
    
    return {"last_sync": None, "last_check": None, "syncs": []}


def save_sync_status(status: dict):
    """Save sync status."""
    LOGS_DIR.mkdir(parents=True, exist_ok=True)
    with open(SYNC_STATUS_FILE, 'w') as f:
        json.dump(status, f, indent=2)


async def scan_for_omi(timeout: int = BLE_SCAN_TIMEOUT) -> bool:
    """Scan for Omi pendant via BLE."""
    try:
        from bleak import BleakScanner
        
        logger.info("Scanning for Omi pendant...")
        devices = await asyncio.wait_for(BleakScanner.discover(), timeout=timeout)
        
        for device in devices:
            if device.name == "Omi":
                logger.info(f"✅ Found Omi pendant: {device.address}")
                return True
        
        logger.info("Omi pendant not found in range")
        return False
        
    except asyncio.TimeoutError:
        logger.warning("BLE scan timed out")
        return False
    except Exception as e:
        logger.error(f"BLE scan error: {e}")
        return False


def should_sync_now(status: dict) -> bool:
    """Check if enough time has passed since last sync."""
    last_sync = status.get("last_sync")
    
    if not last_sync:
        logger.info("No previous sync found - proceeding")
        return True
    
    try:
        last_sync_time = datetime.fromisoformat(last_sync)
        time_since_last = datetime.now() - last_sync_time
        
        if time_since_last < timedelta(minutes=SYNC_INTERVAL_MINUTES):
            logger.info(f"Last sync was {time_since_last.seconds} seconds ago - skipping (interval: {SYNC_INTERVAL_MINUTES} min)")
            return False
        
        logger.info(f"Last sync was {time_since_last.seconds // 60} minutes ago - proceeding")
        return True
        
    except Exception as e:
        logger.warning(f"Could not check sync interval: {e}")
        return True


def trigger_pipeline() -> bool:
    """Trigger the full Omi pipeline."""
    try:
        logger.info("Triggering Omi pipeline...")
        
        cmd = [
            sys.executable,
            str(PIPELINE_SCRIPT),
            "--full",
            "--sync", str(BLE_SYNC_DURATION),
            "--model", "base"
        ]
        
        result = subprocess.run(
            cmd,
            capture_output=True,
            text=True,
            timeout=3600  # 1 hour timeout
        )
        
        if result.returncode == 0:
            logger.info("✅ Pipeline completed successfully")
            return True
        else:
            logger.error(f"Pipeline failed with code {result.returncode}")
            logger.error(f"Error: {result.stderr}")
            return False
            
    except subprocess.TimeoutExpired:
        logger.error("Pipeline timed out")
        return False
    except Exception as e:
        logger.error(f"Pipeline error: {e}")
        return False


async def main():
    """Main auto-sync routine."""
    logger.info("="*60)
    logger.info("Omi Auto-Sync Check")
    logger.info("="*60)
    
    status = load_sync_status()
    status["last_check"] = datetime.now().isoformat()
    
    try:
        # Step 1: Scan for pendant
        pendant_found = await scan_for_omi(BLE_SCAN_TIMEOUT)
        
        if not pendant_found:
            logger.info("Pendant not in range - skipping sync")
            save_sync_status(status)
            return
        
        # Step 2: Check if enough time has passed
        if not should_sync_now(status):
            logger.info("Too soon to sync again - skipping")
            save_sync_status(status)
            return
        
        # Step 3: Trigger pipeline
        success = trigger_pipeline()
        
        if success:
            status["last_sync"] = datetime.now().isoformat()
            sync_record = {
                "timestamp": datetime.now().isoformat(),
                "status": "success"
            }
            status.get("syncs", []).append(sync_record)
            # Keep last 10 syncs
            status["syncs"] = status["syncs"][-10:]
        else:
            logger.warning("Pipeline did not complete successfully")
        
        save_sync_status(status)
        
    except Exception as e:
        logger.error(f"Auto-sync error: {e}")
        save_sync_status(status)
    
    logger.info("="*60)


if __name__ == "__main__":
    try:
        asyncio.run(main())
    except KeyboardInterrupt:
        logger.info("Auto-sync interrupted")
    except Exception as e:
        logger.error(f"Fatal error: {e}")
