import Erdos1135.KrasikovLagarias.Envelope
import Mathlib.Dynamics.PeriodicPts.Defs

/-!
# Periodic target reduction

This module supplies a bounded target-reduction layer for the KL predecessor
bridge.  A positive target not divisible by `3` has a nonperiodic predecessor
congruent to `2 mod 3`, obtained by multiplying by a suitable power of two.
-/

namespace Erdos1135
namespace KrasikovLagarias

open Terras

theorem accelerated_iterate_pow_two_mul (exponent target : Nat) :
    accelerated^[exponent] (2 ^ exponent * target) = target := by
  induction exponent with
  | zero =>
      simp
  | succ exponent ih =>
      rw [Function.iterate_succ_apply]
      have hstep : accelerated (2 ^ Nat.succ exponent * target) =
          2 ^ exponent * target := by
        have heven : Even (2 ^ Nat.succ exponent * target) := by
          simpa [pow_succ, mul_comm, mul_left_comm] using
            even_two_mul (2 ^ exponent * target)
        rw [accelerated_eq_div_two_of_even heven]
        have hmul : 2 ^ Nat.succ exponent * target =
            2 * (2 ^ exponent * target) := by
          simp [pow_succ, mul_comm, mul_left_comm]
        rw [hmul, Nat.mul_div_right _ (by norm_num : 0 < 2)]
      rw [hstep, ih]

theorem pow_two_mul_reaches (exponent target : Nat) :
    Reaches (2 ^ exponent * target) target :=
  ⟨exponent, accelerated_iterate_pow_two_mul exponent target⟩

private theorem pow_two_even_mod_three (period : Nat) :
    2 ^ (2 * period) % 3 = 1 := by
  induction period with
  | zero =>
      norm_num
  | succ period ih =>
      calc
        2 ^ (2 * Nat.succ period) % 3 =
            (2 ^ (2 * period) * 2 ^ 2) % 3 := by
              congr 1
              rw [show 2 * Nat.succ period = 2 * period + 2 by omega, pow_add]
        _ = ((2 ^ (2 * period) % 3) * (2 ^ 2 % 3)) % 3 := by
              rw [Nat.mul_mod]
        _ = 1 := by
              rw [ih]
              norm_num

private theorem pow_two_odd_mod_three (period : Nat) :
    2 ^ (2 * period + 1) % 3 = 2 := by
  calc
    2 ^ (2 * period + 1) % 3 =
        (2 ^ (2 * period) * 2) % 3 := by simp [pow_add]
    _ = ((2 ^ (2 * period) % 3) * (2 % 3)) % 3 := by
          rw [Nat.mul_mod]
    _ = 2 := by
          norm_num [pow_two_even_mod_three]

private theorem pow_two_even_mul_mod_three {period target : Nat}
    (htarget : target % 3 = 2) :
    (2 ^ (2 * period) * target) % 3 = 2 := by
  calc
    (2 ^ (2 * period) * target) % 3 =
        ((2 ^ (2 * period) % 3) * (target % 3)) % 3 := by
          rw [Nat.mul_mod]
    _ = 2 := by
          norm_num [pow_two_even_mod_three, htarget]

private theorem pow_two_odd_mul_mod_three {period target : Nat}
    (htarget : target % 3 = 1) :
    (2 ^ (2 * period + 1) * target) % 3 = 2 := by
  calc
    (2 ^ (2 * period + 1) * target) % 3 =
        ((2 ^ (2 * period + 1) % 3) * (target % 3)) % 3 := by
          rw [Nat.mul_mod]
    _ = 2 := by
          norm_num [pow_two_odd_mod_three, htarget]

private theorem two_mul_mod_three_of_mod_one {target : Nat}
    (htarget : target % 3 = 1) :
    (2 * target) % 3 = 2 := by
  calc
    (2 * target) % 3 = ((2 % 3) * (target % 3)) % 3 := by
      rw [Nat.mul_mod]
    _ = 2 := by
      norm_num [htarget]

