import Mathlib
import Analysis.Section_2_1
import Analysis.Tags.Section_2_1

namespace Chapter2

-- <CONTEXT>
inductive Nat where
| zero : Nat
| succ : Nat → Nat
deriving Repr, DecidableEq

instance Nat.instZero : Zero Nat := ⟨ zero ⟩

postfix:100 "++" => Nat.succ

instance Nat.instOfNat {n:_root_.Nat} : OfNat Nat n where
  ofNat := _root_.Nat.rec 0 (fun _ n ↦ n++) n

instance Nat.instOne : One Nat := ⟨ 1 ⟩

lemma Nat.zero_succ : 0++ = 1 := by
  sorry

lemma Nat.one_succ : 1++ = 2 := by
  sorry

lemma Nat.two_succ : 2++ = 3 := by
  sorry

theorem Nat.succ_ne (n:Nat) : n++ ≠ 0 := by
  sorry

theorem Nat.four_ne : (4:Nat) ≠ 0 := by
  sorry

theorem Nat.succ_cancel {n m:Nat} (hnm: n++ = m++) : n = m := by
  sorry

theorem Nat.succ_ne_succ (n m:Nat) : n ≠ m → n++ ≠ m++ := by
  sorry

theorem Nat.six_ne_two : (6:Nat) ≠ 2 := by
  sorry

theorem Nat.six_ne_two' : (6:Nat) ≠ 2 := by
  sorry

theorem Nat.induction (P : Nat → Prop) (hbase : P 0) (hind : ∀ n, P n → P (n++)) :
    ∀ n, P n := by
  sorry

abbrev Nat.recurse (f: Nat → Nat → Nat) (c: Nat) : Nat → Nat := fun n ↦ match n with
| 0 => c
| n++ => f n (recurse f c n)

theorem Nat.recurse_zero (f: Nat → Nat → Nat) (c: Nat) : Nat.recurse f c 0 = c := by
  sorry

theorem Nat.recurse_succ (f: Nat → Nat → Nat) (c: Nat) (n: Nat) :
    recurse f c (n++) = f n (recurse f c n) := by
  sorry

theorem Nat.eq_recurse (f: Nat → Nat → Nat) (c: Nat) (a: Nat → Nat) :
    (a 0 = c ∧ ∀ n, a (n++) = f n (a n)) ↔ a = recurse f c := by
  sorry

theorem Nat.recurse_uniq (f: Nat → Nat → Nat) (c: Nat) :
    ∃! (a: Nat → Nat), a 0 = c ∧ ∀ n, a (n++) = f n (a n) := by
  sorry

abbrev Nat.add (n m : Nat) : Nat := Nat.recurse (fun _ sum ↦ sum++) m n

instance Nat.instAdd : Add Nat where
  add := add

@[simp]
theorem Nat.zero_add (m: Nat) : 0 + m = m := by
  sorry

theorem Nat.succ_add (n m: Nat) : n++ + m = (n+m)++ := by
  sorry

theorem Nat.one_add (m:Nat) : 1 + m = m++ := by
  sorry

theorem Nat.two_add (m:Nat) : 2 + m = (m++)++ := by
  sorry

@[simp]
lemma Nat.add_zero (n:Nat) : n + 0 = n := by
  sorry

lemma Nat.add_succ (n m:Nat) : n + (m++) = (n + m)++ := by
  sorry

theorem Nat.succ_eq_add_one (n:Nat) : n++ = n + 1 := by
  sorry

theorem Nat.add_comm (n m:Nat) : n + m = m + n := by
  sorry

theorem Nat.add_assoc (a b c:Nat) : (a + b) + c = a + (b + c) := by
  sorry

theorem Nat.add_left_cancel (a b c:Nat) (habc: a + b = a + c) : b = c := by
  sorry

instance Nat.addCommMonoid : AddCommMonoid Nat where
  add_assoc := add_assoc
  add_comm := add_comm
  zero_add := zero_add
  add_zero := add_zero
  nsmul := nsmulRec

def Nat.IsPos (n:Nat) : Prop := n ≠ 0

theorem Nat.isPos_iff (n:Nat) : n.IsPos ↔ n ≠ 0 := by
  sorry

theorem Nat.add_pos_left {a:Nat} (b:Nat) (ha: a.IsPos) : (a + b).IsPos := by
  sorry

theorem Nat.add_pos_right {a:Nat} (b:Nat) (ha: a.IsPos) : (b + a).IsPos := by
  sorry

theorem Nat.add_eq_zero (a b:Nat) (hab: a + b = 0) : a = 0 ∧ b = 0 := by
  sorry

instance Nat.instLE : LE Nat where
  le n m := ∃ a:Nat, m = n + a

instance Nat.instLT : LT Nat where
  lt n m := n ≤ m ∧ n ≠ m

lemma Nat.le_iff (n m:Nat) : n ≤ m ↔ ∃ a:Nat, m = n + a := by
  sorry

