import Mathlib
import Analysis.Section_11_1
import Analysis.Tags.Section_11_1

namespace Chapter11

-- <CONTEXT>
inductive BoundedInterval where
  | Ioo (a b : ℝ) : BoundedInterval
  | Icc (a b : ℝ) : BoundedInterval
  | Ioc (a b : ℝ) : BoundedInterval
  | Ico (a b : ℝ) : BoundedInterval

open BoundedInterval

@[coe]
def BoundedInterval.toSet (I : BoundedInterval) : Set ℝ := match I with
  | Ioo a b => .Ioo a b
  | Icc a b => .Icc a b
  | Ioc a b => .Ioc a b
  | Ico a b => .Ico a b

instance BoundedInterval.inst_coeSet : Coe BoundedInterval (Set ℝ) where
  coe := toSet

instance BoundedInterval.instEmpty : EmptyCollection BoundedInterval where
  emptyCollection := Ioo 0 0

open Classical in
noncomputable instance BoundedInterval.decidableEq : DecidableEq BoundedInterval := Classical.decEq _

instance BoundedInterval.instMembership : Membership ℝ BoundedInterval where
  mem I x := x ∈ (I : Set ℝ)

instance BoundedInterval.instSubset : HasSubset BoundedInterval where
  Subset I J := ∀ x, x ∈ I → x ∈ J

abbrev BoundedInterval.a (I : BoundedInterval) : ℝ := match I with
  | Ioo a _ => a
  | Icc a _ => a
  | Ioc a _ => a
  | Ico a _ => a

abbrev BoundedInterval.b (I : BoundedInterval) : ℝ := match I with
  | Ioo _ b => b
  | Icc _ b => b
  | Ioc _ b => b
  | Ico _ b => b

abbrev BoundedInterval.length (I : BoundedInterval) : ℝ := max (I.b - I.a) 0

