import Erdos1135.ND.Discrepancy.A5ReferenceND31
import Erdos1135.Tao.Section3.QuantitativeLowerBound

/-!
# Conditional ND-1.6 From ND-3.1

This leaf converts the fixed-target quantitative natural-counting estimate
`ND31Bounds d` into the varying-threshold qualitative statement `ND16Statement`.
For each requested density tolerance it first fixes one Syracuse target, then
uses growth only to discard a finite initial segment.
-/

namespace Erdos1135
namespace ND

open Filter
open scoped Topology

noncomputable section

private theorem natCount_le_natCountLEReal_natCast
    (S : Set Nat) (N : Nat) :
    Terras.natCount S N <= natCountLEReal S (N : Real) := by
  unfold natCountLEReal natCountLE Terras.natCount
  simp only [Nat.floor_natCast]
  rw [Nat.count_succ]
  split <;> omega

private theorem natCountingRatio_le_const_div_add_oddBadRatio
    {F : Set Nat} {B K N : Nat} (hN : 0 < N)
    (htail : {n : Nat | n ∈ F ∧ B <= n} ⊆ oddSyracuseBadSet K) :
    Terras.natCountingRatio F N <=
      (B : Real) / (N : Real) + oddSyracuseBadRatio K (N : Real) := by
  let low : Set Nat := {n | n ∈ F ∧ n < B}
  let high : Set Nat := {n | n ∈ F ∧ B <= n}
  have hcover : F = low ∪ high := by
    ext n
    constructor
    · intro hn
      by_cases hnB : n < B
      · exact Or.inl ⟨hn, hnB⟩
      · exact Or.inr ⟨hn, le_of_not_gt hnB⟩
    · rintro (hn | hn)
      · exact hn.1
      · exact hn.1
  have hdisj : Disjoint low high := by
    rw [Set.disjoint_left]
    intro n hnLow hnHigh
    exact (not_lt_of_ge hnHigh.2) hnLow.2
  have hcount :
      Terras.natCount F N =
        Terras.natCount low N + Terras.natCount high N := by
    rw [hcover]
    exact Terras.natCount_union_of_disjoint hdisj N
  have hlow : Terras.natCount low N <= B := by
    apply Terras.natCount_le_of_subset_Iio (B := B)
    intro n hn
    exact hn.2
  have hhigh :
      Terras.natCount high N <=
        Terras.natCount (oddSyracuseBadSet K) N := by
    apply Terras.natCount_mono
    exact htail
  have hendpoint :
      Terras.natCount (oddSyracuseBadSet K) N <=
        natCountLEReal (oddSyracuseBadSet K) (N : Real) :=
    natCount_le_natCountLEReal_natCast _ _
  have hcountBound :
      Terras.natCount F N <=
        B + natCountLEReal (oddSyracuseBadSet K) (N : Real) := by
    rw [hcount]
    omega
  have hcountBoundReal :
      (Terras.natCount F N : Real) <=
        (B : Real) +
          (natCountLEReal (oddSyracuseBadSet K) (N : Real) : Real) := by
    exact_mod_cast hcountBound
  have hNnonneg : (0 : Real) <= (N : Real) := by positivity
  calc
    Terras.natCountingRatio F N =
        (Terras.natCount F N : Real) / (N : Real) := rfl
    _ <= ((B : Real) +
          (natCountLEReal (oddSyracuseBadSet K) (N : Real) : Real)) /
        (N : Real) :=
      div_le_div_of_nonneg_right hcountBoundReal hNnonneg
    _ = (B : Real) / (N : Real) +
        oddSyracuseBadRatio K (N : Real) := by
      unfold oddSyracuseBadRatio
      ring

private theorem eventually_natCast_lt_of_growsOnOdds
    {f : Nat -> Real} (hf : Tao.GrowsOnOddsToInfinity f) (K : Nat) :
    ∀ᶠ n : Nat in atTop, Odd n -> (K : Real) < f n := by
  rcases eventually_atTop.1
      (hf.eventually_gt_atTop (K : Real)) with ⟨m0, hm0⟩
  refine eventually_atTop.2 ⟨2 * m0 + 1, ?_⟩
  intro n hn hnOdd
  rcases hnOdd.exists_bit1 with ⟨m, rfl⟩
  exact hm0 m (by omega)

private theorem hasNatDensity_right_of_union
    {s t u : Set Nat} {a b : Real}
    (hs : Terras.HasNatDensity s a)
    (ht : Terras.HasNatDensity t b)
    (hcover : s = t ∪ u) (hdisj : Disjoint t u) :
    Terras.HasNatDensity u (a - b) := by
  have hcount : ∀ N,
      Terras.natCount s N =
        Terras.natCount t N + Terras.natCount u N := by
    intro N
    rw [hcover]
    exact Terras.natCount_union_of_disjoint hdisj N
  unfold Terras.HasNatDensity Terras.natCountingRatio at hs ht ⊢
  have hdiff := hs.sub ht
  refine hdiff.congr' ?_
  filter_upwards with N
  have hc :
      (Terras.natCount s N : Real) =
        (Terras.natCount t N : Real) +
          (Terras.natCount u N : Real) := by
    exact_mod_cast hcount N
  rw [hc]
  ring

