import Erdos1135.ND.Discrepancy.A5FlatNoHitRate
import Erdos1135.ND.Probability.UniformFloorPerturbation
import Erdos1135.Tao.Section5.TimeBoundedNoHit

/-!
# Scheduled no-hit rate for the uniform ND source block

The ordinary ND-M2 escape row bounds sources that never reach the passage
threshold.  A logarithmic-time theorem needs the larger event of sources that
do not reach it by the literal Section 5 schedule.  The same valuation
certificate proves the same flat-source rate once the time witness is retained.
-/

namespace Erdos1135
namespace ND

open Filter
open scoped Topology

noncomputable section

/-- Uniform-block probability of failing to hit `floor x` by its literal
Section 5 schedule. -/
noncomputable def uniformScheduledNoHitProbability (x y : ℝ)
    (hwindow : (oddBlock y).Nonempty) : ℝ :=
  Tao.pmfProb (uniformOddBlockPMF y hwindow)
    {N | ¬ Tao.syracuseHitsAtMostWithin N.1 (Nat.floor x)
      (Tao.taoSection5N0 (Nat.floor x))}

/-- Scheduled no-hit event on the natural A5 source carrier. -/
def ndA5NoHitWithinEvent (B : ℕ) : Set Tao.TaoOddNat :=
  {N | ¬ Tao.syracuseHitsAtMostWithin N.1 B (Tao.taoSection5N0 B)}

private theorem pmfOuterMass_toReal_mono_time
    {ι : Type*} (p : PMF ι) {A D : Set ι} (hAD : A ⊆ D) :
    (p.toOuterMeasure A).toReal ≤ (p.toOuterMeasure D).toReal := by
  have hfinite : p.toOuterMeasure D ≠ ⊤ := by
    apply ne_of_lt
    calc
      p.toOuterMeasure D ≤ p.toOuterMeasure Set.univ :=
        p.toOuterMeasure.mono (Set.subset_univ D)
      _ = 1 := (p.toOuterMeasure_apply_eq_one_iff Set.univ).2
        (Set.subset_univ _)
      _ < ⊤ := ENNReal.one_lt_top
  exact ENNReal.toReal_mono hfinite (p.toOuterMeasure.mono hAD)

