#!/usr/bin/env python3
"""
FES Bridge - thin wrapper around fes_worker.py that adds:
- Robust error handling (fail loud, never silent)
- Structured logging (for the microservice)
- Multi-format input (JSON, YAML, stdin)
- Status reporting (counts, errors, durations)
- Health check + dry-run mode (for the microservice)

Run modes:
  python3 fes_bridge.py run <input.json> [output-dir]    # Process widgets
  python3 fes_bridge.py health                          # Health check
  python3 fes_bridge.py dry-run <input.json>            # Validate without writing
  python3 fes_bridge.py --help                          # Show help

Used by:
  fes-bridge microservice (port 3005) - thin Flask wrapper
  Manual CLI for ops
  FvRE bridge build pipelines
"""
import json
import os
import sys
import time
import logging
import argparse
from pathlib import Path
from datetime import datetime, timezone

# Force unbuffered output
sys.stdout.reconfigure(line_buffering=True)
sys.stderr.reconfigure(line_buffering=True)

# Set up structured logging
logging.basicConfig(
    level=logging.INFO,
    format='%(asctime)s [%(levelname)s] %(message)s',
    stream=sys.stdout,
)
log = logging.getLogger('fes-bridge')

# Default paths
WCP_CATALOG_DEFAULT = '/workspace/freshvibe-cms/wcp/wcp-catalog.json'
FES_WORKER_PATH = os.path.dirname(os.path.abspath(__file__))


def load_fes_worker(wcp_catalog_path=None):
    """Lazy import of fes_worker to avoid breaking on missing dependencies."""
    catalog = wcp_catalog_path or WCP_CATALOG_DEFAULT
    if not Path(catalog).exists():
        raise FileNotFoundError(f"WCP catalog not found: {catalog}")
    
    # Add the dir to sys.path so we can import
    sys.path.insert(0, FES_WORKER_PATH)
    try:
        import fes_worker
    except ImportError as e:
        raise ImportError(f"Cannot import fes_worker.py: {e}")
    
    return fes_worker, catalog


def parse_input(input_path):
    """Parse input from JSON file or stdin."""
    if input_path == '-':
        data = json.loads(sys.stdin.read())
    elif input_path.endswith(('.yaml', '.yml')):
        try:
            import yaml
        except ImportError:
            raise ImportError("PyYAML required for YAML input. pip install pyyaml")
        with open(input_path) as f:
            data = yaml.safe_load(f)
    else:
        with open(input_path) as f:
            data = json.load(f)
    
    if isinstance(data, dict) and 'widgets' in data:
        data = data['widgets']
    
    if not isinstance(data, list):
        raise ValueError(f"Input must be a list of widgets, got {type(data).__name__}")
    
    return data


def health_check():
    """Verify the bridge can run. Returns 0 if healthy, 1 if not."""
    log.info("Health check starting")
    
    # Check WCP catalog exists + is valid JSON
    if not Path(WCP_CATALOG_DEFAULT).exists():
        log.error(f"❌ WCP catalog missing: {WCP_CATALOG_DEFAULT}")
        return False
    try:
        with open(WCP_CATALOG_DEFAULT) as f:
            catalog = json.load(f)
        n = len(catalog.get('primitives', {}))
        log.info(f"✅ WCP catalog: {n} primitives")
    except Exception as e:
        log.error(f"❌ WCP catalog invalid: {e}")
        return False
    
    # Check fes_worker.py imports
    try:
        fes_worker, _ = load_fes_worker()
        log.info(f"✅ fes_worker.py imports OK")
    except Exception as e:
        log.error(f"❌ fes_worker.py import failed: {e}")
        return False
    
    # Check fes_worker can load the catalog
    try:
        worker = fes_worker.FESWorker(WCP_CATALOG_DEFAULT)
        log.info(f"✅ FESWorker instance: {len(worker.primitives)} primitives loaded")
    except Exception as e:
        log.error(f"❌ FESWorker init failed: {e}")
        return False
    
    # Check output dir is writable
    output_dir = os.path.expanduser('~/avidtech6/fv-module-gallery/cms-widgets/')
    if not Path(output_dir).exists():
        try:
            Path(output_dir).mkdir(parents=True, exist_ok=True)
            log.info(f"✅ Output dir created: {output_dir}")
        except Exception as e:
            log.error(f"❌ Cannot create output dir: {e}")
            return False
    else:
        log.info(f"✅ Output dir exists: {output_dir}")
    
    log.info("Health check PASS")
    return True


