"""
Map-matching Orchestrator.

Manages the chunked, out-of-core streaming of GPS trajectories through
the routing engine backend and immediately writes snapped records to disk.
"""

import logging
from pathlib import Path
from typing import TYPE_CHECKING, List, Optional, Tuple, Union

from ..ingest import write_walks
from .gps import GPSDataset
from .base import BaseMatcher

if TYPE_CHECKING:
    from ...core.network import Network
    from ...core.walk import WalkFrame

logger = logging.getLogger(__name__)


def match_trajectories(
    dataset: GPSDataset,
    backend: BaseMatcher,
    network: "Network",
    output_dir: Union[str, Path],
    chunk_size_walks: int = 1000,
) -> "WalkFrame":
    """Stream GPS data through the matcher and write Parquet incrementally.

    Args:
        dataset: Out-of-core GPS dataset.
        backend: A :class:`BaseMatcher` implementation.
        network: The walkingpandas Network.
        output_dir: Directory for output Parquet chunks.
        chunk_size_walks: Number of walks per processing chunk.

    Returns:
        A :class:`WalkFrame` over the written Parquet files.

    Raises:
        ValueError: If no trajectories could be matched.
    """
    from ...core.walk import WalkFrame

    out_dir = Path(output_dir)
    out_dir.mkdir(parents=True, exist_ok=True)

    all_walks = dataset.get_unique_walk_ids()
    chunk_index = 0

    for i in range(0, len(all_walks), chunk_size_walks):
        walk_chunk = all_walks[i : i + chunk_size_walks]

        chunk_df = dataset.load_walks(walk_chunk)
        if chunk_df.empty:
            continue

        matched_df = backend.match(chunk_df, walk_id_col="walk_id")

        if not matched_df.empty:
            out_file = out_dir / f"chunk_{chunk_index:06d}.parquet"
            write_walks(matched_df, out_file, schema_validate=False)
            chunk_index += 1

    if chunk_index == 0:
        raise ValueError("No trajectories were successfully matched.")

    return WalkFrame(str(out_dir / "*.parquet"), network=network)