/-- On one exact harmonic band, scheduled failure maps to the same strict-low
valuation event used by the eventual no-hit estimate. -/
theorem ndA5HarmonicBandNoHitWithinMass_le_error
    {B : ℕ} (descent : Tao.TaoSection5DescentScaleFacts B)
    {branch : Tao.TaoSection5SourceBranch} {j : ℕ}
    (hB : 1 ≤ B) (hcount : 0 < ndA5BandCount B branch)
    (hj : j < ndA5BandCount B branch) :
    ((ndA5HarmonicBandPMF B branch j hB hcount).toOuterMeasure
        (ndA5NoHitWithinEvent B)).toReal ≤
      Tao.taoSection5NoHitError B := by
  let μ := ndA5HarmonicBandPMF B branch j hB hcount
  let n := Tao.taoSection5N0 B
  let E := Tao.taoLowValuationWeightEvent n
  have hsupport :
      μ.toOuterMeasure
          (ndA5NoHitWithinEvent B ∩
            {N | N.1 ∈ ndA5OddBand B branch j}) =
        μ.toOuterMeasure (ndA5NoHitWithinEvent B) := by
    simpa only [μ] using
      (ndA5HarmonicBandPMF_toOuterMeasure_inter_band
        hB hcount (ndA5NoHitWithinEvent B))
  have hmap :
      (μ.toOuterMeasure (ndA5NoHitWithinEvent B)).toReal ≤
        ((Tao.taoProp19ActualValuationLaw μ n).toOuterMeasure E).toReal := by
    calc
      (μ.toOuterMeasure (ndA5NoHitWithinEvent B)).toReal =
          (μ.toOuterMeasure
            (ndA5NoHitWithinEvent B ∩
              {N | N.1 ∈ ndA5OddBand B branch j})).toReal :=
        congrArg ENNReal.toReal hsupport.symm
      _ ≤ (μ.toOuterMeasure
          {N | Tao.syracuseValuationPNatList n N.1 N.2 ∈ E}).toReal := by
        apply pmfOuterMass_toReal_mono_time
        rintro N ⟨hno, hband⟩
        apply descent.actualValuations_mem_low_of_not_hitsWithin
          (branch := branch)
        · exact ndA5OddBand_mem_taoSection5SourceWindow hB hj hband
        · exact hno
      _ = ((Tao.taoProp19ActualValuationLaw μ n).toOuterMeasure E).toReal := by
        unfold Tao.taoProp19ActualValuationLaw
        rw [PMF.toOuterMeasure_map_apply]
        apply congrArg ENNReal.toReal
        apply congrArg μ.toOuterMeasure
        rfl
  have hM : 1 ≤ Tao.taoSection5NPrime B := by
    have hn0 := descent.five_le_n0
    unfold Tao.taoSection5NPrime
    omega
  have hvaluation :=
    taoProp19ValuationTV_ndA5HarmonicBandPMF_le
      hB j hcount hM
  unfold Tao.taoProp19ValuationTV at hvaluation
  have hcompare :
      ((Tao.taoProp19ActualValuationLaw μ n).toOuterMeasure E).toReal ≤
        ((Tao.geom2PNatListPMF n).toOuterMeasure E).toReal +
          4 * (2 : ℝ) ^ (-((1 / 128 : ℝ) * (n : ℝ))) := by
    apply Tao.pmfOuterMass_le_add_of_taoPMFFullL1_le
    simpa only [μ, n] using hvaluation
  have hideal := Tao.geom2PNatListPMF_lowWeightEvent_le_exp n
  calc
    ((ndA5HarmonicBandPMF B branch j hB hcount).toOuterMeasure
        (ndA5NoHitWithinEvent B)).toReal ≤
        ((Tao.taoProp19ActualValuationLaw μ n).toOuterMeasure E).toReal := by
      simpa only [μ] using hmap
    _ ≤ ((Tao.geom2PNatListPMF n).toOuterMeasure E).toReal +
        4 * (2 : ℝ) ^ (-((1 / 128 : ℝ) * (n : ℝ))) := hcompare
    _ ≤ Real.exp (-((n : ℝ) / 3200)) +
        4 * (2 : ℝ) ^ (-((1 / 128 : ℝ) * (n : ℝ))) := by
      exact add_le_add (by simpa only [E] using hideal) le_rfl
    _ = Tao.taoSection5NoHitError B := by rfl

theorem ndA5FlatBandNoHitWithinMass_le_exp_mul_error
    {B : ℕ} (descent : Tao.TaoSection5DescentScaleFacts B)
    {branch : Tao.TaoSection5SourceBranch} {j : ℕ}
    (hB : 1 ≤ B) (hcount : 0 < ndA5BandCount B branch)
    (hj : j < ndA5BandCount B branch) :
    ((ndA5FlatBandPMF B branch j hB hcount).toOuterMeasure
        (ndA5NoHitWithinEvent B)).toReal ≤
      Real.exp (ndA5BandBeta B branch) * Tao.taoSection5NoHitError B := by
  exact (ndA5FlatBandPMF_eventMass_le_exp_mul_harmonic
    hB hcount (ndA5NoHitWithinEvent B)).trans
      (mul_le_mul_of_nonneg_left
        (ndA5HarmonicBandNoHitWithinMass_le_error
          descent hB hcount hj)
        (Real.exp_pos _).le)

