"""
FGIP Seed Loader - Load nodes and edges from JSON seed files.

Seed file formats:

seed_nodes.json:
[
    {"node_id": "ORG:us_chamber", "node_type": "ORGANIZATION", "name": "U.S. Chamber of Commerce"},
    ...
]

seed_edges.json:
[
    {
        "edge_type": "LOBBIED",
        "from_node_id": "ORG:us_chamber",
        "to_node_id": "LEG:pntr_2000",
        "status": "CLAIMED",
        "attrs": {"amount": 1000000},
        "sources": [
            {"url": "https://example.com/doc.pdf"},
            {"file": "local/doc.pdf"}
        ]
    },
    ...
]
"""

import json
from datetime import datetime
from pathlib import Path
from typing import List, Dict, Any, Optional, Tuple

from .models import EdgeStatus, Sensitivity
from .engine import CausalityEngine


def load_seed_nodes(
    engine: CausalityEngine,
    nodes_file: Path,
) -> Tuple[int, List[str]]:
    """
    Load nodes from a JSON seed file.

    Args:
        engine: CausalityEngine instance
        nodes_file: Path to seed_nodes.json

    Returns:
        Tuple of (loaded_count, node_ids)
    """
    nodes_file = Path(nodes_file)

    with open(nodes_file) as f:
        nodes_data = json.load(f)

    loaded_ids = []

    for node in nodes_data:
        node_id = node['node_id']
        node_type = node['node_type']
        name = node['name']
        metadata = node.get('metadata', {})

        try:
            engine.add_node(node_id, node_type, name, metadata)
            loaded_ids.append(node_id)
        except Exception as e:
            # Node may already exist
            print(f"Warning: Could not add node {node_id}: {e}")

    return len(loaded_ids), loaded_ids


def load_seed_edges(
    engine: CausalityEngine,
    edges_file: Path,
    attach_sources: bool = True,
) -> Tuple[int, List[str]]:
    """
    Load edges from a JSON seed file.

    Args:
        engine: CausalityEngine instance
        edges_file: Path to seed_edges.json
        attach_sources: Whether to fetch/store sources

    Returns:
        Tuple of (loaded_count, edge_ids)
    """
    edges_file = Path(edges_file)

    with open(edges_file) as f:
        edges_data = json.load(f)

    loaded_ids = []

    for edge in edges_data:
        edge_type = edge['edge_type']
        from_node = edge['from_node_id']
        to_node = edge['to_node_id']

        # Parse status
        status_str = edge.get('status', 'CLAIMED')
        status = EdgeStatus[status_str] if status_str else EdgeStatus.CLAIMED

        # Parse sensitivity
        sensitivity_str = edge.get('sensitivity', 'LOW')
        sensitivity = Sensitivity[sensitivity_str] if sensitivity_str else Sensitivity.LOW

        # Parse dates
        date_start = None
        date_end = None
        if edge.get('date_occurred_start'):
            date_start = datetime.fromisoformat(edge['date_occurred_start'])
        if edge.get('date_occurred_end'):
            date_end = datetime.fromisoformat(edge['date_occurred_end'])

        # Get attributes
        attrs = edge.get('attrs', {})

        try:
            edge_id = engine.add_edge(
                edge_type=edge_type,
                from_node=from_node,
                to_node=to_node,
                edge_id=edge.get('edge_id'),
                status=status,
                sensitivity=sensitivity,
                confidence=edge.get('confidence'),
                date_occurred_start=date_start,
                date_occurred_end=date_end,
                notes=edge.get('notes'),
                attrs=attrs,
            )
            loaded_ids.append(edge_id)

            # Attach sources if present
            if attach_sources and 'sources' in edge:
                for source in edge['sources']:
                    try:
                        if 'url' in source:
                            engine.attach_source(
                                edge_id,
                                url=source['url'],
                                claim_excerpt=source.get('claim_excerpt'),
                                page_ref=source.get('page_ref'),
                            )
                        elif 'file' in source:
                            engine.attach_source(
                                edge_id,
                                file=Path(source['file']),
                                claim_excerpt=source.get('claim_excerpt'),
                                page_ref=source.get('page_ref'),
                            )
                        elif 'source_id' in source:
                            engine.attach_source(
                                edge_id,
                                source_id=source['source_id'],
                                claim_excerpt=source.get('claim_excerpt'),
                                page_ref=source.get('page_ref'),
                            )
                    except Exception as e:
                        print(f"Warning: Could not attach source to {edge_id}: {e}")

        except Exception as e:
            print(f"Warning: Could not add edge {edge_type} {from_node}->{to_node}: {e}")

    return len(loaded_ids), loaded_ids


