import Mathlib
import Analysis.Section_9_9
import Analysis.Tags.Section_9_9
import Analysis.Section_11_4
import Analysis.Tags.Section_11_4

namespace Chapter11

inductive BoundedInterval where
  | Ioo (a b : ℝ) : BoundedInterval
  | Icc (a b : ℝ) : BoundedInterval
  | Ioc (a b : ℝ) : BoundedInterval
  | Ico (a b : ℝ) : 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 : Coe BoundedInterval (Set ℝ) where
  coe := BoundedInterval.toSet

noncomputable instance : DecidableEq BoundedInterval := Classical.decEq _

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

instance : 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)

@[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 (I : BoundedInterval) : Membership BoundedInterval (Partition I) where
  mem P J := J ∈ P.intervals

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

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

namespace ConstantOn
end ConstantOn

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

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

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

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

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

abbrev MajorizesOn (g f : ℝ → ℝ) (I : BoundedInterval) : Prop := ∀ x ∈ (I : Set ℝ), f x ≤ g x

abbrev MinorizesOn (g f : ℝ → ℝ) (I : BoundedInterval) : Prop := ∀ x ∈ (I : Set ℝ), g x ≤ f x

noncomputable abbrev upper_integral (f : ℝ → ℝ) (I : BoundedInterval) : ℝ :=
  sInf ((PiecewiseConstantOn.integ · I) '' {g | MajorizesOn g f I ∧ PiecewiseConstantOn g I})

noncomputable abbrev lower_integral (f : ℝ → ℝ) (I : BoundedInterval) : ℝ :=
  sSup ((PiecewiseConstantOn.integ · I) '' {g | MinorizesOn g f I ∧ PiecewiseConstantOn g I})

end Chapter11

namespace Chapter9

abbrev BddOn (f : ℝ → ℝ) (X : Set ℝ) : Prop := ∃ M, ∀ x ∈ X, |f x| ≤ M

end Chapter9

namespace Chapter11

open Chapter9

noncomputable abbrev IntegrableOn (f : ℝ → ℝ) (I : BoundedInterval) : Prop :=
  BddOn f I ∧ lower_integral f I = upper_integral f I

end Chapter11

namespace Chapter11
open BoundedInterval
open Chapter9

-- <CONTEXT>
theorem integ_of_uniform_cts {I: BoundedInterval} {f:ℝ → ℝ} (hf: UniformContinuousOn f I) :
  IntegrableOn f I := by
  sorry

theorem integ_of_cts {a b:ℝ} {f:ℝ → ℝ} (hf: ContinuousOn f (Icc a b)) :
  IntegrableOn f (Icc a b) := by
  sorry

open PiecewiseConstantOn ConstantOn in
set_option maxHeartbeats 300000 in
theorem integ_of_bdd_cts {I: BoundedInterval} {f:ℝ → ℝ} (hbound: BddOn f I)
  (hf: ContinuousOn f I) : IntegrableOn f I := by
  sorry

abbrev PiecewiseContinuousOn (f:ℝ → ℝ) (I:BoundedInterval) : Prop :=
  ∃ P: Partition I, ∀ J ∈ P.intervals, ContinuousOn f J

noncomputable abbrev f_11_5_5 : ℝ → ℝ := fun x ↦
  if x < 2 then x^2
  else if x = 2 then 7
  else x^3
-- </CONTEXT>
-- <TARGET_THEOREM>
theorem integ_of_bdd_piecewise_cts {I: BoundedInterval} {f:ℝ → ℝ}
  (hbound: BddOn f I) (hf: PiecewiseContinuousOn f I) : IntegrableOn f I := by
-- </TARGET_THEOREM>

end Chapter11