theorem uniformScheduledNoHitProbability_natCast_sourceY_eq_flatSourceMass
    {B : ℕ} (hB : 1 ≤ B) (branch : Tao.TaoSection5SourceBranch)
    (hcount : 0 < ndA5BandCount B branch) :
    uniformScheduledNoHitProbability (B : ℝ)
        (Tao.taoSection5SourceY B branch)
        (ndA5OddBlock_sourceY_nonempty hB branch hcount) =
      ((ndA5FlatSourcePMF B branch hB hcount).toOuterMeasure
        (ndA5NoHitWithinEvent B)).toReal := by
  unfold uniformScheduledNoHitProbability ndA5FlatSourcePMF
  rw [Tao.pmfProb_eq_toOuterMeasure_toReal,
    PMF.toOuterMeasure_map_apply]
  apply congrArg ENNReal.toReal
  apply congrArg
    (uniformOddBlockPMF (Tao.taoSection5SourceY B branch)
      (ndA5OddBlock_sourceY_nonempty hB branch hcount)).toOuterMeasure
  ext N
  simp only [Set.mem_setOf_eq, Set.mem_preimage, ndA5NoHitWithinEvent,
    Nat.floor_natCast]
  rfl

/-- Both natural flat-source branches retain the existing `44 B^-1/32000`
rate for failure by the literal schedule. -/
theorem eventually_ndA5FlatSourceNoHitWithinMass_le_forty_four :
    ∀ᶠ B : ℕ in atTop,
      ∀ (branch : Tao.TaoSection5SourceBranch)
        (hB : 1 ≤ B) (hcount : 0 < ndA5BandCount B branch),
        ((ndA5FlatSourcePMF B branch hB hcount).toOuterMeasure
          (ndA5NoHitWithinEvent B)).toReal ≤
            44 * (B : ℝ) ^ (-(1 / 32000 : ℝ)) := by
  have hlog :
      Tendsto (fun B : ℕ => Real.log (B : ℝ)) atTop atTop :=
    Real.tendsto_log_atTop.comp tendsto_natCast_atTop_atTop
  filter_upwards
      [Tao.eventually_taoSection5DescentScaleFacts,
        hlog.eventually_ge_atTop (300000 : ℝ)]
      with B descent hlogB
  intro branch hB hcount
  let R := (B : ℝ) ^ (-(1 / 32000 : ℝ))
  have hR : 0 ≤ R := Real.rpow_nonneg (Nat.cast_nonneg B) _
  have hfortyR : 0 ≤ (40 : ℝ) * R :=
    mul_nonneg (by norm_num) hR
  have hexp : Real.exp (ndA5BandBeta B branch) ≤ 4 := by
    calc
      Real.exp (ndA5BandBeta B branch) ≤ Real.exp (2 * Real.log 2) :=
        (Real.exp_lt_exp.mpr
          (ndA5BandBeta_lt_two_mul_logTwo
            (branch := branch) hB hlogB)).le
      _ = 4 := by
        rw [two_mul, Real.exp_add,
          Real.exp_log (by norm_num : (0 : ℝ) < 2)]
        norm_num
  have hband (j : ℕ) (hj : j < ndA5BandCount B branch) :
      ((ndA5FlatBandPMF B branch j hB hcount).toOuterMeasure
          (ndA5NoHitWithinEvent B)).toReal ≤ 40 * R := by
    calc
      ((ndA5FlatBandPMF B branch j hB hcount).toOuterMeasure
          (ndA5NoHitWithinEvent B)).toReal ≤
          Real.exp (ndA5BandBeta B branch) *
            Tao.taoSection5NoHitError B :=
        ndA5FlatBandNoHitWithinMass_le_exp_mul_error
          descent hB hcount hj
      _ ≤ Real.exp (ndA5BandBeta B branch) * (10 * R) :=
        mul_le_mul_of_nonneg_left
          (by simpa only [R] using
            Tao.taoSection5NoHitError_le_ten_mul_threshold_rpow hB)
          (Real.exp_pos _).le
      _ ≤ 4 * (10 * R) :=
        mul_le_mul_of_nonneg_right hexp (by positivity)
      _ = 40 * R := by ring
  have hbands :
      (∑ j ∈ Finset.range (ndA5BandCount B branch),
          ndA5FlatBandWeight B branch j *
            ((ndA5FlatBandPMF B branch j hB hcount).toOuterMeasure
              (ndA5NoHitWithinEvent B)).toReal) ≤
        ∑ j ∈ Finset.range (ndA5BandCount B branch),
          ndA5FlatBandWeight B branch j * (40 * R) := by
    apply Finset.sum_le_sum
    intro j hj
    exact mul_le_mul_of_nonneg_left
      (hband j (Finset.mem_range.mp hj))
      (ndA5FlatBandWeight_nonneg B branch j)
  have hsumWeight :
      (∑ j ∈ Finset.range (ndA5BandCount B branch),
        ndA5FlatBandWeight B branch j) ≤ 1 := by
    have hnormalize :=
      sum_ndA5FlatBandWeight_add_topWeight_eq_one hB branch hcount
    have htopNonneg := ndA5FlatTopWeight_nonneg B branch
    linarith
  have hpow : (B : ℝ) ^ (-1 : ℝ) ≤ R := by
    exact Real.rpow_le_rpow_of_exponent_le
      (by exact_mod_cast hB : (1 : ℝ) ≤ B) (by norm_num)
  have htop :
      ndA5FlatTopRestrictedMass B branch (ndA5NoHitWithinEvent B) ≤
        4 * R := by
    calc
      ndA5FlatTopRestrictedMass B branch (ndA5NoHitWithinEvent B) ≤
          ndA5FlatTopWeight B branch :=
        ndA5FlatTopRestrictedMass_le_weight hB hcount _
      _ ≤ 4 / (B : ℝ) :=
        ndA5FlatTopWeight_le_four_div hB branch hcount
      _ = 4 * (B : ℝ) ^ (-1 : ℝ) := by
        rw [Real.rpow_neg_one]
        ring
      _ ≤ 4 * R := mul_le_mul_of_nonneg_left hpow (by norm_num)
  calc
    ((ndA5FlatSourcePMF B branch hB hcount).toOuterMeasure
        (ndA5NoHitWithinEvent B)).toReal =
        (∑ j ∈ Finset.range (ndA5BandCount B branch),
          ndA5FlatBandWeight B branch j *
            ((ndA5FlatBandPMF B branch j hB hcount).toOuterMeasure
              (ndA5NoHitWithinEvent B)).toReal) +
          ndA5FlatTopRestrictedMass B branch
            (ndA5NoHitWithinEvent B) :=
      ndA5FlatSourcePMF_eventMass_eq_band_mixture_add_top
        hB hcount (ndA5NoHitWithinEvent B)
    _ ≤ (∑ j ∈ Finset.range (ndA5BandCount B branch),
          ndA5FlatBandWeight B branch j * (40 * R)) + 4 * R :=
      add_le_add hbands htop
    _ = (∑ j ∈ Finset.range (ndA5BandCount B branch),
          ndA5FlatBandWeight B branch j) * (40 * R) + 4 * R := by
      rw [Finset.sum_mul]
    _ ≤ 1 * (40 * R) + 4 * R := by
      exact add_le_add_left
        (mul_le_mul_of_nonneg_right hsumWeight hfortyR) (4 * R)
    _ = 44 * R := by ring
    _ = 44 * (B : ℝ) ^ (-(1 / 32000 : ℝ)) := by rfl

