/-- The Riemann zeta function is differentiable away from `s = 1`. -/
theorem differentiableAt_riemannZeta {s : ℂ} (hs' : s ≠ 1) : DifferentiableAt ℂ riemannZeta s := by
  /- First claim: the result holds at `t` for `t ≠ 0`. Note we will need to use this for the case
    `s = 0` also, as a hypothesis for the removable-singularity criterion. -/
  have c1 : ∀ (t : ℂ) (_ : t ≠ 0) (_ : t ≠ 1),
      DifferentiableAt ℂ
        (fun u : ℂ => (π : ℂ) ^ (u / 2) * riemannCompletedZeta u / Gamma (u / 2)) t := by
    intro t ht ht'
    apply DifferentiableAt.mul
    · refine (DifferentiableAt.const_cpow ?_ ?_).mul (differentiableAt_completed_zeta ht ht')
      · exact DifferentiableAt.div_const differentiableAt_id _
      · exact Or.inl (ofReal_ne_zero.mpr pi_pos.ne')
    · refine differentiable_one_div_Gamma.differentiableAt.comp t ?_
      exact DifferentiableAt.div_const differentiableAt_id _
  -- Second claim: the limit at `s = 0` exists and is equal to `-1 / 2`.
  have c2 : Tendsto (fun s : ℂ => (π : ℂ) ^ (s / 2) * riemannCompletedZeta s / Gamma (s / 2))
      (𝓝[≠] 0) (𝓝 <| -1 / 2) := by
    have h1 : Tendsto (fun z : ℂ => (π : ℂ) ^ (z / 2)) (𝓝 0) (𝓝 1) := by
      convert (ContinuousAt.comp (f := fun z => z/2)
        (continuousAt_const_cpow (ofReal_ne_zero.mpr pi_pos.ne')) ?_).tendsto using 2
      · simp_rw [Function.comp_apply, zero_div, cpow_zero]
      · exact continuousAt_id.div continuousAt_const two_ne_zero
    suffices h2 : Tendsto (fun z => riemannCompletedZeta z / Gamma (z / 2)) (𝓝[≠] 0) (𝓝 <| -1 / 2)
    · convert (h1.mono_left nhdsWithin_le_nhds).mul h2 using 1
      · ext1 x; rw [mul_div]
      · simp only [one_mul]
    suffices h3 :
      Tendsto (fun z => riemannCompletedZeta z * (z / 2) / (z / 2 * Gamma (z / 2))) (𝓝[≠] 0)
        (𝓝 <| -1 / 2)
    · refine Tendsto.congr' (eventuallyEq_of_mem self_mem_nhdsWithin fun z hz => ?_) h3
      rw [← div_div, mul_div_cancel _ (div_ne_zero hz two_ne_zero)]
    have h4 : Tendsto (fun z : ℂ => z / 2 * Gamma (z / 2)) (𝓝[≠] 0) (𝓝 1) := by
      refine tendsto_self_mul_Gamma_nhds_zero.comp ?_
      rw [tendsto_nhdsWithin_iff, (by simp : 𝓝 (0 : ℂ) = 𝓝 (0 / 2))]
      exact
        ⟨(tendsto_id.div_const _).mono_left nhdsWithin_le_nhds,
          eventually_of_mem self_mem_nhdsWithin fun x hx => div_ne_zero hx two_ne_zero⟩
    suffices Tendsto (fun z => riemannCompletedZeta z * z / 2) (𝓝[≠] 0) (𝓝 (-1 / 2 : ℂ)) by
      have := this.div h4 one_ne_zero
      simp_rw [div_one, mul_div_assoc] at this
      exact this
    refine Tendsto.div ?_ tendsto_const_nhds two_ne_zero
    simp_rw [riemannCompletedZeta, add_mul, sub_mul]
    rw [show 𝓝 (-1 : ℂ) = 𝓝 (0 - 1 + 0) by rw [zero_sub, add_zero]]
    refine (Tendsto.sub ?_ ?_).add ?_
    · refine Tendsto.mono_left ?_ nhdsWithin_le_nhds
      have : ContinuousAt riemannCompletedZeta₀ 0 :=
        differentiable_completed_zeta₀.continuous.continuousAt
      simpa only [id.def, mul_zero] using Tendsto.mul this tendsto_id
    · refine tendsto_const_nhds.congr' (eventuallyEq_of_mem self_mem_nhdsWithin fun t ht => ?_)
      simp_rw [one_div_mul_cancel ht]
    · refine Tendsto.mono_left ?_ nhdsWithin_le_nhds
      suffices ContinuousAt (fun z : ℂ => 1 / (z - 1)) 0 by
        simpa only [id.def, mul_zero] using Tendsto.mul this tendsto_id
      refine continuousAt_const.div (continuousAt_id.sub continuousAt_const) ?_
      simpa only [zero_sub] using neg_ne_zero.mpr one_ne_zero
  -- Now the main proof.
  rcases ne_or_eq s 0 with (hs | rfl)
  · -- The easy case: `s ≠ 0`
    have : {(0 : ℂ)}ᶜ ∈ 𝓝 s := isOpen_compl_singleton.mem_nhds hs
    refine (c1 s hs hs').congr_of_eventuallyEq (eventuallyEq_of_mem this fun x hx => ?_)
    rw [riemannZeta_def]
    apply Function.update_noteq hx
  · -- The hard case: `s = 0`.
    rw [riemannZeta, ← (lim_eq_iff ⟨-1 / 2, c2⟩).mpr c2]
    

Proof state:
case inr
c1 :
  ∀ (t : ℂ),
    t ≠ 0 → t ≠ 1 → DifferentiableAt ℂ (fun u => ↑π ^ (u / 2) * riemannCompletedZeta u / Complex.Gamma (u / 2)) t
c2 : Tendsto (fun s => ↑π ^ (s / 2) * riemannCompletedZeta s / Complex.Gamma (s / 2)) (𝓝[≠] 0) (𝓝 (-1 / 2))
hs' : 0 ≠ 1
⊢ DifferentiableAt ℂ
    (Function.update (fun s => ↑π ^ (s / 2) * riemannCompletedZeta s / Complex.Gamma (s / 2)) 0
      (lim (map (fun s => ↑π ^ (s / 2) * riemannCompletedZeta s / Complex.Gamma (s / 2)) (𝓝[≠] 0))))
    0

Next tactic:
have S_nhds : {(1 : ℂ)}ᶜ ∈ 𝓝 (0 : ℂ) := isOpen_compl_singleton.mem_nhds hs'