/-- A positive-exponent ND-3.1 bound makes the varying strict Syracuse failure
set have ambient natural density zero. -/
theorem hasNatDensity_oddSyracuseFailure_zero_of_nd31Bounds
    {d : Real} (hd : 0 < d) (h31 : ND31Bounds d)
    {f : Nat -> Real} (hf : Tao.GrowsOnOddsToInfinity f) :
    Terras.HasNatDensity
      {N : Nat | Odd N ∧
        ¬ Tao.syracuseHitsBelowReal N (f N)} 0 := by
  rcases h31 with ⟨C, _hC, hmain⟩
  let F : Set Nat :=
    {N : Nat | Odd N ∧ ¬ Tao.syracuseHitsBelowReal N (f N)}
  change Terras.HasNatDensity F 0
  unfold Terras.HasNatDensity
  refine tendsto_order.2 ⟨?_, ?_⟩
  · intro a ha
    filter_upwards with N
    have hnonneg : 0 <= Terras.natCountingRatio F N := by
      unfold Terras.natCountingRatio
      positivity
    exact lt_of_lt_of_le ha hnonneg
  · intro eta heta
    have hrate := Tao.section3_log_power_rate_tendsto_zero C d hd
    have hrateSmall :
        ∀ᶠ K : Nat in atTop,
          C * (Real.log (K : Real)) ^ (-d) < eta / 2 :=
      (tendsto_order.1 hrate).2 (eta / 2) (by linarith)
    have hKexists :
        ∃ K : Nat,
          C * (Real.log (K : Real)) ^ (-d) < eta / 2 ∧ 2 <= K := by
      exact (hrateSmall.and (eventually_ge_atTop 2)).exists
    rcases hKexists with ⟨K, hrateK, hKtwo⟩
    rcases eventually_atTop.1
        (eventually_natCast_lt_of_growsOnOdds hf K) with ⟨B, hB⟩
    have hprefix :=
      tendsto_const_div_atTop_nhds_zero_nat (B : Real)
    have hprefixSmall :
        ∀ᶠ N : Nat in atTop, (B : Real) / (N : Real) < eta / 2 :=
      (tendsto_order.1 hprefix).2 (eta / 2) (by linarith)
    filter_upwards [hprefixSmall, eventually_ge_atTop 2] with N hBN hNtwo
    have htail :
        {n : Nat | n ∈ F ∧ B <= n} ⊆ oddSyracuseBadSet K := by
      intro n hn
      rcases hn with ⟨⟨hnOdd, hnFail⟩, hnB⟩
      have hKf : (K : Real) < f n := hB n hnB hnOdd
      change 0 < n ∧ Odd n ∧ ¬ Tao.syracuseHitsAtMost n K
      refine ⟨Odd.pos hnOdd, hnOdd, ?_⟩
      intro hHitK
      exact hnFail
        (Tao.syracuseHitsAtMost_to_hitsBelowReal hHitK hKf)
    have hratio :=
      natCountingRatio_le_const_div_add_oddBadRatio
        (F := F) (B := B) (K := K) (N := N) (by omega) htail
    have hmainN :
        oddSyracuseBadRatio K (N : Real) <=
          C * (Real.log (K : Real)) ^ (-d) :=
      hmain K (N : Real) hKtwo (by exact_mod_cast hNtwo)
    calc
      Terras.natCountingRatio F N <=
          (B : Real) / (N : Real) +
            oddSyracuseBadRatio K (N : Real) := hratio
      _ <= (B : Real) / (N : Real) +
          C * (Real.log (K : Real)) ^ (-d) :=
        add_le_add_right hmainN _
      _ < eta / 2 + eta / 2 := add_lt_add hBN hrateK
      _ = eta := by ring

/-- Conditional ND-1.6, consuming a positive-exponent ND-3.1 estimate. -/
theorem nd16Statement_of_nd31Bounds
    {d : Real} (hd : 0 < d) (h31 : ND31Bounds d) :
    ND16Statement := by
  intro f hf
  let O : Set Nat := {N | Odd N}
  let F : Set Nat :=
    {N | Odd N ∧ ¬ Tao.syracuseHitsBelowReal N (f N)}
  let G : Set Nat :=
    {N | Odd N ∧ Tao.syracuseHitsBelowReal N (f N)}
  have hF : Terras.HasNatDensity F 0 := by
    exact hasNatDensity_oddSyracuseFailure_zero_of_nd31Bounds hd h31 hf
  have hO : Terras.HasNatDensity O (1 / 2 : Real) := by
    dsimp only [O]
    simpa [Nat.odd_iff, Nat.ModEq] using
      (Terras.hasNatDensity_modEq
        (m := 2) (by norm_num : 0 < 2) 1)
  have hcover : O = F ∪ G := by
    ext N
    by_cases hHit : Tao.syracuseHitsBelowReal N (f N)
    · simp [O, F, G, hHit]
    · simp [O, F, G, hHit]
  have hdisj : Disjoint F G := by
    rw [Set.disjoint_left]
    intro N hFmem hGmem
    change Odd N ∧ ¬ Tao.syracuseHitsBelowReal N (f N) at hFmem
    change Odd N ∧ Tao.syracuseHitsBelowReal N (f N) at hGmem
    exact hFmem.2 hGmem.2
  have hG : Terras.HasNatDensity G ((1 / 2 : Real) - 0) :=
    hasNatDensity_right_of_union hO hF hcover hdisj
  simpa [HasOddRelativeNatDensityOne, G] using hG

end

end ND
end Erdos1135
