using System.Collections.Generic;
namespace IslaApocalypse.Tools
{
///
/// ⭐⭐ ONE CANDIDATE MAJOR DRAINAGE — the unit the river count is chosen over (rivers/02).
///
/// ═══ WHY THIS TYPE EXISTS: ONE LIST, NOT TWO ═══
///
/// The reference promoted rivers from TWO separate lists with TWO separate quotas — N sea-reaching
/// trunks and N endorheic giants (DrainageAnalysis.Params.TrunkCount / GiantCount,
/// both 3). That structure encodes an assumption this terrain does not satisfy: that reaching the
/// sea is what makes a drainage a river, and inland ones are a second category to be quota'd
/// separately.
///
/// **On the reshaped terrain ~68 % of land drains INLAND** (measured: 67.6 % on the primary seed,
/// 116 terminal basins). A separate quota would fight that — it would promote small coastal
/// drainages over far larger inland ones purely because of where they end.
///
/// > ### So selection is UNIFIED: rank every major drainage by contributing area, promote the top N,
/// > and let the sea-vs-endorheic split FALL OUT of which promoted rivers happen to reach the ocean.
/// > **An endorheic terminus is a PASS, not a fallback** — a river ending in a significant lake is
/// > as real as one reaching the coast, and is never forced to the coast.
///
/// ⚠ This is a DELIBERATE DEPARTURE from the reference's two-list structure (approved in chat;
/// D-050 port-discipline noted). Only the SELECTION is unified — is retained
/// per river because downstream routing branches on it, and Trunk / Giant are left
/// exactly as ported.
///
/// ═══ ⚠ THE METRIC IS THE SAME UNIT ON BOTH SIDES, AND THAT IS LOAD-BEARING ═══
///
/// is a COUNT OF CONTRIBUTING LAND CELLS in both cases, computed on the
/// same D8 field in the same pass:
///
/// SEA Plan.Acc at the outlet — every non-ocean cell is seeded 1 and accumulated
/// along Plan.Dir, so the outlet's value is the count of cells whose flow path
/// passes through it.
/// ENDORHEIC Plan.BasinInflow[BasinId] — the memoised downstream walk over the SAME
/// Dir, counting cells whose flow TERMINATES in that basin.
///
/// Every land cell has exactly one destination, so the two populations are disjoint and exhaustive:
/// Σ sea-outlet Acc + Σ BasinInflow + UnroutedCells == LandCells. `RiverPromotionTool`
/// ASSERTS that identity per seed — it is the mechanical proof that one ranking over both is sound.
///
public sealed class RiverCandidate
{
/// ⭐ The terminus. True = the outlet touches RegionLabeling.OceanMask; false = it pools in a terminal basin. Never a bare h < sea test.
public bool IsSea;
/// Row-major cell: the sea outlet, or the terminal basin's MINIMUM (its deepest cell).
public int Cell;
public int X, Y;
///
/// ⭐ Where the RIVER actually ends — the point its main stem pools at, i.e. the first point of
/// . Defaults to / until bound.
///
/// ⚠⚠ FOR AN ENDORHEIC RIVER THIS IS NOT THE BASIN'S DEEPEST CELL, and the difference is
/// visible on a map. `DrainageAnalysis` is explicit about why: *"Terminal is where the MAIN
/// STEM actually pools (its sub-minimum), which on a flat basin floor is more truthful than the
/// basin's deepest cell."* On a wide flat lagoon bed those two points can sit far apart.
///
/// Both are real and both are kept: the basin minimum is the BASIN's identity (and is what the
/// CSV records), this is the RIVER's terminus (and is what the plates mark). Marking a river at
/// its basin's deepest cell draws the stem visibly detached from its own endpoint — which reads
/// as a broken river and would corrupt a count judgment.
///
public int TermX, TermY;
/// ⭐ THE RANKING METRIC — contributing land cells. Same unit for both termini (see the class note).
public long DrainagePx;
/// Terminal-basin id (endorheic only; 0 for sea). The stable key for binding a candidate to its Giant.
public int BasinId;
/// Endorheic only: the basin's max fill depth, metres.
public float BasinDepthM;
/// Endorheic only: the basin's area in cells.
public long BasinAreaPx;
///
/// ⚠ Sea only. True when this outlet was DROPPED by the MinOutletSeparationPx rule
/// because a larger outlet sits within that radius. Kept in the distribution (it is a real
/// drainage) but excluded from ranking — see the tool's note on what separation discards.
///
public bool SuppressedBySeparation;
///
/// The REAL upland stem — the max-accumulation traced course from DrainageAnalysis's own
/// TraceStem, bound after selection. Null for candidates outside the promoted set.
/// ⚠ Downstream-first and decimated ×4, as the analysis produces it.
/// ⚠⚠ This is the erosion-carved course, NOT Giant.ProvisionalRoute — the steepest-descent
/// placeholder ("the comb") is deliberately never drawn here; replacing it is rivers/03's job,
/// and drawing it would mislead a count judgment.
///
public List<(float x, float y)> Course;
/// 1-based rank in the unified descending ranking. 0 until ranked.
public int Rank;
///
/// ⭐ rivers/03 — THE ANALYSIS'S OWN routed/lake-ender verdict, copied from Giant.Kind at
/// bind time. Endorheic only ("" for sea candidates).
///
/// ⚠⚠ READ THE TEST BEFORE TRUSTING THE NAME. `DrainageAnalysis` assigns this as
/// (basinHasLake[id] && !SouthernCandidate) ? "lake-ender" : "routed" — i.e. purely on
/// **whether the terminal basin holds classify water**. It is NOT a path test: "routed" means
/// "this basin is a dry pan, so it SHOULD be routed", not "a route to the sea exists". Whether
/// one actually does is what `RiverRouting.RouteToOcean` decides, and the two CAN disagree.
/// rivers/03 reports both per river rather than silently picking one.
///
public string AnalysisKind = "";
/// Endorheic only: the analysis found classify water in this terminal basin.
public bool TerminalInClassifyWater;
public string TerminusName => IsSea ? "sea" : "endorheic";
}
}