#!/usr/bin/env python3
"""walking.py - distances, elevation changes and walking-time envelopes for the tent -> cedar descent
and the attempted return (Dyatlov, Slobodin, Kolmogorova).

Inputs: data/coordinates.csv, out/dem_summary.json (from dem_slope.py).
Walking-speed assumptions (cited in the write-up): on wind-packed crust/firn 2-4 km/h; in knee-deep loose
snow 1-2 km/h; in thigh-deep forest snow 0.5-1 km/h (Pandolf et al. 1976 / Soule & Goldman 1972 energy-cost
work implies 2-5x the energy of trail walking for 25-45 cm footprint depth; Richmond et al. 2019 give
terrain coefficients 1.3-4.6 for snow). Uphill in the dark on crust with bare/socked feet: 1-2 km/h.
Output: out/walking.md, out/distances.csv
"""
import csv, json, math, os
from geo_common import OUT, load_coordinates, haversine, bearing

C = load_coordinates(); S = json.load(open(os.path.join(OUT, "dem_summary.json")))
tent = C["tent_dyatlovpass_map"]
pairs = [("tent_dyatlovpass_map", "cedar"), ("tent_dyatlovpass_map", "kolmogorova"), ("tent_dyatlovpass_map", "slobodin"), ("tent_dyatlovpass_map", "dyatlov"),
         ("tent_dyatlovpass_map", "den_flooring"), ("cedar", "dyatlov"), ("dyatlov", "slobodin"), ("slobodin", "kolmogorova"), ("cedar", "kolmogorova"),
         ("cedar", "den_flooring"), ("tent_dyatlovpass_map", "labaz"), ("labaz", "searchers_camp_1959"), ("tent_dyatlovpass_map", "kholat_syakhl_summit_dem"),
         ("tent_dyatlovpass_map", "pass_memorial_osm"), ("tent_dyatlovpass_map", "tent_prosecutors_2019"), ("tent_dyatlovpass_map", "new_monument_sculpture"),
         ("tent_dyatlovpass_map", "tent_borzenkov_gps_2009"), ("tent_dyatlovpass_map", "tent_semyashkin_2010_as_published"), ("cedar", "pass_memorial_osm"),
         ("tent_dyatlovpass_map", "helipad_1959"), ("tent_dyatlovpass_map", "incident_enwiki"), ("kholat_syakhl_summit_map", "kholat_syakhl_summit_dem")]
casefile = {("tent_dyatlovpass_map", "cedar"): "1500 (Ivanov, sheet 386; Maslennikov scheme)", ("cedar", "dyatlov"): "300 (Ivanov; Maslennikov) / 400 (scene protocol sheet 4)",
            ("dyatlov", "slobodin"): "180 (Ivanov)", ("slobodin", "kolmogorova"): "150 (Ivanov)", ("cedar", "kolmogorova"): "630 = 300+180+150 (Ivanov); 650-700 (Maslennikov: 300+350)",
            ("cedar", "den_flooring"): "75 (Ivanov) / 70 (Maslennikov scheme) / 50 (den protocol sheet 341)", ("labaz", "searchers_camp_1959"): "400 (radiogram 2 Mar)",
            ("tent_dyatlovpass_map", "kholat_syakhl_summit_dem"): "300 (sheet 2 tent protocol) / 100-150 (Chernyshev sheet 88)", ("tent_dyatlovpass_map", "tent_prosecutors_2019"): "115-116 (Konstantinov; dyatlovpass map)"}
rows = []
for a, b in pairs:
    A, B = C[a], C[b]
    d = haversine(A["lat"], A["lon"], B["lat"], B["lon"]); brg = bearing(A["lat"], A["lon"], B["lat"], B["lon"])
    rows.append({"from": a, "to": b, "distance_m": round(d), "bearing_deg": round(brg), "case_file_m": casefile.get((a, b), "")})
with open(os.path.join(OUT, "distances.csv"), "w", newline="") as f:
    w = csv.DictWriter(f, fieldnames=list(rows[0].keys())); w.writeheader(); w.writerows(rows)

L = S["tent_to_cedar_horizontal_m"]; drop = S["tent_to_cedar_drop_m"]
prof = {float(r["dist_m"]): float(r["elev_m"]) for r in csv.DictReader(open(os.path.join(OUT, "profile_tent_cedar.csv")))}
Z850 = prof[850.0]   # elevation where Maslennikov's scheme puts the 'start of the snow zone' (~850 m below the tent)
zt, zc = S["tent_elev_m"], S["cedar_elev_m"]
B = S["bodies_along_line_m"]
md = ["# Distances and walking-time envelopes (generated by walking.py)", "", "## Distances between mapped points (haversine on the dyatlovpass.com placemarks)", "",
      "| from | to | distance (m) | bearing (deg true) | case-file figure (m) |", "|---|---|---|---|---|"]
for r in rows:
    md.append(f"| {r['from']} | {r['to']} | {r['distance_m']} | {r['bearing_deg']} | {r['case_file_m']} |")
