#!/usr/bin/env python3
"""
viewer.py

Load JSON metadata produced by scanner.py and display it as a tree.

Usage:
  viewer.py [OPTIONS] JSON_FILE

Options:
  -v, --verbose           Enable debug logging.

Examples:
  # View scan output:
  viewer.py scan.json

  # View with debug logging:
  viewer.py -v scan.json
"""

import argparse
import json
import logging
import sys
from pathlib import Path
from typing import Any, Dict, List, Tuple


def format_size(size: int) -> str:
    """
    Format a byte count into a human-readable string.
    """
    if size < 1024:
        return f"{size} B"
    if size < 1024**2:
        return f"{size / 1024:.1f} KB"
    if size < 1024**3:
        return f"{size / 1024**2:.1f} MB"
    return f"{size / 1024**3:.1f} GB"


def load_scan(file_path: Path) -> Dict[str, Any]:
    """
    Load and validate scanner JSON output. Exits on error if invalid.
    """
    if not file_path.is_file():
        logging.error("File not found: %s", file_path)
        sys.exit(1)
    try:
        raw = file_path.read_text(encoding="utf-8")
        data = json.loads(raw)
    except (OSError, json.JSONDecodeError) as err:
        logging.error("Cannot read or parse JSON '%s': %s", file_path, err)
        sys.exit(1)

    if not isinstance(data, dict) or "items" not in data:
        logging.error("Invalid scan data structure in %s", file_path)
        sys.exit(1)
    return data


def display_structure(data: Dict[str, Any]) -> None:
    """
    Render the scan items as a tree with metadata.
    """
    # Header from JSON keys
    root = data.get("scanned_path", "<unknown>")
    timestamp = data.get("timestamp_utc", "N/A")
    version = data.get("scanner_version", "N/A")
    print(f"Scan Root: {root}")
    print(f"Scan Timestamp: {timestamp}")
    print(f"Schema Version: {version}")
    print("-" * 60)

    items: List[Dict[str, Any]] = data["items"]

    def sort_key(item: Dict[str, Any]) -> Tuple[str, ...]:
        p = item.get("path", "")
        return tuple(Path(p).parts) if p != "." else ()

    items = sorted(items, key=sort_key)
    last_markers: Dict[int, str] = {}

    for idx, entry in enumerate(items):
        path_str = entry.get("path", "")
        # Determine depth and display name
        if path_str == ".":
            depth = 0
            name = Path(root).name or root
            display = f"{name}/"
        else:
            parts = Path(path_str).parts
            depth = len(parts)
            name = parts[-1]
            display = name

        # Build vertical connectors
        prefix = ""
        for lvl in range(depth):
            prefix += last_markers.get(lvl, "│") + "   "

        # Check if last sibling
        is_last = True
        for next_entry in items[idx + 1 :]:
            next_parts = (
                tuple(Path(next_entry.get("path", "")).parts)
                if next_entry.get("path") != "."
                else ()
            )
            if len(next_parts) == depth:
                is_last = False
                break
            if len(next_parts) < depth:
                break

        # Choose branch or end connector
        if is_last:
            prefix += "└── "
            last_markers[depth] = " "
        else:
            prefix += "├── "
            last_markers[depth] = "│"

        # Permissions
        perms = entry.get("permissions", "")

        # File size and extension or symlink target
        extra = ""
        if entry.get("type") == "file":
            sz = entry.get("size_bytes")
            if isinstance(sz, int):
                extra = f" {format_size(sz)}"
            ext = entry.get("extension")
            if ext:
                display += f" [{ext}]"
        elif entry.get("type") == "symlink":
            target = entry.get("symlink_target", "?")
            display += f" -> {target}"

        # Timestamp fields: created, modified, accessed, metadata-changed
        times: List[str] = []
        for label, key in [
            ("Cre", "created_utc"),
            ("Mod", "modified_utc"),
            ("Acc", "accessed_utc"),
            ("Meta", "metadata_changed_utc"),
        ]:
            val = entry.get(key)
            if val:
                times.append(f"{label}: {val}")
        if not times:
            times = ["N/A"]
        time_str = " | ".join(times)

        # Type marker
        typ_char = entry.get("type", "?")[0].upper()
        marker = f"[{typ_char}]"

        # Assemble and print
        details = f"{perms}{extra}"
        print(f"{prefix}{display}  {marker} {details} ({time_str})")


def main() -> None:
    parser = argparse.ArgumentParser(
        description="View structured directory metadata from a JSON file."
    )
    parser.add_argument("json_file", help="JSON file generated by scanner.py")
    parser.add_argument(
        "-v", "--verbose", action="store_true", help="Enable debug logging"
    )
    args = parser.parse_args()

    logging.basicConfig(
        level=logging.DEBUG if args.verbose else logging.INFO,
        format="%(levelname)s: %(message)s",
    )

    scan_data = load_scan(Path(args.json_file))
    display_structure(scan_data)


if __name__ == "__main__":
    main()
