import Mathlib.Tactic

/-- Definition from Section 4.3: eps-closeness on rationals -/
def Rat.Close (ε : ℚ) (x y : ℚ) := |x - y| ≤ ε

namespace Chapter5

@[ext]
structure Sequence where
  n₀ : ℤ
  seq : ℤ → ℚ
  vanish : ∀ n < n₀, seq n = 0

instance Sequence.instCoeFun : CoeFun Sequence (fun _ ↦ ℤ → ℚ) where
  coe := fun a ↦ a.seq

/-- Functions from ℕ to ℚ coerced to sequences starting at 0. -/
@[coe]
def Sequence.ofNatFun (a : ℕ → ℚ) : Sequence where
  n₀ := 0
  seq n := if n ≥ 0 then a n.toNat else 0
  vanish := by
    grind

instance : Coe (ℕ → ℚ) Sequence where
  coe := Sequence.ofNatFun

abbrev Sequence.mk' (n₀ : ℤ) (a : { n // n ≥ n₀ } → ℚ) : Sequence where
  n₀ := n₀
  seq n := if h : n ≥ n₀ then a ⟨n, h⟩ else 0
  vanish := by
    grind

@[simp]
lemma Sequence.eval_coe_at_int (n : ℤ) (a : ℕ → ℚ) :
    (a : Sequence) n = if n ≥ 0 then a n.toNat else 0 := by
  norm_cast

@[simp]
lemma Sequence.n0_coe (a : ℕ → ℚ) : (a : Sequence).n₀ = 0 := by
  norm_cast

/-- Start a sequence from a later index. -/
abbrev Sequence.from (a : Sequence) (n₁ : ℤ) : Sequence :=
  mk' (max a.n₀ n₁) (fun n ↦ a (n : ℤ))

end Chapter5

/-- ε-steadiness of a sequence (Section 5.1). -/
abbrev Rat.Steady (ε : ℚ) (a : Chapter5.Sequence) : Prop :=
  ∀ n ≥ a.n₀, ∀ m ≥ a.n₀, ε.Close (a n) (a m)

/-- Eventually ε-steadiness (reusing `Sequence.from`). -/
abbrev Rat.EventuallySteady (ε : ℚ) (a : Chapter5.Sequence) : Prop :=
  ∃ N ≥ a.n₀, ε.Steady (a.from N)

namespace Chapter5

/-- Eventually ε-steadiness (Section 5.1). -/
abbrev Sequence.IsCauchy (a : Sequence) : Prop := ∀ ε > (0 : ℚ), ε.EventuallySteady a

end Chapter5

/-- ε-close sequences (Section 5.2). -/
abbrev Rat.CloseSeq (ε : ℚ) (a b : Chapter5.Sequence) : Prop :=
  ∀ n, n ≥ a.n₀ → n ≥ b.n₀ → ε.Close (a n) (b n)

/-- Eventually ε-close sequences (Section 5.2). -/
abbrev Rat.EventuallyClose (ε : ℚ) (a b : Chapter5.Sequence) : Prop :=
  ∃ N, ε.CloseSeq (a.from N) (b.from N)

namespace Chapter5

/-- Equivalent sequences (Section 5.2). -/
abbrev Sequence.Equiv (a b : ℕ → ℚ) : Prop :=
  ∀ ε > (0 : ℚ), ε.EventuallyClose (a : Sequence) (b : Sequence)

/-- Cauchy sequences starting at 0 (Section 5.3). -/
@[ext]
class CauchySequence extends Sequence where
  zero : n₀ = 0
  cauchy : toSequence.IsCauchy

instance CauchySequence.instCoeFun : CoeFun CauchySequence (fun _ ↦ ℕ → ℚ) where
  coe a n := a.toSequence (n : ℤ)

/-- View a Cauchy sequence coming from a Cauchy ℕ-indexed sequence. -/
abbrev CauchySequence.mk' {a : ℕ → ℚ} (ha : (a : Sequence).IsCauchy) : CauchySequence where
  n₀ := 0
  seq := (a : Sequence).seq
  vanish := by aesop
  zero := rfl
  cauchy := ha

/-- Setoid of Cauchy sequences modulo eventual closeness (Section 5.3). -/
instance CauchySequence.instSetoid : Setoid CauchySequence where
  r := fun a b ↦ Sequence.Equiv a b
  iseqv :=
    { refl := sorry
      symm := sorry
      trans := sorry }

/-- Constant sequences are Cauchy. -/
lemma Sequence.IsCauchy.const (a : ℚ) : ((fun _ : ℕ ↦ a) : Sequence).IsCauchy := by
  sorry

/-- Zero Cauchy sequence. -/
instance CauchySequence.instZero : Zero CauchySequence where
  zero := CauchySequence.mk' (a := fun _ : ℕ ↦ 0) (Sequence.IsCauchy.const (0 : ℚ))

/-- The real numbers as equivalence classes of Cauchy sequences (Section 5.3). -/
abbrev Real := Quotient CauchySequence.instSetoid

open Classical in
/-- Formal limit of a sequence, defaulting to 0 if not Cauchy (Section 5.3). -/
noncomputable abbrev LIM (a : ℕ → ℚ) : Real :=
  Quotient.mk _ (if h : (a : Sequence).IsCauchy then CauchySequence.mk' h else (0 : CauchySequence))

/-- Sequences bounded away from zero on the positive side (Section 5.4). -/
abbrev BoundedAwayPos (a : ℕ → ℚ) : Prop :=
  ∃ c : ℚ, c > 0 ∧ ∀ n, a n ≥ c

/-- Sequences bounded away from zero on the negative side (Section 5.4). -/
abbrev BoundedAwayNeg (a : ℕ → ℚ) : Prop :=
  ∃ c : ℚ, c > 0 ∧ ∀ n, a n ≤ -c

namespace Real

/-- Positive real (via a positive, Cauchy rational sequence with given limit). -/
abbrev IsPos (x : Chapter5.Real) : Prop :=
  ∃ a : ℕ → ℚ, BoundedAwayPos a ∧ (a : Sequence).IsCauchy ∧ x = LIM a

/-- Negative real (via a negative, Cauchy rational sequence with given limit). -/
abbrev IsNeg (x : Chapter5.Real) : Prop :=
  ∃ a : ℕ → ℚ, BoundedAwayNeg a ∧ (a : Sequence).IsCauchy ∧ x = LIM a

end Real

/-- Proposition 5.4.4 (basic properties of positive reals) / Exercise 5.4.1 -/
 theorem Real.not_pos_neg (x:Real) : ¬(x.IsPos ∧ x.IsNeg) := by
end Chapter5