import Mathlib
import Analysis.Section_2_2
import Analysis.Tags.Section_2_2

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 ⟩

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)

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

@[simp]
lemma Nat.add_zero (n:Nat) : n + 0 = n := 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

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

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

lemma Nat.le_of_lt {n m:Nat} (hnm: n < m) : n ≤ m := 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.ge_antisymm {a b:Nat} (hab: a ≥ b) (hba: b ≥ a) : a = b := by
  sorry

theorem Nat.add_le_add_right (a b c:Nat) : a ≤ b ↔ a + c ≤ b + c := 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.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

abbrev Nat.mul (n m : Nat) : Nat := Nat.recurse (fun _ prod ↦ prod + m) 0 n

instance Nat.instMul : Mul Nat where
  mul := mul

theorem Nat.zero_mul (m: Nat) : 0 * m = 0 := by
  sorry

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

theorem Nat.one_mul' (m: Nat) : 1 * m = 0 + m := by
  sorry

theorem Nat.one_mul (m: Nat) : 1 * m = m := by
  sorry

theorem Nat.two_mul (m: Nat) : 2 * m = 0 + m + m := by
  sorry

lemma Nat.mul_zero (n: Nat) : n * 0 = 0 := by
  sorry

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

lemma Nat.mul_comm (n m: Nat) : n * m = m * n := by
  sorry

theorem Nat.mul_one (m: Nat) : m * 1 = m := by
  sorry

lemma Nat.pos_mul_pos {n m: Nat} (h₁: n.IsPos) (h₂: m.IsPos) : (n * m).IsPos := by
  sorry

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

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

theorem Nat.mul_assoc (a b c: Nat) : (a * b) * c = a * (b * c) := by
  sorry

instance Nat.instCommSemiring : CommSemiring Nat where
  left_distrib := mul_add
  right_distrib := add_mul
  zero_mul := zero_mul
  mul_zero := mul_zero
  mul_assoc := mul_assoc
  one_mul := one_mul
  mul_one := mul_one
  mul_comm := mul_comm

theorem Nat.mul_lt_mul_of_pos_right {a b c: Nat} (h: a < b) (hc: c.IsPos) : a * c < b * c := by
  sorry

theorem Nat.mul_gt_mul_of_pos_right {a b c: Nat} (h: a > b) (hc: c.IsPos) :
    a * c > b * c := by
  sorry

theorem Nat.mul_lt_mul_of_pos_left {a b c: Nat} (h: a < b) (hc: c.IsPos) : c * a < c * b := by
  sorry

theorem Nat.mul_gt_mul_of_pos_left {a b c: Nat} (h: a > b) (hc: c.IsPos) :
    c * a > c * b := by
  sorry

lemma Nat.mul_cancel_right {a b c: Nat} (h: a * c = b * c) (hc: c.IsPos) : a = b := by
  sorry

instance Nat.isOrderedRing : IsOrderedRing Nat where
  zero_le_one := by sorry
  mul_le_mul_of_nonneg_left := by sorry
  mul_le_mul_of_nonneg_right := by sorry

abbrev Nat.pow (m n: Nat) : Nat := Nat.recurse (fun _ prod ↦ prod * m) 1 n

instance Nat.instPow : HomogeneousPow Nat where
  pow := Nat.pow

@[simp]
theorem Nat.pow_zero (m: Nat) : m ^ (0:Nat) = 1 := by
  sorry

@[simp]
theorem Nat.zero_pow_zero : (0:Nat) ^ 0 = 1 := by
  sorry

theorem Nat.pow_succ (m n: Nat) : (m:Nat) ^ n++ = m^n * m := by
  sorry

@[simp]
theorem Nat.pow_one (m: Nat) : m ^ (1:Nat) = m := by
  sorry
-- </CONTEXT>
-- <TARGET_THEOREM>
theorem Nat.sq_add_eq (a b: Nat) :
    (a + b) ^ (2 : Nat) = a ^ (2 : Nat) + 2 * a * b + b ^ (2 : Nat) := by
-- </TARGET_THEOREM>

end Chapter2