lemma Nat.lt_iff (n m:Nat) : n < m ↔ (∃ a:Nat, m = n + a) ∧ n ≠ m := by
  sorry

@[symm]
lemma Nat.ge_iff_le (n m:Nat) : n ≥ m ↔ m ≤ n := by
  sorry

@[symm]
lemma Nat.gt_iff_lt (n m:Nat) : n > m ↔ m < n := by
  sorry

lemma Nat.le_of_lt {n m:Nat} (hnm: n < m) : n ≤ m := by
  sorry

lemma Nat.le_iff_lt_or_eq (n m:Nat) : n ≤ m ↔ n < m ∨ n = m := by
  sorry

theorem Nat.succ_gt_self (n:Nat) : n++ > n := by
  sorry

theorem Nat.ge_refl (a:Nat) : a ≥ a := by
  sorry

@[refl]
theorem Nat.le_refl (a:Nat) : a ≤ a := by
  sorry

theorem Nat.ge_trans {a b c:Nat} (hab: a ≥ b) (hbc: b ≥ c) : a ≥ c := by
  sorry

theorem Nat.le_trans {a b c:Nat} (hab: a ≤ b) (hbc: b ≤ c) : a ≤ c := by
  sorry

theorem Nat.ge_antisymm {a b:Nat} (hab: a ≥ b) (hba: b ≥ a) : a = b := by
  sorry

theorem Nat.add_ge_add_right (a b c:Nat) : a ≥ b ↔ a + c ≥ b + c := by
  sorry

theorem Nat.add_ge_add_left (a b c:Nat) : a ≥ b ↔ c + a ≥ c + b := by
  sorry

theorem Nat.add_le_add_right (a b c:Nat) : a ≤ b ↔ a + c ≤ b + c := by
  sorry

theorem Nat.add_le_add_left (a b c:Nat) : a ≤ b ↔ c + a ≤ c + b := by
  sorry

theorem Nat.lt_iff_succ_le (a b:Nat) : a < b ↔ a++ ≤ b := by
  sorry

theorem Nat.lt_iff_add_pos (a b:Nat) : a < b ↔ ∃ d:Nat, d.IsPos ∧ b = a + d := by
  sorry

theorem Nat.ne_of_lt (a b:Nat) : a < b → a ≠ b := by
  sorry

theorem Nat.ne_of_gt (a b:Nat) : a > b → a ≠ b := by
  sorry

theorem Nat.not_lt_of_gt (a b:Nat) : a < b ∧ a > b → False := by
  sorry

theorem Nat.not_lt_self {a: Nat} (h : a < a) : False := by
  sorry

theorem Nat.lt_of_le_of_lt {a b c : Nat} (hab: a ≤ b) (hbc: b < c) : a < c := by
  sorry

theorem Nat.zero_le (a:Nat) : 0 ≤ a := by
  sorry

theorem Nat.trichotomous (a b:Nat) : a < b ∨ a = b ∨ a > b := by
  sorry

def Nat.decLe : (a b : Nat) → Decidable (a ≤ b)
  | 0, b => by
    apply isTrue
    sorry
  | a++, b => by
    cases decLe a b with
    | isTrue h =>
      cases decEq a b with
      | isTrue h =>
        apply isFalse
        sorry
      | isFalse h =>
        apply isTrue
        sorry
    | isFalse h =>
      apply isFalse
      sorry

instance Nat.decidableRel : DecidableRel (· ≤ · : Nat → Nat → Prop) := Nat.decLe

instance Nat.instLinearOrder : LinearOrder Nat where
  le_refl := ge_refl
  le_trans a b c hab hbc := ge_trans hbc hab
  lt_iff_le_not_ge a b := by
    constructor
    . intro h; refine ⟨ le_of_lt h, ?_ ⟩
      by_contra h'
      exact not_lt_self (lt_of_le_of_lt h' h)
    rintro ⟨ h1, h2 ⟩
    rw [lt_iff, ←le_iff]; refine ⟨ h1, ?_ ⟩
    by_contra h
    subst h
    contradiction
  le_antisymm a b hab hba := ge_antisymm hba hab
  le_total a b := by
    obtain h | rfl | h := trichotomous a b
    . left; exact le_of_lt h
    . simp [ge_refl]
    . right; exact le_of_lt h
  toDecidableLE := decidableRel

instance Nat.isOrderedAddMonoid : IsOrderedAddMonoid Nat where
  add_le_add_left a b hab c := (Nat.add_le_add_right a b c).mp hab
-- </CONTEXT>
-- <TARGET_THEOREM>
theorem Nat.strong_induction {m₀:Nat} {P: Nat → Prop}
  (hind: ∀ m, m ≥ m₀ → (∀ m', m₀ ≤ m' ∧ m' < m → P m') → P m) :
    ∀ m, m ≥ m₀ → P m := by
-- </TARGET_THEOREM>

end Chapter2