import Mathlib.Data.List.Sort

import Bookshelf.List.Basic
import Bookshelf.Real.Set.Interval

namespace Real

open List

/--
A `Partition` is some finite subset of `[a, b]` containing points `a` and `b`.

It is assumed that the points of the `Partition` are distinct and sorted. The
use of a `List` ensures finite-ness.
-/
structure Partition where
  xs : List ℝ
  sorted : Sorted LT.lt xs
  has_min_length : xs.length ≥ 2

/--
The length of any list associated with a `Partition` is `> 0`.
-/
private lemma length_gt_zero (p : Partition) : p.xs.length > 0 :=
  calc p.xs.length
    _ ≥ 2 := p.has_min_length
    _ > 0 := by simp

/--
The length of any list associated with a `Partition` is `≠ 0`.
-/
instance (p : Partition) : NeZero (length p.xs) where
  out := LT.lt.ne' (length_gt_zero p)

namespace Partition

/--
The left-most subdivision point of the `Partition`.
-/
def left (p : Partition) : ℝ :=
  p.xs.head (neq_nil_iff_length_gt_zero.mpr (length_gt_zero p))

/--
The right-most subdivision point of the `Partition`.
-/
def right (p : Partition) : ℝ :=
  p.xs.getLast (neq_nil_iff_length_gt_zero.mpr (length_gt_zero p))

/--
Define `∈` syntax for a `Partition`. We say a real is a member of a partition
provided it lies somewhere in closed interval `[a, b]`.
-/
instance : Membership ℝ Partition where
  mem (x : ℝ) (p : Partition) := p.left ≤ x ∧ x ≤ p.right

/--
Every subdivision point is `≥` the left-most point of the partition.
-/
theorem subdivision_point_geq_left {p : Partition} (h : x ∈ p.xs)
  : p.left ≤ x := by
  unfold left
  rw [head_eq_get_zero (exists_mem_iff_neq_nil.mp ⟨x, h⟩)]
  have ⟨i, hi⟩ := mem_iff_exists_get.mp h
  conv => rhs; rw [← hi]
  by_cases hz : i = (0 : Fin (length p.xs))
  · rw [hz]
    simp
  · refine le_of_lt (Sorted.rel_get_of_lt p.sorted ?_)
    rwa [← ne_eq, ← Fin.pos_iff_ne_zero i] at hz

/--
Every subdivision point is `≤` the right-most point of the partition.
-/
theorem subdivision_point_leq_right {p : Partition} (h : x ∈ p.xs)
  : x ≤ p.right := by
  unfold right
  have hx := exists_mem_iff_neq_nil.mp ⟨x, h⟩
  rw [getLast_eq_get_length_sub_one hx]
  have ⟨i, hi⟩ := mem_iff_exists_get.mp h
  conv => lhs; rw [← hi]
  have ⟨_, ⟨_, hs⟩⟩ := self_neq_nil_imp_exists_mem.mp hx
  by_cases hz : i = ⟨p.xs.length - 1, by rw [hs]; simp⟩
  · rw [hz]
  · refine le_of_lt (Sorted.rel_get_of_lt p.sorted ?_)
    rw [← ne_eq, Fin.ne_iff_vne] at hz
    rw [Fin.lt_iff_val_lt_val]
    exact lt_of_le_of_ne (le_tsub_of_add_le_right i.2) hz

/--
Every subdivision point of a `Partition` is itself a member of the `Partition`.
-/
theorem subdivision_point_mem_partition {p : Partition} (h : x ∈ p.xs)
  : x ∈ p := ⟨subdivision_point_geq_left h, subdivision_point_leq_right h⟩

end Partition

end Real