def load_seeds(
    engine: CausalityEngine,
    seed_dir: Path,
    nodes_file: str = "seed_nodes.json",
    edges_file: str = "seed_edges.json",
    attach_sources: bool = True,
) -> Dict[str, Any]:
    """
    Load both nodes and edges from a seed directory.

    Args:
        engine: CausalityEngine instance
        seed_dir: Directory containing seed files
        nodes_file: Filename for nodes (default: seed_nodes.json)
        edges_file: Filename for edges (default: seed_edges.json)
        attach_sources: Whether to fetch/store sources

    Returns:
        Dict with loading statistics
    """
    seed_dir = Path(seed_dir)

    result = {
        "nodes_loaded": 0,
        "edges_loaded": 0,
        "node_ids": [],
        "edge_ids": [],
        "errors": [],
    }

    # Load nodes first
    nodes_path = seed_dir / nodes_file
    if nodes_path.exists():
        try:
            count, ids = load_seed_nodes(engine, nodes_path)
            result["nodes_loaded"] = count
            result["node_ids"] = ids
        except Exception as e:
            result["errors"].append(f"Failed to load nodes: {e}")

    # Load edges
    edges_path = seed_dir / edges_file
    if edges_path.exists():
        try:
            count, ids = load_seed_edges(engine, edges_path, attach_sources)
            result["edges_loaded"] = count
            result["edge_ids"] = ids
        except Exception as e:
            result["errors"].append(f"Failed to load edges: {e}")

    return result


def validate_seed_file(seed_file: Path) -> Tuple[bool, List[str]]:
    """
    Validate a seed file format.

    Args:
        seed_file: Path to JSON seed file

    Returns:
        Tuple of (is_valid, error_messages)
    """
    seed_file = Path(seed_file)
    errors = []

    if not seed_file.exists():
        return False, [f"File not found: {seed_file}"]

    try:
        with open(seed_file) as f:
            data = json.load(f)
    except json.JSONDecodeError as e:
        return False, [f"Invalid JSON: {e}"]

    if not isinstance(data, list):
        return False, ["Seed file must contain a JSON array"]

    # Detect file type by content
    if len(data) == 0:
        return True, []  # Empty is valid

    first = data[0]

    # Node validation
    if 'node_id' in first:
        for i, node in enumerate(data):
            if not isinstance(node, dict):
                errors.append(f"Node {i}: must be an object")
                continue
            if 'node_id' not in node:
                errors.append(f"Node {i}: missing node_id")
            if 'node_type' not in node:
                errors.append(f"Node {i}: missing node_type")
            if 'name' not in node:
                errors.append(f"Node {i}: missing name")

    # Edge validation
    elif 'edge_type' in first:
        for i, edge in enumerate(data):
            if not isinstance(edge, dict):
                errors.append(f"Edge {i}: must be an object")
                continue
            if 'edge_type' not in edge:
                errors.append(f"Edge {i}: missing edge_type")
            if 'from_node_id' not in edge:
                errors.append(f"Edge {i}: missing from_node_id")
            if 'to_node_id' not in edge:
                errors.append(f"Edge {i}: missing to_node_id")

            # Validate status if present
            if 'status' in edge:
                if edge['status'] not in ['CLAIMED', 'EVIDENCED', 'DISPUTED', 'RETRACTED']:
                    errors.append(f"Edge {i}: invalid status '{edge['status']}'")

            # Validate sensitivity if present
            if 'sensitivity' in edge:
                if edge['sensitivity'] not in ['LOW', 'MED', 'HIGH']:
                    errors.append(f"Edge {i}: invalid sensitivity '{edge['sensitivity']}'")

    else:
        errors.append("Could not determine file type (neither nodes nor edges)")

    return len(errors) == 0, errors
