/-- If a function is `C^n` on a domain with unique derivatives, then its bundled derivative
is `C^m` when `m+1 ≤ n`. -/
theorem ContMDiffOn.contMDiffOn_tangentMapWithin (hf : ContMDiffOn I I' n f s) (hmn : m + 1 ≤ n)
    (hs : UniqueMDiffOn I s) :
    ContMDiffOn I.tangent I'.tangent m (tangentMapWithin I I' f s)
      (π E (TangentSpace I) ⁻¹' s) := by
  /- The strategy of the proof is to avoid unfolding the definitions, and reduce by functoriality
    to the case of functions on the model spaces, where we have already proved the result.
    Let `l` and `r` be the charts to the left and to the right, so that we have
    ```
       l^{-1}      f       r
    H --------> M ---> M' ---> H'
    ```
    Then the tangent map `T(r ∘ f ∘ l)` is smooth by a previous result. Consider the composition
    ```
        Tl        T(r ∘ f ∘ l^{-1})         Tr^{-1}
    TM -----> TH -------------------> TH' ---------> TM'
    ```
    where `Tr^{-1}` and `Tl` are the tangent maps of `r^{-1}` and `l`. Writing `Tl` and `Tr^{-1}` as
    composition of charts (called `Dl` and `il` for `l` and `Dr` and `ir` in the proof below), it
    follows that they are smooth. The composition of all these maps is `Tf`, and is therefore smooth
    as a composition of smooth maps.
    -/
  have one_le_n : 1 ≤ n := (le_add_left le_rfl).trans hmn
  -- First step: local reduction on the space, to a set `s'` which is contained in chart domains.
  refine' contMDiffOn_of_locally_contMDiffOn fun p hp => _
  have hf' := contMDiffOn_iff.1 hf
  simp only [mfld_simps] at hp
  let l := chartAt H p.proj
  set Dl := chartAt (ModelProd H E) p with hDl
  let r := chartAt H' (f p.proj)
  let Dr := chartAt (ModelProd H' E') (tangentMapWithin I I' f s p)
  let il := chartAt (ModelProd H E) (tangentMap I I l p)
  let ir := chartAt (ModelProd H' E') (tangentMap I I' (r ∘ f) p)
  let s' := f ⁻¹' r.source ∩ s ∩ l.source
  let s'_lift := π E (TangentSpace I) ⁻¹' s'
  let s'l := l.target ∩ l.symm ⁻¹' s'
  let s'l_lift := π E (TangentSpace I) ⁻¹' s'l
  rcases continuousOn_iff'.1 hf'.1 r.source r.open_source with ⟨o, o_open, ho⟩
  suffices h : ContMDiffOn I.tangent I'.tangent m (tangentMapWithin I I' f s) s'_lift
  · refine' ⟨π E (TangentSpace I) ⁻¹' (o ∩ l.source), _, _, _⟩
    show IsOpen (π E (TangentSpace I) ⁻¹' (o ∩ l.source));
    exact (IsOpen.inter o_open l.open_source).preimage (FiberBundle.continuous_proj E _)
    show p ∈ π E (TangentSpace I) ⁻¹' (o ∩ l.source)
    · simp
      have : p.proj ∈ f ⁻¹' r.source ∩ s := by simp [hp]
      rw [ho] at this
      exact this.1
    · have : π E (TangentSpace I) ⁻¹' s ∩ π E (TangentSpace I) ⁻¹' (o ∩ l.source) = s'_lift := by
        dsimp only; rw [ho]; mfld_set_tac
      rw [this]
      exact h
  /- Second step: check that all functions are smooth, and use the chain rule to write the bundled
    derivative as a composition of a function between model spaces and of charts.
    Convention: statements about the differentiability of `a ∘ b ∘ c` are named `diff_abc`.
    Statements about differentiability in the bundle have a `_lift` suffix. -/
  have U' : UniqueMDiffOn I s' := by
    apply UniqueMDiffOn.inter _ l.open_source
    rw [ho, inter_comm]
    exact hs.inter o_open
  have U'l : UniqueMDiffOn I s'l := U'.uniqueMDiffOn_preimage (mdifferentiable_chart _ _)
  have diff_f : ContMDiffOn I I' n f s' := hf.mono (by mfld_set_tac)
  have diff_r : ContMDiffOn I' I' n r r.source := contMDiffOn_chart
  have diff_rf : ContMDiffOn I I' n (r ∘ f) s' := by
    refine ContMDiffOn.comp diff_r diff_f fun x hx => ?_
    simp only [mfld_simps] at hx; simp only [hx, mfld_simps]
  have diff_l : ContMDiffOn I I n l.symm s'l :=
    haveI A : ContMDiffOn I I n l.symm l.target := contMDiffOn_chart_symm
    A.mono (by mfld_set_tac)
  have diff_rfl : ContMDiffOn I I' n (r ∘ f ∘ l.symm) s'l := by
    apply ContMDiffOn.comp diff_rf diff_l
    mfld_set_tac
  have diff_rfl_lift :
    ContMDiffOn I.tangent I'.tangent m (tangentMapWithin I I' (r ∘ f ∘ l.symm) s'l) s'l_lift :=
    diff_rfl.contMDiffOn_tangentMapWithin_aux hmn U'l
  have diff_irrfl_lift :
    ContMDiffOn I.tangent I'.tangent m (ir ∘ tangentMapWithin I I' (r ∘ f ∘ l.symm) s'l) s'l_lift :=
    haveI A : ContMDiffOn I'.tangent I'.tangent m ir ir.source := contMDiffOn_chart
    ContMDiffOn.comp A diff_rfl_lift fun p _ => by simp only [mfld_simps]
  have diff_Drirrfl_lift :
    ContMDiffOn I.tangent I'.tangent m (Dr.symm ∘ ir ∘ tangentMapWithin I I' (r ∘ f ∘ l.symm) s'l)
      s'l_lift := by
    have A : ContMDiffOn I'.tangent I'.tangent m Dr.symm Dr.target := contMDiffOn_chart_symm
    refine ContMDiffOn.comp A diff_irrfl_lift fun p hp => ?_
    simp only [mfld_simps] at hp
    -- Porting note: added `rw` because `simp` can't see through some `ModelProd _ _ = _ × _`
    rw [mem_preimage, TangentBundle.mem_chart_target_iff]
    simp only [hp, mfld_simps]
  -- conclusion of this step: the composition of all the maps above is smooth
  have diff_DrirrflilDl :
    ContMDiffOn I.tangent I'.tangent m
      (Dr.symm ∘ (ir ∘ tangentMapWithin I I' (r ∘ f ∘ l.symm) s'l) ∘ il.symm ∘ Dl) s'_lift := by
    have A : ContMDiffOn I.tangent I.tangent m Dl Dl.source := contMDiffOn_chart
    have A' : ContMDiffOn I.tangent I.tangent m Dl s'_lift := by
      refine A.mono fun p hp => ?_
      simp only [mfld_simps] at hp
      simp only [hp, mfld_simps]
    have B : ContMDiffOn I.tangent I.tangent m il.symm il.target := contMDiffOn_chart_symm
    have C : ContMDiffOn I.tangent I.tangent m (il.symm ∘ Dl) s'_lift :=
      ContMDiffOn.comp B A' fun p _ => by simp only [mfld_simps]
    refine diff_Drirrfl_lift.comp C fun p hp => ?_
    simp only [mfld_simps] at hp
    simp only [hp, TotalSpace.proj, mfld_simps]
  /- Third step: check that the composition of all the maps indeed coincides with the derivative we
    are looking for -/
  have eq_comp :
      ∀ q ∈ s'_lift,
        tangentMapWithin I I' f s q =
          (Dr.symm ∘ ir ∘ tangentMapWithin I I' (r ∘ f ∘ l.symm) s'l ∘ il.symm ∘ Dl) q := by
    intro q hq
    simp only [mfld_simps] at hq
    have U'q : UniqueMDiffWithinAt I s' q.1 := by apply U'; simp only [hq, mfld_simps]
    have U'lq : UniqueMDiffWithinAt I s'l (Dl q).1 := by apply U'l; simp only [hq, mfld_simps]
    have A :
      tangentMapWithin I I' ((r ∘ f) ∘ l.symm) s'l (il.symm (Dl q)) =
        tangentMapWithin I I' (r ∘ f) s' (tangentMapWithin I I l.symm s'l (il.symm (Dl q))) := by
      refine' tangentMapWithin_comp_at (il.symm (Dl q)) _ _ (fun p hp => _) U'lq
      · apply diff_rf.mdifferentiableOn one_le_n
        simp only [hq, mfld_simps]
      · apply diff_l.mdifferentiableOn one_le_n
        simp only [hq, mfld_simps]
      · simp only [mfld_simps] at hp; simp only [hp, mfld_simps]
    have B : tangentMapWithin I I l.symm s'l (il.symm (Dl q)) = q := by
      have : tangentMapWithin I I l.symm s'l (il.symm (Dl q)) =
        tangentMap I I l.symm (il.symm (Dl q))
      · refine' tangentMapWithin_eq_tangentMap U'lq _
        -- Porting note: the arguments below were underscores.
        refine' mdifferentiableAt_atlas_symm I (chart_mem_atlas H (TotalSpace.proj p)) _
        simp only [hq, mfld_simps]
      rw [this, tangentMap_chart_symm, hDl]
      · simp only [hq, mfld_simps]
        have : q ∈ (chartAt (ModelProd H E) p).source := by simp only [hq, mfld_simps]
        exact (chartAt (ModelProd H E) p).left_inv this
      · simp only [hq, mfld_simps]
    have C :
      tangentMapWithin I I' (r ∘ f) s' q =
        tangentMapWithin I' I' r r.source (tangentMapWithin I I' f s' q) := by
      refine' tangentMapWithin_comp_at q _ _ (fun r hr => _) U'q
      · apply diff_r.mdifferentiableOn one_le_n
        simp only [hq, mfld_simps]
      · apply diff_f.mdifferentiableOn one_le_n
        simp only [hq, mfld_simps]
      · simp only [mfld_simps] at hr
        simp only [hr, mfld_simps]
    have D :
      Dr.symm (ir (tangentMapWithin I' I' r r.source (tangentMapWithin I I' f s' q))) =
        tangentMapWithin I I' f s' q := by
      have A :
        tangentMapWithin I' I' r r.source (tangentMapWithin I I' f s' q) =
          tangentMap I' I' r (tangentMapWithin I I' f s' q) := by
        apply tangentMapWithin_eq_tangentMap
        · apply IsOpen.uniqueMDiffWithinAt _ r.open_source; simp [hq]
        · exact mdifferentiableAt_atlas I' (chart_mem_atlas H' (f p.proj)) hq.1.1
      have : f p.proj = (tangentMapWithin I I' f s p).1 := rfl
      rw [A]
      dsimp
      rw [this, tangentMap_chart]
      · simp only [hq, mfld_simps]
        

Proof state:
𝕜 : Type u_1
inst✝²⁴ : NontriviallyNormedField 𝕜
E : Type u_2
inst✝²³ : NormedAddCommGroup E
inst✝²² : NormedSpace 𝕜 E
H : Type u_3
inst✝²¹ : TopologicalSpace H
I : ModelWithCorners 𝕜 E H
M : Type u_4
inst✝²⁰ : TopologicalSpace M
inst✝¹⁹ : ChartedSpace H M
Is : SmoothManifoldWithCorners I M
E' : Type u_5
inst✝¹⁸ : NormedAddCommGroup E'
inst✝¹⁷ : NormedSpace 𝕜 E'
H' : Type u_6
inst✝¹⁶ : TopologicalSpace H'
I' : ModelWithCorners 𝕜 E' H'
M' : Type u_7
inst✝¹⁵ : TopologicalSpace M'
inst✝¹⁴ : ChartedSpace H' M'
I's : SmoothManifoldWithCorners I' M'
F : Type u_8
inst✝¹³ : NormedAddCommGroup F
inst✝¹² : NormedSpace 𝕜 F
G : Type u_9
inst✝¹¹ : TopologicalSpace G
J : ModelWithCorners 𝕜 F G
N : Type u_10
inst✝¹⁰ : TopologicalSpace N
inst✝⁹ : ChartedSpace G N
Js : SmoothManifoldWithCorners J N
F' : Type u_11
inst✝⁸ : NormedAddCommGroup F'
inst✝⁷ : NormedSpace 𝕜 F'
G' : Type u_12
inst✝⁶ : TopologicalSpace G'
J' : ModelWithCorners 𝕜 F' G'
N' : Type u_13
inst✝⁵ : TopologicalSpace N'
inst✝⁴ : ChartedSpace G' N'
J's : SmoothManifoldWithCorners J' N'
F₁ : Type u_14
inst✝³ : NormedAddCommGroup F₁
inst✝² : NormedSpace 𝕜 F₁
F₂ : Type u_15
inst✝¹ : NormedAddCommGroup F₂
inst✝ : NormedSpace 𝕜 F₂
f f₁ : M → M'
s s₁ t : Set M
x : M
m n : ℕ∞
hf : ContMDiffOn I I' n f s
hmn : m + 1 ≤ n
hs : UniqueMDiffOn I s
one_le_n : 1 ≤ n
p : TangentBundle I M
hf' :
  ContinuousOn f s ∧
    ∀ (x : M) (y : M'),
      ContDiffOn 𝕜 n (↑(extChartAt I' y) ∘ f ∘ ↑(PartialEquiv.symm (extChartAt I x)))
        ((extChartAt I x).target ∩ ↑(PartialEquiv.symm (extChartAt I x)) ⁻¹' (s ∩ f ⁻¹' (extChartAt I' y).source))
hp : p.proj ∈ s
l : PartialHomeomorph M H := chartAt H p.proj
Dl : PartialHomeomorph (TangentBundle I M) (ModelProd H E) := chartAt (ModelProd H E) p
hDl : Dl = chartAt (ModelProd H E) p
r : PartialHomeomorph M' H' := chartAt H' (f p.proj)
Dr : PartialHomeomorph (TangentBundle I' M') (ModelProd H' E') :=
  chartAt (ModelProd H' E') (tangentMapWithin I I' f s p)
il : PartialHomeomorph (TangentBundle I H) (ModelProd H E) := chartAt (ModelProd H E) (tangentMap I I (↑l) p)
ir : PartialHomeomorph (TangentBundle I' H') (ModelProd H' E') := chartAt (ModelProd H' E') (tangentMap I I' (↑r ∘ f) p)
s' : Set M := f ⁻¹' r.source ∩ s ∩ l.source
s'_lift : Set (TotalSpace E (TangentSpace I)) := TotalSpace.proj ⁻¹' s'
s'l : Set H := l.target ∩ ↑(PartialHomeomorph.symm l) ⁻¹' s'
s'l_lift : Set (TotalSpace E (TangentSpace I)) := TotalSpace.proj ⁻¹' s'l
o : Set M
o_open : IsOpen o
ho : f ⁻¹' r.source ∩ s = o ∩ s
U' : UniqueMDiffOn I s'
U'l : UniqueMDiffOn I s'l
diff_f : ContMDiffOn I I' n f s'
diff_r : ContMDiffOn I' I' n (↑r) r.source
diff_rf : ContMDiffOn I I' n (↑r ∘ f) s'
diff_l : ContMDiffOn I I n (↑(PartialHomeomorph.symm l)) s'l
diff_rfl : ContMDiffOn I I' n (↑r ∘ f ∘ ↑(PartialHomeomorph.symm l)) s'l
diff_rfl_lift :
  ContMDiffOn (ModelWithCorners.tangent I) (ModelWithCorners.tangent I') m
    (tangentMapWithin I I' (↑r ∘ f ∘ ↑(PartialHomeomorph.symm l)) s'l) s'l_lift
diff_irrfl_lift :
  ContMDiffOn (ModelWithCorners.tangent I) (ModelWithCorners.tangent I') m
    (↑ir ∘ tangentMapWithin I I' (↑r ∘ f ∘ ↑(PartialHomeomorph.symm l)) s'l) s'l_lift
diff_Drirrfl_lift :
  ContMDiffOn (ModelWithCorners.tangent I) (ModelWithCorners.tangent I') m
    (↑(PartialHomeomorph.symm Dr) ∘ ↑ir ∘ tangentMapWithin I I' (↑r ∘ f ∘ ↑(PartialHomeomorph.symm l)) s'l) s'l_lift
diff_DrirrflilDl :
  ContMDiffOn (ModelWithCorners.tangent I) (ModelWithCorners.tangent I') m
    (↑(PartialHomeomorph.symm Dr) ∘
      (↑ir ∘ tangentMapWithin I I' (↑r ∘ f ∘ ↑(PartialHomeomorph.symm l)) s'l) ∘ ↑(PartialHomeomorph.symm il) ∘ ↑Dl)
    s'_lift
q : TotalSpace E (TangentSpace I)
hq :
  (f q.proj ∈ (chartAt H' (f p.proj)).toPartialEquiv.source ∧ q.proj ∈ s) ∧
    q.proj ∈ (chartAt H p.proj).toPartialEquiv.source
U'q : UniqueMDiffWithinAt I s' q.proj
U'lq : UniqueMDiffWithinAt I s'l (↑Dl q).1
A✝ :
  tangentMapWithin I I' ((↑r ∘ f) ∘ ↑(PartialHomeomorph.symm l)) s'l (↑(PartialHomeomorph.symm il) (↑Dl q)) =
    tangentMapWithin I I' (↑r ∘ f) s'
      (tangentMapWithin I I (↑(PartialHomeomorph.symm l)) s'l (↑(PartialHomeomorph.symm il) (↑Dl q)))
B : tangentMapWithin I I (↑(PartialHomeomorph.symm l)) s'l (↑(PartialHomeomorph.symm il) (↑Dl q)) = q
C : tangentMapWithin I I' (↑r ∘ f) s' q = tangentMapWithin I' I' (↑r) r.source (tangentMapWithin I I' f s' q)
A :
  tangentMapWithin I' I' (↑r) r.source (tangentMapWithin I I' f s' q) =
    tangentMap I' I' (↑r) (tangentMapWithin I I' f s' q)
this : f p.proj = (tangentMapWithin I I' f s p).proj
⊢ ↑(PartialHomeomorph.symm (chartAt (ModelProd H' E') (tangentMapWithin I I' f s p)))
      (↑(chartAt H' (f p.proj)) (f q.proj),
        (↑(chartAt (ModelProd H' E') (tangentMapWithin I I' f s p))
            (tangentMapWithin I I' f
              (f ⁻¹' (chartAt H' (f p.proj)).toPartialEquiv.source ∩ s ∩ (chartAt H p.proj).toPartialEquiv.source)
              q)).2) =
    tangentMapWithin I I' f
      (f ⁻¹' (chartAt H' (f p.proj)).toPartialEquiv.source ∩ s ∩ (chartAt H p.proj).toPartialEquiv.source) q

Next tactic:
have :
          tangentMapWithin I I' f s' q ∈
            (chartAt (ModelProd H' E') (tangentMapWithin I I' f s p)).source :=
          by simp only [hq, mfld_simps]