private theorem lt_pow_two_mul_self {exponent target : Nat}
    (htarget : 0 < target) (hexponent : 0 < exponent) :
    target < 2 ^ exponent * target := by
  exact lt_mul_of_one_lt_left htarget (Nat.one_lt_two_pow (Nat.ne_of_gt hexponent))

private theorem two_mul_lt_pow_two_mul_self {period target : Nat}
    (htarget : 0 < target) (hperiod : 0 < period) :
    2 * target < 2 ^ (2 * period + 1) * target := by
  have hlt : target < 2 ^ (2 * period) * target :=
    lt_pow_two_mul_self htarget (by omega)
  have hscaled := Nat.mul_lt_mul_of_pos_left hlt (by norm_num : 0 < 2)
  have hrewrite : 2 * (2 ^ (2 * period) * target) =
      2 ^ (2 * period + 1) * target := by
    simp [pow_add, mul_comm, mul_left_comm]
  simpa [hrewrite] using hscaled

private theorem pow_two_even_mul_not_inAcceleratedCycle_of_periodic
    {period target : Nat} (htarget : 0 < target) (hperiod : 0 < period)
    (hreturns : accelerated^[period] target = target) :
    ¬ InAcceleratedCycle (2 ^ (2 * period) * target) := by
  intro hcycle
  let exponent := 2 * period
  let source := 2 ^ exponent * target
  have htargetPeriodic : Function.IsPeriodicPt accelerated period target := hreturns
  have htargetF : Function.IsPeriodicPt (accelerated^[exponent]) period target := by
    exact htargetPeriodic.iterate exponent
  have hsourceMap : (accelerated^[exponent]) source = target := by
    dsimp [source, exponent]
    exact accelerated_iterate_pow_two_mul (2 * period) target
  have htargetMap : (accelerated^[exponent]) target = target := by
    dsimp [exponent]
    simpa using htargetPeriodic.const_mul 2
  rcases hcycle with ⟨sourcePeriod, hsourcePeriod, hsourceReturns⟩
  have hsourcePeriodic : Function.IsPeriodicPt accelerated sourcePeriod source := hsourceReturns
  have hsourceF : Function.IsPeriodicPt (accelerated^[exponent]) sourcePeriod source := by
    exact hsourcePeriodic.iterate exponent
  have heq : source = target :=
    hsourceF.eq_of_apply_eq htargetF hsourcePeriod hperiod (by rw [hsourceMap, htargetMap])
  have hlt : target < source := by
    dsimp [source, exponent]
    exact lt_pow_two_mul_self htarget (by omega)
  exact (ne_of_gt hlt) heq

private theorem pow_two_odd_mul_not_inAcceleratedCycle_of_periodic_two_mul
    {period target : Nat} (htarget : 0 < target) (hperiod : 0 < period)
    (hreturns : accelerated^[period] target = target)
    (htwoCycle : InAcceleratedCycle (2 * target)) :
    ¬ InAcceleratedCycle (2 ^ (2 * period + 1) * target) := by
  intro hcycle
  let exponent := 2 * period + 1
  let source := 2 ^ exponent * target
  let doubled := 2 * target
  have htargetPeriodic : Function.IsPeriodicPt accelerated period target := hreturns
  have htargetTwice : accelerated^[2 * period] target = target := by
    simpa using htargetPeriodic.const_mul 2
  have hdoubledStep : accelerated doubled = target := by
    dsimp [doubled]
    rw [accelerated_eq_div_two_of_even (even_two_mul target)]
    omega
  have hsourceMap : (accelerated^[exponent]) source = target := by
    dsimp [source, exponent]
    exact accelerated_iterate_pow_two_mul (2 * period + 1) target
  have hdoubledMap : (accelerated^[exponent]) doubled = target := by
    dsimp [doubled, exponent]
    rw [hdoubledStep, htargetTwice]
  rcases htwoCycle with ⟨doubledPeriod, hdoubledPeriod, hdoubledReturns⟩
  have hdoubledPeriodic : Function.IsPeriodicPt accelerated doubledPeriod doubled :=
    hdoubledReturns
  have hdoubledF : Function.IsPeriodicPt (accelerated^[exponent]) doubledPeriod doubled := by
    exact hdoubledPeriodic.iterate exponent
  rcases hcycle with ⟨sourcePeriod, hsourcePeriod, hsourceReturns⟩
  have hsourcePeriodic : Function.IsPeriodicPt accelerated sourcePeriod source := hsourceReturns
  have hsourceF : Function.IsPeriodicPt (accelerated^[exponent]) sourcePeriod source := by
    exact hsourcePeriodic.iterate exponent
  have heq : source = doubled :=
    hsourceF.eq_of_apply_eq hdoubledF hsourcePeriod hdoubledPeriod
      (by rw [hsourceMap, hdoubledMap])
  have hlt : doubled < source := by
    dsimp [doubled, source, exponent]
    exact two_mul_lt_pow_two_mul_self htarget hperiod
  exact (ne_of_gt hlt) heq