md += ["", "## Tent -> cedar descent", "", f"- Horizontal distance {L:.0f} m, elevation {zt:.0f} m -> {zc:.0f} m, drop {drop:.0f} m, mean gradient {S['tent_to_cedar_mean_slope_deg']} deg (Copernicus GLO-30).",
       f"- The three bodies on the slope lie within {max(abs(B[k]['offset_m']) for k in ['kolmogorova','slobodin','dyatlov']):.0f} m of the straight tent-cedar line (offsets: Kolmogorova {B['kolmogorova']['offset_m']:.0f} m, Slobodin {B['slobodin']['offset_m']:.0f} m, Dyatlov {B['dyatlov']['offset_m']:.0f} m; negative = right/south of the line looking downhill).",
       "- Snow conditions from the case file: wind-packed crust on the open slope (footprints preserved as raised columns for 500 m to ~1 km below the tent: sheets 160, 386; Tempalov sheet 309-312: 'walking a normal step down the mountain'), then loose snow 1-2 m+ deep from the forest edge (radiograms sheets 169-170; Maslennikov scheme: 'start of the snow zone' ~850 m below the tent).",
       "", "| segment | length (m) | drop (m) | surface | speed range (km/h) | time range (min) |", "|---|---|---|---|---|---|"]
segs = [("tent -> start of deep snow (~850 m)", 850, zt - Z850, "wind crust, 10-16 deg, dark", (2.0, 4.0)),
        ("deep-snow zone -> cedar (~700 m)", L - 850, Z850 - zc, "loose snow 1-2 m, birch/forest edge", (0.7, 2.0))]
tot_min, tot_max = 0, 0
for name, ln, dz, surf, (v1, v2) in segs:
    t1, t2 = ln / (v2 * 1000 / 60), ln / (v1 * 1000 / 60); tot_min += t1; tot_max += t2
    md.append(f"| {name} | {ln:.0f} | {dz:.0f} | {surf} | {v1}-{v2} | {t1:.0f}-{t2:.0f} |")
md.append(f"| **total** | {L:.0f} | {drop:.0f} | | | **{tot_min:.0f}-{tot_max:.0f}** |")
md += ["", f"So the descent plausibly took ~{tot_min:.0f}-{tot_max:.0f} min (a fast, purposeful group on crust could do it in about half an hour; stragglers in socks, in the dark, in deep forest snow, over an hour). Krivonischenko's and Doroshenko's fire under the cedar therefore cannot have been lit before roughly 30 min after leaving the tent.",
       "", "## Attempted return: positions relative to the tent", "", "| body | from cedar (m) | from tent (m) | elevation (m) | climbed from cedar (m) | remaining climb to tent (m) | remaining distance (m) |", "|---|---|---|---|---|---|---|"]
for k, lab in [("dyatlov", "Dyatlov"), ("slobodin", "Slobodin"), ("kolmogorova", "Kolmogorova")]:
    b = B[k]
    md.append(f"| {lab} | {b['from_cedar_m']:.0f} | {b['along_m']:.0f} | {b['elev_m']:.0f} | {b['elev_m']-zc:.0f} | {zt-b['elev_m']:.0f} | {L-b['along_m']:.0f} |")
kb = B["kolmogorova"]
t_k = [kb["from_cedar_m"] / (v * 1000 / 60) for v in (2.0, 1.0)]
md += ["", f"- Kolmogorova's position ({kb['from_cedar_m']:.0f} m from the cedar, {L - kb['along_m']:.0f} m short of the tent, {zt - kb['elev_m']:.0f} m below it) is on the tent-cedar line to within {abs(kb['offset_m']):.0f} m, on the open wind-crust part of the slope (gradient ~10 deg there), with the head toward the tent (scene protocol sheet 4-5; Maslennikov sheet 62-75). At 1-2 km/h uphill the {kb['from_cedar_m']:.0f} m from the cedar takes {t_k[0]:.0f}-{t_k[1]:.0f} min; she had covered {100*kb['from_cedar_m']/L:.0f} % of the horizontal distance and {100*(kb['elev_m']-zc)/drop:.0f} % of the climb.",
       f"- Dyatlov ({B['dyatlov']['from_cedar_m']:.0f} m) and Slobodin ({B['slobodin']['from_cedar_m']:.0f} m) are spaced ~150-180 m apart along the same line; the ordering (Kolmogorova highest, Dyatlov lowest) is what a staggered attempt to regain the tent - or a staggered descent - would produce; the positions alone do not distinguish the two, but the body orientations recorded in 1959 (heads toward the tent, Kolmogorova's pose 'climbing') favour a return attempt.",
       f"- Slobodin's and Dyatlov's watches stopped at 8:45 and 5:31 (Ivanov, sheet 386); Thibeaux-Brignolle's at 8:14 and 8:39 - these are not times of death (a wound mechanical watch runs ~36 h after its last winding and cold can stop it sooner; the Gaume-Puzrin supplement also notes watches 'generally stop in such cold weather'), so they cannot be used to time the return.",
       "", "Speed references: Pandolf, Givoni & Goldman (1977, J. Appl. Physiol. 43:577) terrain factor for snow rises with footprint depth (roughly 1.3 + 0.08 x depth in cm, i.e. 2.9 at 20 cm, 4.5 at 40 cm); Soule & Goldman (1972) report walking in 30-45 cm snow at 1.6-2.5 km/h cost 2-3x the energy of trail walking; typical sustained speeds quoted for unbroken deep snow without skis/snowshoes are 1-2 km/h, and <1 km/h in waist-deep snow. The descent here mostly ran over wind-packed crust (footprints stood proud as columns, sheets 160/386), where 3-4 km/h is normal even in socks."]
open(os.path.join(OUT, "walking.md"), "w").write("\n".join(md))
print("\n".join(md))