theorem eventually_uniformScheduledNoHitProbability_natCast_sourceY_le :
    ∀ᶠ B : ℕ in atTop,
      ∀ (branch : Tao.TaoSection5SourceBranch)
        (hB : 1 ≤ B) (hcount : 0 < ndA5BandCount B branch),
        uniformScheduledNoHitProbability (B : ℝ)
            (Tao.taoSection5SourceY B branch)
            (ndA5OddBlock_sourceY_nonempty hB branch hcount) ≤
          44 * (B : ℝ) ^ (-(1 / 32000 : ℝ)) := by
  filter_upwards [eventually_ndA5FlatSourceNoHitWithinMass_le_forty_four]
      with B hnoHit
  intro branch hB hcount
  rw [uniformScheduledNoHitProbability_natCast_sourceY_eq_flatSourceMass
    hB branch hcount]
  exact hnoHit branch hB hcount

/-- Uniform floor-to-real source transport applies directly because both
carriers use the same scheduled event at `floor x`. -/
theorem eventually_uniformScheduledNoHitProbability_floor_transport_le :
    ∀ᶠ x : ℝ in atTop,
      ∀ (branch : Tao.TaoSection5SourceBranch)
        (hFloor :
          (oddBlock
            (Tao.taoSection5SourceY (Nat.floor x) branch)).Nonempty)
        (hReal : (oddBlock (transportSourceY x branch)).Nonempty),
        uniformScheduledNoHitProbability x
            (transportSourceY x branch) hReal ≤
          uniformScheduledNoHitProbability x
              (Tao.taoSection5SourceY (Nat.floor x) branch) hFloor +
            96 * x ^ (-(99 / 100 : ℝ)) := by
  filter_upwards
      [eventually_abs_pmfProb_uniformOddBlock_floor_transport_sub_le]
      with x hsource
  intro branch hFloor hReal
  have hdisc := hsource branch hFloor hReal
    {N : ℕ | ¬ Tao.syracuseHitsAtMostWithin N (Nat.floor x)
      (Tao.taoSection5N0 (Nat.floor x))}
  unfold uniformScheduledNoHitProbability
  have hdisc' :
      |Tao.pmfProb
          (uniformOddBlockPMF
            (Tao.taoSection5SourceY (Nat.floor x) branch) hFloor)
          {N | ¬ Tao.syracuseHitsAtMostWithin N.1 (Nat.floor x)
            (Tao.taoSection5N0 (Nat.floor x))} -
        Tao.pmfProb
          (uniformOddBlockPMF (transportSourceY x branch) hReal)
          {N | ¬ Tao.syracuseHitsAtMostWithin N.1 (Nat.floor x)
            (Tao.taoSection5N0 (Nat.floor x))}| ≤
        96 * x ^ (-(99 / 100 : ℝ)) := by
    simpa only [Set.mem_setOf_eq] using hdisc
  linarith [neg_le_abs
    (Tao.pmfProb
        (uniformOddBlockPMF
          (Tao.taoSection5SourceY (Nat.floor x) branch) hFloor)
        {N | ¬ Tao.syracuseHitsAtMostWithin N.1 (Nat.floor x)
          (Tao.taoSection5N0 (Nat.floor x))} -
      Tao.pmfProb
        (uniformOddBlockPMF (transportSourceY x branch) hReal)
        {N | ¬ Tao.syracuseHitsAtMostWithin N.1 (Nat.floor x)
          (Tao.taoSection5N0 (Nat.floor x))})]

