import Mathlib
import Analysis.Section_9_6
import Analysis.Tags.Section_9_6
import Analysis.Section_10_3
import Analysis.Tags.Section_10_3
import Analysis.Section_11_9
import Analysis.Tags.Section_11_9

namespace Chapter10
end Chapter10

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

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 := BoundedInterval.toSet

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

@[simp] theorem BoundedInterval.mem_iff (I : BoundedInterval) (x : ℝ) : x ∈ I ↔ x ∈ (I : Set ℝ) := by
  sorry

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

open Chapter9

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)

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})

noncomputable abbrev integ (f : ℝ → ℝ) (I : BoundedInterval) : ℝ := upper_integral f I

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

noncomputable abbrev right_lim (f : ℝ → ℝ) (x₀ : ℝ) : ℝ := lim ((nhdsWithin x₀ (.Ioi x₀)).map f)

noncomputable abbrev left_lim (f : ℝ → ℝ) (x₀ : ℝ) : ℝ := lim ((nhdsWithin x₀ (.Iio x₀)).map f)

noncomputable abbrev jump (f : ℝ → ℝ) (x₀ : ℝ) : ℝ :=
  right_lim f x₀ - left_lim f x₀

noncomputable abbrev α_length (α : ℝ → ℝ) (I : BoundedInterval) : ℝ := match I with
  | Icc a b => if a ≤ b then (right_lim α b) - (left_lim α a) else 0
  | Ico a b => if a ≤ b then (left_lim α b) - (left_lim α a) else 0
  | Ioc a b => if a ≤ b then (right_lim α b) - (right_lim α a) else 0
  | Ioo a b => if a < b then (left_lim α b) - (right_lim α a) else 0

notation3:max α"["I"]ₗ" => α_length α I

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

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

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

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

noncomputable abbrev RS_integ (f : ℝ → ℝ) (I : BoundedInterval) (α : ℝ → ℝ) : ℝ := upper_RS_integral f I α

noncomputable abbrev RS_IntegrableOn (f : ℝ → ℝ) (I : BoundedInterval) (α : ℝ → ℝ) : Prop :=
  BddOn f I ∧ lower_RS_integral f I α = upper_RS_integral f I α

open BoundedInterval Chapter9 Chapter10

theorem PiecewiseConstantOn.RS_integ_eq_integ_of_mul_deriv
  {a b : ℝ} {α f : ℝ → ℝ}
  (hα_diff : DifferentiableOn ℝ α (Icc a b)) (hαcont : Continuous α)
  (hα' : IntegrableOn (derivWithin α (Icc a b)) (Icc a b))
  (hf : PiecewiseConstantOn f (Icc a b)) :
  IntegrableOn (f * derivWithin α (Icc a b)) (Icc a b) ∧
  Chapter11.integ (f * derivWithin α (Icc a b)) (Icc a b) = RS_integ f (Icc a b) α := by
  sorry

theorem RS_integ_eq_integ_of_mul_deriv
  {a b : ℝ} (hab : a < b) {α f : ℝ → ℝ} (hα : Monotone α)
  (hα_diff : DifferentiableOn ℝ α (Icc a b)) (hαcont : Continuous α)
  (hα' : IntegrableOn (derivWithin α (Icc a b)) (Icc a b))
  (hf : RS_IntegrableOn f (Icc a b) α) :
  IntegrableOn (f * derivWithin α (Icc a b)) (Icc a b) ∧
  integ (f * derivWithin α (Icc a b)) (Icc a b) = RS_integ f (Icc a b) α := by
  sorry

theorem RS_integ_of_comp {a b : ℝ} (hab : a < b) {ϕ f : ℝ → ℝ}
  (hφ_cont : Continuous ϕ) (hφ_mono : Monotone ϕ) (hf : IntegrableOn f (Icc (ϕ a) (ϕ b))) :
  RS_IntegrableOn (f ∘ ϕ) (Icc a b) ϕ ∧
  RS_integ (f ∘ ϕ) (Icc a b) ϕ = integ f (Icc (ϕ a) (ϕ b)) := by
  sorry

theorem integ_of_comp {a b : ℝ} (hab : a < b) {ϕ f : ℝ → ℝ}
  (hφ_diff : DifferentiableOn ℝ ϕ (Icc a b))
  (hφ_cont : Continuous ϕ) (hφ_mono : Monotone ϕ)
  (hφ' : IntegrableOn (derivWithin ϕ (Icc a b)) (Icc a b))
  (hf : IntegrableOn f (Icc (ϕ a) (ϕ b))) :
  IntegrableOn (f ∘ ϕ * derivWithin ϕ (Icc a b)) (Icc a b) ∧
  integ (f ∘ ϕ * derivWithin ϕ (Icc a b)) (Icc a b) =
    integ f (Icc (ϕ a) (ϕ b)) := by
  sorry
-- </CONTEXT>
-- <TARGET_THEOREM>
theorem Exercise_11_10_3 {a b : ℝ} (hab : a < b) {f : ℝ → ℝ}
    (hf : IntegrableOn f (Icc a b)) :
    IntegrableOn (fun x ↦ f (-x)) (Icc (-b) (-a)) ∧
    integ (fun x ↦ f (-x)) (Icc (-b) (-a)) = -integ f (Icc a b) := by
-- </TARGET_THEOREM>

end Chapter11