theorem exists_nonperiodic_mod_two_reaches_of_pos_mod_three_ne_zero
    {target : Nat} (htarget : 0 < target) (hmod : target % 3 ≠ 0) :
    ∃ source : Nat,
      0 < source ∧ source % 3 = 2 ∧ ¬ InAcceleratedCycle source ∧ Reaches source target := by
  classical
  have hcases : target % 3 = 1 ∨ target % 3 = 2 := by
    have hlt : target % 3 < 3 := Nat.mod_lt target (by norm_num : 0 < 3)
    omega
  rcases hcases with hmod_one | hmod_two
  · by_cases htwoCycle : InAcceleratedCycle (2 * target)
    · have htargetCycle : InAcceleratedCycle target := by
        have hstep : accelerated (2 * target) = target := by
          rw [accelerated_eq_div_two_of_even (even_two_mul target)]
          omega
        simpa [Function.iterate_one, hstep] using htwoCycle.iterate 1
      rcases htargetCycle with ⟨period, hperiod, hreturns⟩
      refine ⟨2 ^ (2 * period + 1) * target, ?_, ?_, ?_, ?_⟩
      · exact Nat.mul_pos (pow_pos (by norm_num : 0 < (2 : Nat)) _) htarget
      · exact pow_two_odd_mul_mod_three hmod_one
      · exact pow_two_odd_mul_not_inAcceleratedCycle_of_periodic_two_mul
          htarget hperiod hreturns htwoCycle
      · exact pow_two_mul_reaches (2 * period + 1) target
    · refine ⟨2 * target, ?_, ?_, htwoCycle, ?_⟩
      · exact Nat.mul_pos (by norm_num : 0 < (2 : Nat)) htarget
      · exact two_mul_mod_three_of_mod_one hmod_one
      · exact two_mul_reaches target
  · by_cases htargetCycle : InAcceleratedCycle target
    · rcases htargetCycle with ⟨period, hperiod, hreturns⟩
      refine ⟨2 ^ (2 * period) * target, ?_, ?_, ?_, ?_⟩
      · exact Nat.mul_pos (pow_pos (by norm_num : 0 < (2 : Nat)) _) htarget
      · exact pow_two_even_mul_mod_three hmod_two
      · exact pow_two_even_mul_not_inAcceleratedCycle_of_periodic
          htarget hperiod hreturns
      · exact pow_two_mul_reaches (2 * period) target
    · exact ⟨target, htarget, hmod_two, htargetCycle, reaches_refl target⟩

theorem exists_admissibleTarget15_reaches_of_pos_mod_three_ne_zero
    {target : Nat} (htarget : 0 < target) (hmod : target % 3 ≠ 0) :
    ∃ source : Nat,
      AdmissibleTarget 15 (source % 3 ^ 15) source ∧
        source % 3 = 2 ∧ Reaches source target := by
  rcases exists_nonperiodic_mod_two_reaches_of_pos_mod_three_ne_zero
      htarget hmod with ⟨source, hsourcePos, hsourceMod, hsourceCycle, hsourceReach⟩
  refine ⟨source, ?_, hsourceMod, hsourceReach⟩
  refine ⟨hsourcePos, ?_, hsourceCycle⟩
  simp [Nat.ModEq]

end KrasikovLagarias
end Erdos1135