private theorem logTime_half_le_floor_cast
    {x : ℝ} (hx : 2 ≤ x) :
    x / 2 ≤ ((Nat.floor x : ℕ) : ℝ) := by
  have hfloor := Nat.lt_floor_add_one x
  nlinarith

private theorem logTime_floor_power_le_two_mul
    {x : ℝ} (hx : 2 ≤ x) :
    ((Nat.floor x : ℕ) : ℝ) ^ (-(1 / 32000 : ℝ)) ≤
      2 * x ^ (-(1 / 32000 : ℝ)) := by
  have hxpos : 0 < x := by linarith
  have hhalfPos : 0 < x / 2 := div_pos hxpos (by norm_num)
  have hbase := Real.rpow_le_rpow_of_nonpos hhalfPos
    (logTime_half_le_floor_cast hx)
    (show -(1 / 32000 : ℝ) ≤ 0 by norm_num)
  have htwo : (2 : ℝ) ^ (1 / 32000 : ℝ) ≤ 2 := by
    calc
      (2 : ℝ) ^ (1 / 32000 : ℝ) ≤ (2 : ℝ) ^ (1 : ℝ) :=
        Real.rpow_le_rpow_of_exponent_le (by norm_num) (by norm_num)
      _ = 2 := by norm_num
  calc
    ((Nat.floor x : ℕ) : ℝ) ^ (-(1 / 32000 : ℝ)) ≤
        (x / 2) ^ (-(1 / 32000 : ℝ)) := hbase
    _ = (2 : ℝ) ^ (1 / 32000 : ℝ) *
        x ^ (-(1 / 32000 : ℝ)) := by
      rw [Real.div_rpow hxpos.le (by norm_num : (0 : ℝ) ≤ 2),
        Real.rpow_neg (by norm_num : (0 : ℝ) ≤ 2)]
      simp only [div_eq_mul_inv, inv_inv]
      ring
    _ ≤ 2 * x ^ (-(1 / 32000 : ℝ)) :=
      mul_le_mul_of_nonneg_right htwo (Real.rpow_nonneg hxpos.le _)

