#!/usr/bin/env python3
"""
Build COMPLETE GTFS database for aNavigator.
ALL trips, ALL stops, ALL shapes - nothing removed.
Uses compact JSON encoding for minimal file size.
"""
import csv, json, sys, os
from collections import defaultdict, OrderedDict

GTFS_DIR = sys.argv[1] if len(sys.argv) > 1 else "/tmp/gtfs_tper"
OUTPUT = sys.argv[2] if len(sys.argv) > 2 else "/home/alina/aNavigator/src/gtfs_db.json"

print(f"Reading GTFS from {GTFS_DIR}...")

# 1. Routes
print("Loading routes...")
routes = {}
with open(os.path.join(GTFS_DIR, "routes.txt"), encoding="utf-8") as f:
    for row in csv.DictReader(f):
        routes[row["route_id"]] = row

# 2. Stops
print("Loading stops...")
stops = {}
with open(os.path.join(GTFS_DIR, "stops.txt"), encoding="utf-8") as f:
    for row in csv.DictReader(f):
        stops[row["stop_id"]] = {
            "n": row["stop_name"].strip(),
            "lat": round(float(row["stop_lat"]), 6),
            "lon": round(float(row["stop_lon"]), 6)
        }
print(f"  {len(stops)} stops loaded")

# 3. Shapes
print("Loading shapes (this may take a moment)...")
shapes = defaultdict(list)
with open(os.path.join(GTFS_DIR, "shapes.txt"), encoding="utf-8") as f:
    for row in csv.DictReader(f):
        coords = [round(float(row["shape_pt_lat"]), 6), round(float(row["shape_pt_lon"]), 6)]
        shapes[row["shape_id"]].append(coords)
print(f"  {len(shapes)} shapes loaded")

# Simplify shape helper
def simplify_shape(coords, max_pts=150):
    if len(coords) <= max_pts:
        return coords
    step = len(coords) / max_pts
    res = [coords[min(int(i * step), len(coords)-1)] for i in range(max_pts)]
    if res[-1] != coords[-1]:
        res[-1] = coords[-1]
    return res

# 4. Stop times indexed by trip_id
print("Loading stop_times...")
stop_times_by_trip = defaultdict(list)
with open(os.path.join(GTFS_DIR, "stop_times.txt"), encoding="utf-8") as f:
    for row in csv.DictReader(f):
        stop_times_by_trip[row["trip_id"]].append({
            "s": row["stop_id"],
            "seq": int(row["stop_sequence"]),
            "a": row.get("arrival_time", "")[:5],
            "d": row.get("departure_time", "")[:5]
        })
print(f"  {len(stop_times_by_trip)} trips indexed")

# 5. Calendar
print("Loading calendar...")
calendar = {}
with open(os.path.join(GTFS_DIR, "calendar.txt"), encoding="utf-8") as f:
    for row in csv.DictReader(f):
        days = []
        for d in ['monday','tuesday','wednesday','thursday','friday','saturday','sunday']:
            if row.get(d) == '1':
                days.append(d[:3])
        calendar[row["service_id"]] = ",".join(days)
print(f"  {len(calendar)} entries")

# Map service pattern to label
def service_label(pattern):
    if not pattern:
        return ""
    if pattern == "mon,tue,wed,thu,fri":
        return "Feriale"
    if pattern == "sat":
        return "Sabato"
    if pattern == "sun":
        return "Domenica"
    if "sat" in pattern and "sun" in pattern:
        return "Festivo"
    if "sat" in pattern:
        return "Sabato"
    if "sun" in pattern:
        return "Domenica"
    if "mon" in pattern:
        return "Feriale"
    return ""

# 6. Load ALL trips
print("Loading trips...")
trips_by_route = defaultdict(list)
with open(os.path.join(GTFS_DIR, "trips.txt"), encoding="utf-8") as f:
    for row in csv.DictReader(f):
        trips_by_route[row["route_id"]].append(row)

# 7. Build database - EVERY trip individually
print("Building database with ALL trips...")
db = {"lines": OrderedDict()}

sorted_routes = sorted(
    routes.values(),
    key=lambda r: (
        int(r["route_short_name"]) if r["route_short_name"].strip().isdigit() else 999,
        r["route_short_name"]
    )
)

total_trips_written = 0
total_lines = 0

for route in sorted_routes:
    short_name = route["route_short_name"].strip()
    route_id = route["route_id"]
    long_name = route["route_long_name"].strip()
    
    trip_rows = trips_by_route.get(route_id, [])
    if not trip_rows:
        continue
    
    # Group trips by (direction_id, service_id) to create variants
    # Most lines have multiple variants due to different terminus
    groups = defaultdict(list)
    for t in trip_rows:
        key = (t["direction_id"], t["service_id"])
        groups[key].append(t)
    
    # Build a mapping: service_id -> day pattern
    svc_patterns = {}
    for key, trips_list in groups.items():
        dir_id, svc_id = key
        svc_patterns[svc_id] = calendar.get(svc_id, "")
    
    # Now group by service pattern AND shape to identify variants
    # A variant = trips that share same shape (path) and service pattern
    variant_groups = defaultdict(list)
    for t in trip_rows:
        sid = t["shape_id"]
        svc = t["service_id"]
        pat = service_label(svc_patterns.get(svc, ""))
        # Use shape_id + direction + service_label as variant key
        variant_key = (sid, t["direction_id"], pat)
        variant_groups[variant_key].append(t)
    
    # Build line entries: map short_name -> list of all trips
    # But Tper often has the same short_name with multiple route_ids
    # We'll append trips as we go
    
    # Actually simpler: just add ALL trips directly to a single line
    # Unless they have different long names (different route_id)
    line_key = short_name
    if line_key not in db["lines"]:
        db["lines"][line_key] = {"name": long_name, "trips": []}
    
    for t in trip_rows:
        sid = t["shape_id"]
        shape_coords = simplify_shape(shapes.get(sid, []))
        if len(shape_coords) < 2:
            continue
        
        trip_stops = stop_times_by_trip.get(t["trip_id"], [])
        trip_stops.sort(key=lambda x: x["seq"])
        
        stop_info = []
        for s in trip_stops:
            sid_stop = s["s"]
            if sid_stop in stops:
                entry = dict(stops[sid_stop])
                if s.get("a"):
                    entry["a"] = s["a"]
                if s.get("d"):
                    entry["d"] = s["d"]
                stop_info.append(entry)
        
        if not stop_info:
            continue
        
        headsign = t.get("trip_headsign", "").strip()
        if not headsign:
            headsign = stop_info[0]["n"] + " → " + stop_info[-1]["n"]
        
        dir_id = int(t["direction_id"])
        pattern = svc_patterns.get(t["service_id"], "")
        label = service_label(pattern)
        
        # Departure = departure from first stop (or arrival if no departure)
        dep = stop_info[0].get("d", stop_info[0].get("a", ""))
        
        db["lines"][line_key]["trips"].append({
            "dir": dir_id,
            "h": headsign,
            "svc": label,
            "dep": dep,
            "shape": shape_coords,
            "stops": stop_info
        })
        total_trips_written += 1
    
    total_lines += 1

print(f"  Built {total_lines} line entries with {total_trips_written} total trips")

# 8. Output
with open(OUTPUT, "w", encoding="utf-8") as f:
    json.dump(db, f, ensure_ascii=False, separators=(",", ":"))

size_mb = os.path.getsize(OUTPUT) / (1024*1024)
print(f"Written to {OUTPUT} ({size_mb:.1f} MB)")
print("Done!")