macro:max atomic("|" noWs) a:term noWs "|ₗ" : term => `(BoundedInterval.length $a)

abbrev BoundedInterval.joins (K I J : BoundedInterval) : Prop := (I : Set ℝ) ∩ (J : Set ℝ) = ∅
  ∧ (K : Set ℝ) = (I : Set ℝ) ∪ (J : Set ℝ) ∧ |K|ₗ = |I|ₗ + |J|ₗ

theorem BoundedInterval.join_Icc_Ioc {a b c : ℝ} (hab : a ≤ b) (hbc : b ≤ c) : (Icc a c).joins (Icc a b) (Ioc b c) := by
  sorry

theorem BoundedInterval.join_Ico_Icc {a b c : ℝ} (hab : a ≤ b) (hbc : b ≤ c) : (Icc a c).joins (Ico a b) (Icc b c) := by
  sorry

theorem BoundedInterval.join_Ico_Ico {a b c : ℝ} (hab : a ≤ b) (hbc : b ≤ c) : (Ico a c).joins (Ico a b) (Ico b c) := by
  sorry

@[ext]
structure Partition (I : BoundedInterval) where
  intervals : Finset BoundedInterval
  exists_unique (x : ℝ) (hx : x ∈ I) : ∃! J, J ∈ intervals ∧ x ∈ J
  contains (J : BoundedInterval) (hJ : J ∈ intervals) : J ⊆ I

instance Partition.instMembership (I : BoundedInterval) : Membership BoundedInterval (Partition I) where
  mem P J := J ∈ P.intervals

instance Partition.instBot (I : BoundedInterval) : Bot (Partition I) where
  bot := {
    intervals := {I}
    exists_unique := by
      sorry
    contains := by
      sorry
  }

noncomputable abbrev Partition.join {I J K : BoundedInterval} (P : Partition I) (Q : Partition J) (h : K.joins I J) : Partition K :=
{
  intervals := P.intervals ∪ Q.intervals
  exists_unique := by
    sorry
  contains := by
    sorry
}

noncomputable abbrev Partition.add_empty {I : BoundedInterval} (P : Partition I) : Partition I := {
  intervals := P.intervals ∪ {∅}
  exists_unique := by
    sorry
  contains := by
    sorry
}

abbrev Constant {X Y : Type} (f : X → Y) : Prop := ∃ c, ∀ x, f x = c

open Classical in
noncomputable abbrev constant_value {X Y : Type} [hY : Nonempty Y] (f : X → Y) : Y :=
  if h : Constant f then h.choose else hY.some

theorem Constant.eq {X Y : Type} {f : X → Y} [Nonempty Y] (h : Constant f) (x : X) :
  f x = constant_value f := by
  sorry

theorem Constant.of_const {X Y : Type} {f : X → Y} {c : Y} (h : ∀ x, f x = c) :
  Constant f := by
  sorry

theorem Constant.const_eq {X Y : Type} {f : X → Y} [hX : Nonempty X] [Nonempty Y] {c : Y} (h : ∀ x, f x = c) :
  constant_value f = c := by
  sorry

theorem Constant.of_subsingleton {X Y : Type} [hs : Subsingleton X] [hY : Nonempty Y] {f : X → Y} :
  Constant f := by
  sorry

abbrev ConstantOn (f : ℝ → ℝ) (X : Set ℝ) : Prop := Constant (fun x : X ↦ f ↑x)

noncomputable abbrev constant_value_on (f : ℝ → ℝ) (X : Set ℝ) : ℝ := constant_value (fun x : X ↦ f ↑x)

theorem ConstantOn.eq {f : ℝ → ℝ} {X : Set ℝ} (h : ConstantOn f X) {x : ℝ} (hx : x ∈ X) :
  f x = constant_value_on f X := by
  sorry

theorem ConstantOn.of_const {f : ℝ → ℝ} {X : Set ℝ} {c : ℝ} (h : ∀ x ∈ X, f x = c) :
  ConstantOn f X := by
  sorry

theorem ConstantOn.of_const' (c : ℝ) (X : Set ℝ) : ConstantOn (fun _ ↦ c) X := by
  sorry

theorem ConstantOn.const_eq {f : ℝ → ℝ} {X : Set ℝ} (hX : X.Nonempty) {c : ℝ} (h : ∀ x ∈ X, f x = c) :
  constant_value_on f X = c := by
  sorry

theorem ConstantOn.congr {f g : ℝ → ℝ} {X : Set ℝ} (h : ∀ x ∈ X, f x = g x) : ConstantOn f X ↔ ConstantOn g X := by
  sorry

theorem ConstantOn.congr' {f g : ℝ → ℝ} {X : Set ℝ} (hf : ConstantOn f X) (h : ∀ x ∈ X, f x = g x) : ConstantOn g X := by
  sorry

theorem ConstantOn.of_subsingleton {f : ℝ → ℝ} {X : Set ℝ} [Subsingleton X] :
  ConstantOn f X := by
  sorry

theorem constant_value_on_congr {f g : ℝ → ℝ} {X : Set ℝ} (h : ∀ x ∈ X, f x = g x) :
  constant_value_on f X = constant_value_on g X := by
  sorry

abbrev PiecewiseConstantWith (f : ℝ → ℝ) {I : BoundedInterval} (P : Partition I) : Prop := ∀ J ∈ P, ConstantOn f (J : Set ℝ)

theorem PiecewiseConstantWith.def (f : ℝ → ℝ) {I : BoundedInterval} {P : Partition I} :
  PiecewiseConstantWith f P ↔ ∀ J ∈ P, ∃ c, ∀ x ∈ J, f x = c := by
  sorry

theorem PiecewiseConstantWith.congr {f g : ℝ → ℝ} {I : BoundedInterval} {P : Partition I}
  (h : ∀ x ∈ (I : Set ℝ), f x = g x) :
  PiecewiseConstantWith f P ↔ PiecewiseConstantWith g P := by
  sorry

abbrev PiecewiseConstantOn (f : ℝ → ℝ) (I : BoundedInterval) : Prop := ∃ P : Partition I, PiecewiseConstantWith f P

theorem PiecewiseConstantOn.def (f : ℝ → ℝ) (I : BoundedInterval) :
  PiecewiseConstantOn f I ↔ ∃ P : Partition I, ∀ J ∈ P, ConstantOn f (J : Set ℝ) := by
  sorry

theorem PiecewiseConstantOn.congr {f g : ℝ → ℝ} {I : BoundedInterval} (h : ∀ x ∈ (I : Set ℝ), f x = g x) :
  PiecewiseConstantOn f I ↔ PiecewiseConstantOn g I := by
  sorry

theorem PiecewiseConstantOn.congr' {f g : ℝ → ℝ} {I : BoundedInterval} (hf : PiecewiseConstantOn f I) (h : ∀ x ∈ (I : Set ℝ), f x = g x) : PiecewiseConstantOn g I := by
  sorry

noncomputable abbrev f_11_2_4 : ℝ → ℝ := fun x ↦
  if x < 1 then 0 else
    if x < 3 then 7 else
      if x = 3 then 4 else
        if x < 6 then 5 else
          if x = 6 then 2 else
            0

theorem ConstantOn.piecewiseConstantOn {f : ℝ → ℝ} {I : BoundedInterval} (h : ConstantOn f (I : Set ℝ)) :
  PiecewiseConstantOn f I := by
  sorry

noncomputable abbrev PiecewiseConstantWith.integ (f : ℝ → ℝ) {I : BoundedInterval} (P : Partition I) :
  ℝ := ∑ J ∈ P.intervals, constant_value_on f (J : Set ℝ) * |J|ₗ

theorem PiecewiseConstantWith.integ_congr {f g : ℝ → ℝ} {I : BoundedInterval} {P : Partition I}
  (h : ∀ x ∈ (I : Set ℝ), f x = g x) : integ f P = integ g P := by
  sorry

noncomputable abbrev f_11_2_12 : ℝ → ℝ := fun x ↦
    if x < 3 then 2 else
      if x = 3 then 4 else
        6

noncomputable abbrev P_11_2_12 : Partition (Icc 1 4) :=
  ((⊥ : Partition (Ico 1 3)).join (⊥ : Partition (Icc 3 3))
  (join_Ico_Icc (by norm_num) (by norm_num))).join
  (⊥ : Partition (Ioc 3 4))
  (join_Icc_Ioc (by norm_num) (by norm_num))

noncomputable abbrev P_11_2_12' : Partition (Icc 1 4) :=
  ((((⊥ : Partition (Ico 1 2)).join (⊥ : Partition (Ico 2 3))
  (join_Ico_Ico (by norm_num) (by norm_num))).join
  (⊥ : Partition (Icc 3 3))
  (join_Ico_Icc (by norm_num) (by norm_num))).join
  (⊥ : Partition (Ioc 3 4))
  (join_Icc_Ioc (by norm_num) (by norm_num))).add_empty

open Classical in
noncomputable abbrev PiecewiseConstantOn.integ (f : ℝ → ℝ) (I : BoundedInterval) :
  ℝ := if h : PiecewiseConstantOn f I then PiecewiseConstantWith.integ f h.choose else 0

noncomputable abbrev PiecewiseConstantOn.integ' {f : ℝ → ℝ} {I : BoundedInterval} (_ : PiecewiseConstantOn f I) := integ f I

theorem PiecewiseConstantOn.integ_def {f : ℝ → ℝ} {I : BoundedInterval} {P : Partition I}
  (h : PiecewiseConstantWith f P) : integ f I = PiecewiseConstantWith.integ f P := by
  sorry

theorem PiecewiseConstantOn.integ_congr {f g : ℝ → ℝ} {I : BoundedInterval}
  (h : ∀ x ∈ (I : Set ℝ), f x = g x) : integ f I = integ g I := by
  sorry
-- </CONTEXT>
-- <TARGET_THEOREM>
open Classical in
theorem PiecewiseConstantOn.of_extend {I J : BoundedInterval} (hIJ : I ⊆ J)
  {f : ℝ → ℝ} (h : PiecewiseConstantOn f I) :
  PiecewiseConstantOn (fun x ↦ if x ∈ I then f x else 0) J := by
-- </TARGET_THEOREM>

end Chapter11