/-- On the actual real source block, scheduled top-passage failure has a
uniform power rate. -/
theorem eventually_uniformScheduledNoHitProbability_transportSourceY_le :
    ∀ᶠ x : ℝ in atTop,
      ∀ (branch : Tao.TaoSection5SourceBranch)
        (hReal : (oddBlock (transportSourceY x branch)).Nonempty),
        uniformScheduledNoHitProbability x
            (transportSourceY x branch) hReal ≤
          184 * x ^ (-(1 / 32000 : ℝ)) := by
  have hFloorTendsto : Tendsto (fun x : ℝ => Nat.floor x) atTop atTop :=
    tendsto_nat_floor_atTop
  have hFloorCastTendsto :
      Tendsto (fun x : ℝ => ((Nat.floor x : ℕ) : ℝ)) atTop atTop :=
    tendsto_natCast_atTop_atTop.comp hFloorTendsto
  have hLogFloorTendsto :
      Tendsto
        (fun x : ℝ => Real.log ((Nat.floor x : ℕ) : ℝ))
        atTop atTop :=
    Real.tendsto_log_atTop.comp hFloorCastTendsto
  filter_upwards
      [eventually_uniformScheduledNoHitProbability_floor_transport_le,
        hFloorTendsto.eventually
          eventually_uniformScheduledNoHitProbability_natCast_sourceY_le,
        hLogFloorTendsto.eventually_ge_atTop (300000 : ℝ),
        eventually_ge_atTop (2 : ℝ)]
      with x htransport hnatural hlogFloor hx
  intro branch hReal
  let B := Nat.floor x
  have hB : 1 ≤ B := Tao.one_le_floor_of_one_le (by linarith)
  have hcountThree : 3 ≤ ndA5BandCount B branch :=
    ndA5BandCount_ge_three_of_guards hB (by simpa only [B] using hlogFloor)
  have hcount : 0 < ndA5BandCount B branch := by omega
  let hFloor := ndA5OddBlock_sourceY_nonempty hB branch hcount
  have htransport' := htransport branch hFloor hReal
  have hnatural' := hnatural branch hB hcount
  have hfloorPow := logTime_floor_power_le_two_mul hx
  have hxOne : 1 ≤ x := by linarith
  have htransportPow :
      x ^ (-(99 / 100 : ℝ)) ≤ x ^ (-(1 / 32000 : ℝ)) :=
    Real.rpow_le_rpow_of_exponent_le hxOne (by norm_num)
  calc
    uniformScheduledNoHitProbability x
        (transportSourceY x branch) hReal ≤
        uniformScheduledNoHitProbability x
            (Tao.taoSection5SourceY B branch) hFloor +
          96 * x ^ (-(99 / 100 : ℝ)) := by
      simpa only [B, hFloor] using htransport'
    _ = uniformScheduledNoHitProbability (B : ℝ)
            (Tao.taoSection5SourceY B branch) hFloor +
          96 * x ^ (-(99 / 100 : ℝ)) := by
      unfold uniformScheduledNoHitProbability
      simp only [B, Nat.floor_natCast]
    _ ≤ 44 * (B : ℝ) ^ (-(1 / 32000 : ℝ)) +
          96 * x ^ (-(99 / 100 : ℝ)) :=
      add_le_add hnatural' le_rfl
    _ ≤ 44 * (2 * x ^ (-(1 / 32000 : ℝ))) +
          96 * x ^ (-(1 / 32000 : ℝ)) :=
      add_le_add
        (mul_le_mul_of_nonneg_left hfloorPow (by norm_num))
        (mul_le_mul_of_nonneg_left htransportPow (by norm_num))
    _ = 184 * x ^ (-(1 / 32000 : ℝ)) := by ring

end


end ND
end Erdos1135
