import Nevanlinna.stronglyMeromorphicAt
import Mathlib.Algebra.BigOperators.Finprod

open Topology


/- Strongly MeromorphicOn -/
def StronglyMeromorphicOn
  (f : ℂ → ℂ)
  (U : Set ℂ) :=
  ∀ z ∈ U, StronglyMeromorphicAt f z


/- Strongly MeromorphicAt is Meromorphic -/
theorem StronglyMeromorphicOn.meromorphicOn
  {f : ℂ → ℂ}
  {U : Set ℂ}
  (hf : StronglyMeromorphicOn f U) :
  MeromorphicOn f U := by
  intro z hz
  exact StronglyMeromorphicAt.meromorphicAt (hf z hz)


/- Strongly MeromorphicOn of non-negative order is analytic -/
theorem StronglyMeromorphicOn.analytic
  {f : ℂ → ℂ}
  {U : Set ℂ}
  (h₁f : StronglyMeromorphicOn f U)
  (h₂f : ∀ x, (hx : x ∈ U) → 0 ≤ (h₁f x hx).meromorphicAt.order) :
  AnalyticOnNhd ℂ f U := by
  intro z hz
  apply StronglyMeromorphicAt.analytic
  exact h₂f z hz
  exact h₁f z hz


/- Analytic functions are strongly meromorphic -/
theorem AnalyticOn.stronglyMeromorphicOn
  {f : ℂ → ℂ}
  {U : Set ℂ}
  (h₁f : AnalyticOnNhd ℂ f U) :
  StronglyMeromorphicOn f U := by
  intro z hz
  apply AnalyticAt.stronglyMeromorphicAt
  exact h₁f z hz


/- Make strongly MeromorphicOn -/
noncomputable def MeromorphicOn.makeStronglyMeromorphicOn
  {f : ℂ → ℂ}
  {U : Set ℂ}
  (hf : MeromorphicOn f U) :
  ℂ → ℂ := by
  intro z
  by_cases hz : z ∈ U
  · exact (hf z hz).makeStronglyMeromorphicAt z
  · exact f z


theorem makeStronglyMeromorphicOn_changeDiscrete
  {f : ℂ → ℂ}
  {U : Set ℂ}
  {z₀ : ℂ}
  (hf : MeromorphicOn f U)
  (hz₀ : z₀ ∈ U) :
  hf.makeStronglyMeromorphicOn =ᶠ[𝓝[≠] z₀] f := by
  apply Filter.eventually_iff_exists_mem.2
  let A := (hf z₀ hz₀).eventually_analyticAt
  obtain ⟨V, h₁V, h₂V⟩  := Filter.eventually_iff_exists_mem.1 A
  use V
  constructor
  · assumption
  · intro v hv
    unfold MeromorphicOn.makeStronglyMeromorphicOn
    by_cases h₂v : v ∈ U
    · simp [h₂v]
      rw [← StronglyMeromorphicAt.makeStronglyMeromorphic_id]
      exact AnalyticAt.stronglyMeromorphicAt (h₂V v hv)
    · simp [h₂v]


theorem makeStronglyMeromorphicOn_changeDiscrete'
  {f : ℂ → ℂ}
  {U : Set ℂ}
  {z₀ : ℂ}
  (hf : MeromorphicOn f U)
  (hz₀ : z₀ ∈ U) :
  hf.makeStronglyMeromorphicOn =ᶠ[𝓝 z₀] (hf z₀ hz₀).makeStronglyMeromorphicAt := by
  apply Mnhds
  · apply Filter.EventuallyEq.trans (makeStronglyMeromorphicOn_changeDiscrete hf hz₀)
    exact m₂ (hf z₀ hz₀)
  · rw [MeromorphicOn.makeStronglyMeromorphicOn]
    simp [hz₀]


theorem stronglyMeromorphicOn_of_makeStronglyMeromorphicOn
  {f : ℂ → ℂ}
  {U : Set ℂ}
  (hf : MeromorphicOn f U) :
  StronglyMeromorphicOn hf.makeStronglyMeromorphicOn U := by
  intro z hz
  let A := makeStronglyMeromorphicOn_changeDiscrete' hf hz
  rw [stronglyMeromorphicAt_congr A]
  exact StronglyMeromorphicAt_of_makeStronglyMeromorphic (hf z hz)