def run(input_path, output_dir, max_workers=2, dry_run=False):
    """Process widgets from input, write to output_dir."""
    started = time.time()
    log.info(f"Run starting. input={input_path} output={output_dir} workers={max_workers} dry_run={dry_run}")
    
    try:
        widgets = parse_input(input_path)
    except Exception as e:
        log.error(f"❌ Input parse failed: {e}")
        return 1
    
    log.info(f"✅ Parsed {len(widgets)} widgets from input")
    
    if dry_run:
        log.info("Dry-run mode: validating without writing")
        # Just validate each widget has required fields
        for i, w in enumerate(widgets):
            if not isinstance(w, dict):
                log.error(f"❌ Widget {i}: not a dict, got {type(w).__name__}")
                return 1
            if 'id' not in w:
                log.error(f"❌ Widget {i}: missing 'id' field")
                return 1
            if 'type' not in w:
                log.error(f"❌ Widget {i}: missing 'type' field")
                return 1
        log.info(f"✅ All {len(widgets)} widgets have id+type. Dry-run PASS")
        return 0
    
    try:
        fes_worker, _ = load_fes_worker()
    except Exception as e:
        log.error(f"❌ Bridge init failed: {e}")
        return 1
    
    try:
        worker = fes_worker.FESWorker(WCP_CATALOG_DEFAULT)
    except Exception as e:
        log.error(f"❌ FESWorker init failed: {e}")
        return 1
    
    try:
        worker.process_batch(widgets, output_dir, max_workers=max_workers)
    except Exception as e:
        log.error(f"❌ process_batch failed: {e}")
        return 1
    
    duration = time.time() - started
    log.info(f"Run finished in {duration:.1f}s. completed={worker.completed} failed={worker.failed} shape_failures={worker.shape_failures}")
    return 0 if worker.failed == 0 else 1


def main():
    parser = argparse.ArgumentParser(
        description="FES Bridge — robust wrapper around fes_worker.py",
        formatter_class=argparse.RawDescriptionHelpFormatter,
        epilog="""
Examples:
  python3 fes_bridge.py health
  python3 fes_bridge.py run widgets.json /tmp/output
  python3 fes_bridge.py dry-run widgets.json
  cat widgets.json | python3 fes_bridge.py run - /tmp/output
        """
    )
    sub = parser.add_subparsers(dest='command', required=True)
    
    sub.add_parser('health', help='Verify the bridge can run')
    
    p_run = sub.add_parser('run', help='Process widgets from input')
    p_run.add_argument('input', help='Input file (JSON or YAML, or "-" for stdin)')
    p_run.add_argument('output_dir', nargs='?', default=None, help='Output directory')
    p_run.add_argument('--workers', type=int, default=2, help='Max workers (default 2)')
    
    p_dry = sub.add_parser('dry-run', help='Validate without writing')
    p_dry.add_argument('input', help='Input file')
    
    args = parser.parse_args()
    
    if args.command == 'health':
        return 0 if health_check() else 1
    elif args.command == 'run':
        return run(args.input, args.output_dir, args.workers, dry_run=False)
    elif args.command == 'dry-run':
        return run(args.input, '/tmp/dry-run-output', max_workers=1, dry_run=True)


if __name__ == '__main__':
    sys.exit(main())
