import Erdos1135.ND.Discrepancy.A5ReferenceND31Count

/-!
# Full real-endpoint count splice for ND-3.1

This leaf attaches the strict bottom prefix to the checked inclusive top-count
adapter.  The ambient bad set is partitioned into `n < ceil y` and
`ceil y <= n`; only after applying the inclusive real prefix is the top part
fed to the finite source-block theorem.

No ambient-boundary algebra, rate absorption, `PhaseGap`, or powered cutoff is
used here.
-/

namespace Erdos1135
namespace ND

noncomputable section

local instance nd31FullCountDecidable (p : Prop) : Decidable p :=
  Classical.propDecidable p

/-- If the counting endpoint is at most the fixed Syracuse target, the bad
ratio is zero.  Equality is included: every counted input hits the target at
iterate zero. -/
theorem oddSyracuseBadRatio_eq_zero_of_le
    {b : Nat} {X : Real} (hX0 : 0 <= X) (hXb : X <= (b : Real)) :
    oddSyracuseBadRatio b X = 0 := by
  have hcount : natCountLEReal (oddSyracuseBadSet b) X = 0 := by
    simp only [natCountLEReal, natCountLE, Terras.natCount_eq_count,
      Nat.count_eq_card_filter_range]
    rw [Finset.card_eq_zero]
    simp only [Finset.filter_eq_empty_iff, Finset.mem_range]
    intro n hnRange hnBad
    have hnFloor : n <= Nat.floor X := Nat.lt_succ_iff.mp hnRange
    have hnX : (n : Real) <= X := (Nat.le_floor_iff hX0).mp hnFloor
    have hnb : n <= b := by exact_mod_cast hnX.trans hXb
    apply hnBad.2.2
    exact ⟨0, by simpa only [Function.iterate_zero, id_eq] using hnb⟩
  simp only [oddSyracuseBadRatio, hcount, Nat.cast_zero, zero_div]

/-- The strict bottom portion of any inclusive real prefix has at most
`ceil y` elements.  This bound intentionally counts zero and therefore needs
no positivity hypothesis. -/
theorem natCountLEReal_oddSyracuseBad_bottom_le_ceil
    (b : Nat) (y X : Real) :
    natCountLEReal
        {n : Nat | n ∈ oddSyracuseBadSet b ∧ n < Nat.ceil y} X <=
      Nat.ceil y := by
  unfold natCountLEReal natCountLE
  exact Terras.natCount_le_of_subset_Iio
    (fun _n hn => hn.2) (Nat.floor X + 1)

/-- A universal finite-prefix bound used to absorb the bounded target range
in the later ND-3.1 scalar assembly. -/
theorem oddSyracuseBadRatio_le_two
    (b : Nat) {X : Real} (hX : 1 <= X) :
    oddSyracuseBadRatio b X <= 2 := by
  have hX0 : 0 <= X := zero_le_one.trans hX
  have hXpos : 0 < X := zero_lt_one.trans_le hX
  have hcountNat :
      natCountLEReal (oddSyracuseBadSet b) X <= Nat.floor X + 1 := by
    unfold natCountLEReal natCountLE
    exact Terras.natCount_le _ _
  have hcountReal :
      (natCountLEReal (oddSyracuseBadSet b) X : Real) <= 2 * X := by
    calc
      (natCountLEReal (oddSyracuseBadSet b) X : Real) <=
          ((Nat.floor X + 1 : Nat) : Real) := by
        exact_mod_cast hcountNat
      _ = (Nat.floor X : Real) + 1 := by norm_num
      _ <= X + 1 := by nlinarith [Nat.floor_le hX0]
      _ <= 2 * X := by linarith
  unfold oddSyracuseBadRatio
  exact (div_le_iff₀ hXpos).2 hcountReal

/-- Full real-endpoint count splice.  The bottom prefix has coefficient one;
the factor two belongs only to the already checked top-block cardinal
normalization.

The ambient top set is not asserted to equal a finite block globally.  Its
inclusive prefix is passed unchanged to the checked top-count theorem. -/
theorem oddSyracuseBadRatio_le_ceil_div_add_two_mul_fixedEventTerms
    {b : Nat} {q y X : Real}
    (hb : 1 <= b) (hq : 1 <= q) (hy : 1 <= y) (hX : 1 <= X)
    (hupper : y ^ alpha = X)
    (hwindow : (oddBlock y).Nonempty)
    (hmass : 0 < Tao.logFinsetMass (oddBlock y)) :
    oddSyracuseBadRatio b X <=
      (Nat.ceil y : Real) / X +
        2 *
          (uniformNoHitProbability q y hwindow +
            passFullL1 q y hq hwindow hmass +
            Tao.pmfProb (logOddBlockPMF y hmass)
              {N | b < syracuseOrbitMin N.1}) := by
  let bottom : Set Nat :=
    {n : Nat | n ∈ oddSyracuseBadSet b ∧ n < Nat.ceil y}
  let top : Set Nat :=
    {n : Nat | n ∈ oddSyracuseBadSet b ∧ Nat.ceil y <= n}
  have hsplit : oddSyracuseBadSet b = bottom ∪ top := by
    ext n
    simp only [bottom, top, Set.mem_union, Set.mem_setOf_eq]
    constructor
    · intro hn
      by_cases hny : n < Nat.ceil y
      · exact Or.inl ⟨hn, hny⟩
      · exact Or.inr ⟨hn, Nat.le_of_not_gt hny⟩
    · rintro (⟨hn, _⟩ | ⟨hn, _⟩) <;> exact hn
  have hdisj : Disjoint bottom top := by
    apply Set.disjoint_left.2
    intro n hnBottom hnTop
    exact (not_lt_of_ge hnTop.2) hnBottom.2
  have hcountEq :
      natCountLEReal (oddSyracuseBadSet b) X =
        natCountLEReal bottom X + natCountLEReal top X := by
    unfold natCountLEReal natCountLE
    rw [hsplit, Terras.natCount_union_of_disjoint hdisj]
  have hbottom : natCountLEReal bottom X <= Nat.ceil y := by
    exact natCountLEReal_oddSyracuseBad_bottom_le_ceil b y X
  have hbottomReal :
      (natCountLEReal bottom X : Real) <= (Nat.ceil y : Real) := by
    exact_mod_cast hbottom
  have hcountReal :
      (natCountLEReal (oddSyracuseBadSet b) X : Real) <=
        (Nat.ceil y : Real) + (natCountLEReal top X : Real) := by
    rw [hcountEq, Nat.cast_add]
    linarith
  have hXpos : 0 < X := zero_lt_one.trans_le hX
  have hsplitRatio :
      oddSyracuseBadRatio b X <=
        (Nat.ceil y : Real) / X +
          (natCountLEReal top X : Real) / X := by
    unfold oddSyracuseBadRatio
    calc
      (natCountLEReal (oddSyracuseBadSet b) X : Real) / X <=
          ((Nat.ceil y : Real) + (natCountLEReal top X : Real)) / X :=
        div_le_div_of_nonneg_right hcountReal hXpos.le
      _ = (Nat.ceil y : Real) / X +
          (natCountLEReal top X : Real) / X := by ring
  have htop := oddSyracuseBadTopRatio_le_two_mul_fixedEventTerms
    hb hq hy hX hupper hwindow hmass
  change (natCountLEReal top X : Real) / X <= _ at htop
  linarith

end

end ND
end Erdos1135
