import Mathlib
import Definitions.Def_FLTPrelim_Ramification
import Definitions.Def_WeierstrassCurve_ReductionMap
import Definitions.Def_Deformations_ContinuousSMulDiscrete

set_option autoImplicit false
set_option backward.isDefEq.respectTransparency false

open IsLocalRing
open scoped Pointwise

section

variable {G M : Type*} [TopologicalSpace G] [SMul G M]

end

section

variable (R A : Type*) [CommRing R] [CommRing A] [Algebra R A]

def IntegralClosure : Type _ := integralClosure R A

instance : CommRing (IntegralClosure R A) := (integralClosure R A).toCommRing

instance : Algebra R (IntegralClosure R A) := (integralClosure R A).algebra

instance : Algebra (IntegralClosure R A) A := (integralClosure R A).toAlgebra

instance [IsDomain A] : IsDomain (IntegralClosure R A) := by
  delta IntegralClosure; infer_instance

instance : Algebra.IsIntegral R (IntegralClosure R A) := by
  delta IntegralClosure; infer_instance

instance : IsScalarTower R (IntegralClosure R A) A := (integralClosure R A).isScalarTower_mid

instance [FaithfulSMul R A] : FaithfulSMul R (IntegralClosure R A) := by
  refine (faithfulSMul_iff_algebraMap_injective _ _).mpr (.of_comp (f := algebraMap _ A) ?_)
  exact (FaithfulSMul.algebraMap_injective R A)

instance mulSemiringActionIntegralClosure
    {G R K : Type*} [CommRing R] [Field K] [Algebra R K] [Monoid G] [MulSemiringAction G K]
    [SMulCommClass G R K] :
    MulSemiringAction G (IntegralClosure R K) where
  smul σ x := ⟨σ • x.1, x.2.map (MulSemiringAction.toAlgHom R K σ)⟩
  one_smul _ := Subtype.ext (one_smul _ _)
  mul_smul _ _ _ := Subtype.ext (mul_smul _ _ _)
  smul_zero _ := Subtype.ext (smul_zero _)
  smul_add _ _ _ := Subtype.ext (smul_add _ _ _)
  smul_one _ := Subtype.ext (smul_one _)
  smul_mul _ _ _ := Subtype.ext (MulSemiringAction.smul_mul _ _ _)

instance smulCommClass_integralClosure
    {G R K : Type*} [CommRing R] [Field K] [Algebra R K] [Monoid G] [MulSemiringAction G K]
    [SMulCommClass G R K] :
    SMulCommClass G R (IntegralClosure R K) where
  smul_comm _ _ _ := Subtype.ext (smul_comm _ _ _)

lemma not_isField_integralClosure
    {K L : Type*} [Field K] [Field L] [Algebra K L] (R : ValuationSubring K) (hR : R ≠ ⊤) :
    ¬ IsField (IntegralClosure R L) := by
  have : FaithfulSMul K L := inferInstance
  contrapose! hR
  letI := hR.toField
  let F := IsFractionRing.liftAlgHom (K := K) (g := Algebra.ofId R (IntegralClosure R L))
    (FaithfulSMul.algebraMap_injective _ _)
  refine top_le_iff.mp fun x _ ↦ ?_
  have : IsIntegrallyClosed R := GCDMonoid.toIsIntegrallyClosed
  have := (isIntegral_algHom_iff F F.injective).mp (Algebra.IsIntegral.isIntegral (R := R) (F x))
  obtain ⟨x, rfl⟩ := (IsIntegralClosure.isIntegral_iff (A := R)).mp this
  exact x.2

instance isInvariant_integralClosure
    {G K L : Type*} [Field K] [Field L] [Algebra K L] [Group G] [MulSemiringAction G L]
    [SMulCommClass G K L] [Algebra.IsInvariant K L G] (R : ValuationSubring K) :
    Algebra.IsInvariant R (IntegralClosure R L) G where
  isInvariant := by
    rintro ⟨x, hx : IsIntegral _ _⟩ hx'
    obtain ⟨x, rfl⟩ := Algebra.IsInvariant.isInvariant (A := K) x fun g ↦ congr($(hx' g).1)
    rw [isIntegral_algebraMap_iff (algebraMap K L).injective] at hx
    have : IsIntegrallyClosed R := GCDMonoid.toIsIntegrallyClosed
    obtain ⟨x, rfl⟩ := (IsIntegralClosure.isIntegral_iff (A := R)).mp hx
    exact ⟨x, rfl⟩

instance continuousSMulDiscrete_integralClosure
    {G R L : Type*} [CommRing R] [Field L] [Algebra R L] [Group G] [MulSemiringAction G L]
    [SMulCommClass G R L] [TopologicalSpace G] [ContinuousSMulDiscrete G L] :
    ContinuousSMulDiscrete G (IntegralClosure R L) where
  isOpen_smul_eq x y := by
    simp only [IntegralClosure, Subtype.ext_iff]
    exact ContinuousSMulDiscrete.isOpen_smul_eq (G := G) x.1 y.1

instance {R S : Type*} [CommRing R] [CommRing S] {I : Ideal S} [Algebra R S]
    [Nontrivial R] [IsDomain S] [Algebra.IsIntegral R S] [NeZero I] : NeZero (I.under R) :=
  ⟨fun H ↦ NeZero.ne I (Ideal.eq_bot_of_comap_eq_bot H)⟩

end

namespace ValuationSubring

variable {L : Type*} [Field L]

variable (K : Type*) [Field K] [Algebra K L]

end ValuationSubring

namespace ValuationSubring

section Nonunits

variable {L : Type*} [Field L] (A : ValuationSubring L)

theorem mul_mem_nonunits_of_mem_of_mem_nonunits {x y : L} (hx : x ∈ A) (hy : y ∈ A.nonunits) :
    x * y ∈ A.nonunits := by
  rw [mem_nonunits_iff] at hy ⊢
  calc A.valuation (x * y) = A.valuation x * A.valuation y := Valuation.map_mul _ _ _
    _ ≤ 1 * A.valuation y := mul_le_mul_left ((valuation_le_one_iff A x).mpr hx) _
    _ = A.valuation y := one_mul _
    _ < 1 := hy

theorem one_notMem_nonunits_alt : (1 : L) ∉ A.nonunits := by
  rw [mem_nonunits_iff, Valuation.map_one]
  exact lt_irrefl 1

theorem neg_mem_nonunits {x : L} (hx : x ∈ A.nonunits) : -x ∈ A.nonunits := by
  rw [mem_nonunits_iff] at hx ⊢
  rwa [Valuation.map_neg]

theorem add_mem_nonunits {x y : L} (hx : x ∈ A.nonunits) (hy : y ∈ A.nonunits) :
    x + y ∈ A.nonunits := by
  rw [mem_nonunits_iff] at hx hy ⊢
  exact (A.valuation.map_add x y).trans_lt (max_lt hx hy)

theorem exists_mem_nonunits_of_multiset_prod_mem
    (s : Multiset L) (hs : ∀ x ∈ s, x ∈ A) (hprod : s.prod ∈ A.nonunits) :
    ∃ x ∈ s, x ∈ A.nonunits := by
  revert hs hprod
  induction s using Multiset.induction_on with
  | empty =>
    intro hs hprod
    rw [Multiset.prod_zero] at hprod
    exact absurd hprod (one_notMem_nonunits_alt A)
  | cons a s ih =>
    intro hs hprod
    rw [Multiset.prod_cons] at hprod
    by_cases ha : a ∈ A.nonunits
    · exact ⟨a, Multiset.mem_cons_self a s, ha⟩
    ·
      have hsA : ∀ x ∈ s, x ∈ A := fun x hx => hs x (Multiset.mem_cons_of_mem hx)
      have hva : (1 : _) ≤ A.valuation a := by
        rw [mem_nonunits_iff, not_lt] at ha
        exact ha
      have hprod' : s.prod ∈ A.nonunits := by
        rw [mem_nonunits_iff] at hprod ⊢
        calc A.valuation s.prod = 1 * A.valuation s.prod := (one_mul _).symm
          _ ≤ A.valuation a * A.valuation s.prod := mul_le_mul_left hva _
          _ = A.valuation (a * s.prod) := (Valuation.map_mul _ _ _).symm
          _ < 1 := hprod
      obtain ⟨x, hxs, hx⟩ := ih hsA hprod'
      exact ⟨x, Multiset.mem_cons_of_mem hxs, hx⟩

end Nonunits

variable {K L : Type*} [Field K] [Field L] [Algebra K L]

theorem smul_mem_iff_of_mem_decompositionSubgroup {A : ValuationSubring L} {σ : L ≃ₐ[K] L}
    (hσ : σ ∈ A.decompositionSubgroup K) {x : L} : σ x ∈ A ↔ x ∈ A := by
  have hσ' : σ⁻¹ • A = A := MulAction.mem_stabilizer_iff.mp ((A.decompositionSubgroup K).inv_mem hσ)
  calc σ x ∈ A ↔ σ • x ∈ A := Iff.rfl
    _ ↔ x ∈ σ⁻¹ • A := by
        rw [mem_pointwise_smul_iff_inv_smul_mem, inv_inv]
    _ ↔ x ∈ A := by rw [hσ']

theorem smul_mem_nonunits_iff_of_mem_decompositionSubgroup {A : ValuationSubring L}
    {σ : L ≃ₐ[K] L} (hσ : σ ∈ A.decompositionSubgroup K) {x : L} :
    σ x ∈ A.nonunits ↔ x ∈ A.nonunits := by
  have h1 : σ x = 0 ↔ x = 0 := by
    constructor
    · intro h; exact σ.injective (by simpa using h)
    · intro h; simp [h]
  have h2 : σ x⁻¹ ∈ A ↔ x⁻¹ ∈ A := smul_mem_iff_of_mem_decompositionSubgroup hσ
  rw [mem_nonunits_iff_or, mem_nonunits_iff_or, ← map_inv₀, h1, h2]

section SmulNonunits

variable {K L : Type*} [Field K] [Field L] [Algebra K L]

theorem mem_smul_nonunits_iff {τ : L ≃ₐ[K] L} {A : ValuationSubring L} {x : L} :
    x ∈ (τ • A).nonunits ↔ τ.symm x ∈ A.nonunits := by
  rw [mem_nonunits_iff_or, mem_nonunits_iff_or]
  constructor
  · rintro (h0 | hinv)
    · left
      rw [h0, map_zero]
    · by_cases hx0 : x = 0
      · left; rw [hx0, map_zero]
      right
      intro hmem
      apply hinv
      have : τ (τ.symm x)⁻¹ ∈ τ • A := by
        rw [mem_pointwise_smul_iff_inv_smul_mem]
        have h1 : (τ⁻¹ : L ≃ₐ[K] L) • τ (τ.symm x)⁻¹ = (τ.symm x)⁻¹ := by
          show τ.symm (τ (τ.symm x)⁻¹) = (τ.symm x)⁻¹
          exact τ.symm_apply_apply _
        rw [h1]
        exact hmem
      rwa [map_inv₀, τ.apply_symm_apply] at this
  · rintro (h0 | hinv)
    · left
      have := congrArg τ h0
      rwa [τ.apply_symm_apply, map_zero] at this
    · right
      intro hmem
      apply hinv
      rw [mem_pointwise_smul_iff_inv_smul_mem] at hmem
      have h1 : (τ⁻¹ : L ≃ₐ[K] L) • x⁻¹ = (τ.symm x)⁻¹ := by
        show τ.symm x⁻¹ = (τ.symm x)⁻¹
        exact map_inv₀ _ _
      rwa [h1] at hmem

end SmulNonunits

end ValuationSubring

namespace ValuationSubring

section RatArithmetic

variable {L : Type*} [Field L]

private lemma intCast_mem'' (A : ValuationSubring L) (n : ℤ) : ((n : ℤ) : L) ∈ A :=
  intCast_mem A.toSubring n

theorem intCast_notMem_nonunits_of_not_dvd {q : ℕ} (hq : q.Prime) {A : ValuationSubring L}
    (hA : A.LiesOverPrime q) {n : ℤ} (hn : ¬ (q : ℤ) ∣ n) : ((n : ℤ) : L) ∉ A.nonunits := by
  intro hmem

  have hqirr : Irreducible ((q : ℕ) : ℤ) := (Nat.prime_iff_prime_int.mp hq).irreducible
  obtain ⟨u, v, huv⟩ := hqirr.coprime_iff_not_dvd.mpr hn

  have h1 : (u : L) * ((q : ℕ) : L) + (v : L) * ((n : ℤ) : L) = 1 := by
    have h0 : ((u * (q : ℕ) + v * n : ℤ) : L) = ((1 : ℤ) : L) := by rw [huv]
    push_cast at h0
    exact h0

  apply one_notMem_nonunits_alt A
  rw [← h1]
  refine add_mem_nonunits A ?_ ?_
  · exact mul_mem_nonunits_of_mem_of_mem_nonunits A (intCast_mem'' A u) hA
  · exact mul_mem_nonunits_of_mem_of_mem_nonunits A (intCast_mem'' A v) hmem

theorem natCast_notMem_nonunits_of_not_dvd {q : ℕ} (hq : q.Prime) {A : ValuationSubring L}
    (hA : A.LiesOverPrime q) {n : ℕ} (hn : ¬ q ∣ n) : ((n : ℕ) : L) ∉ A.nonunits := by
  have h := intCast_notMem_nonunits_of_not_dvd hq hA (n := (n : ℤ))
    (fun hd => hn (by exact_mod_cast hd))
  rwa [Int.cast_natCast] at h

variable [Algebra ℚ L]

theorem algebraMap_rat_mem_of_not_dvd_den {q : ℕ} (hq : q.Prime) {A : ValuationSubring L}
    (hA : A.LiesOverPrime q) {r : ℚ} (hden : ¬ q ∣ r.den) :
    algebraMap ℚ L r ∈ A := by

  have hd1 : ((r.den : ℕ) : L) ∉ A.nonunits := natCast_notMem_nonunits_of_not_dvd hq hA hden
  have hdinv : (((r.den : ℕ) : L))⁻¹ ∈ A := by
    by_contra hinv
    exact hd1 (A.mem_nonunits_iff_or.mpr (Or.inr hinv))

  have hr : algebraMap ℚ L r = ((r.num : ℤ) : L) * (((r.den : ℕ) : L))⁻¹ := by
    conv_lhs => rw [← Rat.num_div_den r]
    rw [map_div₀, div_eq_mul_inv, map_intCast, map_natCast]
  rw [hr]
  exact MulMemClass.mul_mem (intCast_mem'' A r.num) hdinv

theorem algebraMap_rat_mem_nonunits_of_dvd_num {q : ℕ} (hq : q.Prime) {A : ValuationSubring L}
    (hA : A.LiesOverPrime q) {r : ℚ} (hden : ¬ q ∣ r.den) (hnum : (q : ℤ) ∣ r.num) :
    algebraMap ℚ L r ∈ A.nonunits := by
  obtain ⟨m, hm⟩ := hnum
  have hd1 : ((r.den : ℕ) : L) ∉ A.nonunits := natCast_notMem_nonunits_of_not_dvd hq hA hden
  have hdinv : (((r.den : ℕ) : L))⁻¹ ∈ A := by
    by_contra hinv
    exact hd1 (A.mem_nonunits_iff_or.mpr (Or.inr hinv))

  have hr : algebraMap ℚ L r = (((m : ℤ) : L) * (((r.den : ℕ) : L))⁻¹) * ((q : ℕ) : L) := by
    conv_lhs => rw [← Rat.num_div_den r]
    rw [map_div₀, div_eq_mul_inv, map_intCast, map_natCast, hm]
    push_cast
    ring
  rw [hr]
  exact mul_mem_nonunits_of_mem_of_mem_nonunits A
    (MulMemClass.mul_mem (intCast_mem'' A m) hdinv) hA

end RatArithmetic

section RatPlace

variable {q : ℕ} (hq : q.Prime) {R₀ : ValuationSubring ℚ} (hR₀ : R₀.LiesOverPrime q)

include hq hR₀ in

theorem not_dvd_den_of_mem {r : ℚ} (hr : r ∈ R₀) : ¬ q ∣ r.den := by
  intro hdvd

  have hnum : ¬ (q : ℤ) ∣ r.num := by
    intro hdvd'
    have h1 : q ∣ r.num.natAbs := by
      have := Int.natAbs_dvd_natAbs.mpr hdvd'
      simpa using this
    have h2 := Nat.dvd_gcd h1 hdvd
    have h4 : Nat.gcd r.num.natAbs r.den = 1 := r.reduced
    rw [h4] at h2
    exact hq.one_lt.ne' (Nat.dvd_one.mp h2)

  have hnotmem : ((r.num : ℤ) : ℚ) ∉ R₀.nonunits :=
    intCast_notMem_nonunits_of_not_dvd hq hR₀ hnum

  obtain ⟨c, hc⟩ := hdvd
  have hden0 : ((r.den : ℕ) : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr r.den_nz
  have hrden : ((r.num : ℤ) : ℚ) = (r * (c : ℕ)) * ((q : ℕ) : ℚ) := by
    have h4 : ((r.num : ℤ) : ℚ) = r * ((r.den : ℕ) : ℚ) :=
      (div_eq_iff hden0).mp (Rat.num_div_den r)
    rw [h4, hc]
    push_cast
    ring
  apply hnotmem
  rw [hrden]
  exact mul_mem_nonunits_of_mem_of_mem_nonunits R₀
    (MulMemClass.mul_mem hr (natCast_mem' R₀ c)) hR₀

include hq hR₀ in

theorem dvd_num_of_mem_nonunits {r : ℚ} (hr : r ∈ R₀.nonunits) : (q : ℤ) ∣ r.num := by
  by_contra hnum

  have hnum0 : r.num ≠ 0 := by
    intro h0
    exact hnum (h0 ▸ dvd_zero _)
  have hnotmem : ((r.num : ℤ) : ℚ) ∉ R₀.nonunits :=
    intCast_notMem_nonunits_of_not_dvd hq hR₀ hnum
  have hninv : (((r.num : ℤ) : ℚ))⁻¹ ∈ R₀ := by
    by_contra hinv
    exact hnotmem (R₀.mem_nonunits_iff_or.mpr (Or.inr hinv))

  have hrinv : r⁻¹ = ((r.den : ℕ) : ℚ) * (((r.num : ℤ) : ℚ))⁻¹ := by
    conv_lhs => rw [← Rat.num_div_den r]
    rw [inv_div, div_eq_mul_inv]
  rcases (R₀.mem_nonunits_iff_or).mp hr with h0 | hinv
  · exact hnum0 (Rat.num_eq_zero.mpr h0)
  · exact hinv (hrinv ▸ MulMemClass.mul_mem (natCast_mem' R₀ r.den) hninv)

variable {L : Type*} [Field L] [Algebra ℚ L]
variable {A : ValuationSubring L} (hA : A.LiesOverPrime q)

include hq hR₀ hA in

theorem algebraMap_rat_mem_of_mem {r : ℚ} (hr : r ∈ R₀) : algebraMap ℚ L r ∈ A :=
  algebraMap_rat_mem_of_not_dvd_den hq hA (not_dvd_den_of_mem hq hR₀ hr)

include hq hR₀ hA in

theorem algebraMap_rat_mem_nonunits_of_mem_nonunits {r : ℚ} (hr : r ∈ R₀.nonunits) :
    algebraMap ℚ L r ∈ A.nonunits :=
  algebraMap_rat_mem_nonunits_of_dvd_num hq hA
    (not_dvd_den_of_mem hq hR₀ (R₀.nonunits_subset hr)) (dvd_num_of_mem_nonunits hq hR₀ hr)

include hq hR₀ hA in

theorem mem_nonunits_of_algebraMap_mem_nonunits {r : ℚ}
    (h : algebraMap ℚ L r ∈ A.nonunits) : r ∈ R₀.nonunits := by
  by_contra hnot

  have hr0 : r ≠ 0 := by
    intro h0
    exact hnot (R₀.mem_nonunits_iff_or.mpr (Or.inl h0))
  have hrinv : r⁻¹ ∈ R₀ := by
    by_contra hinv
    exact hnot (R₀.mem_nonunits_iff_or.mpr (Or.inr hinv))
  rcases (A.mem_nonunits_iff_or).mp h with h0 | hinv
  · exact hr0 ((map_eq_zero _).mp h0)
  · exact hinv (by
      rw [← map_inv₀]
      exact algebraMap_rat_mem_of_mem hq hR₀ hA hrinv)

end RatPlace

section IntegralClosureMem

variable {L : Type*} [Field L] [Algebra ℚ L]

set_option maxHeartbeats 400000 in

theorem algebraMap_integralClosure_mem {q : ℕ} (hq : q.Prime)
    {R₀ : ValuationSubring ℚ} (hR₀ : R₀.LiesOverPrime q)
    {A : ValuationSubring L} (hA : A.LiesOverPrime q) (b : IntegralClosure R₀ L) :
    algebraMap (IntegralClosure R₀ L) L b ∈ A := by

  let f : R₀ →+* A :=
    { toFun := fun r => ⟨algebraMap ℚ L (r : ℚ), algebraMap_rat_mem_of_mem hq hR₀ hA r.2⟩
      map_one' := Subtype.ext (by simp)
      map_mul' := fun x y => Subtype.ext (by push_cast; simp)
      map_zero' := Subtype.ext (by simp)
      map_add' := fun x y => Subtype.ext (by push_cast; simp) }
  letI : Algebra R₀ A := f.toAlgebra
  haveI : IsScalarTower R₀ A L := IsScalarTower.of_algebraMap_eq fun r => rfl

  have hint : IsIntegral R₀ (algebraMap (IntegralClosure R₀ L) L b) := by
    have h0 := (Algebra.IsIntegral.isIntegral (R := R₀) b).map
      (IsScalarTower.toAlgHom R₀ (IntegralClosure R₀ L) L)
    rwa [IsScalarTower.toAlgHom_apply] at h0
  have hintA : IsIntegral A (algebraMap (IntegralClosure R₀ L) L b) := hint.tower_top
  obtain ⟨a, ha⟩ := IsIntegrallyClosed.isIntegral_iff.mp hintA
  exact ha ▸ a.2

end IntegralClosureMem

section PlaceCenter

variable {L : Type*} [Field L] [Algebra ℚ L] {R₀ : ValuationSubring ℚ}

def placeCenter (A : ValuationSubring L)
    (hBA : ∀ b : IntegralClosure R₀ L, algebraMap (IntegralClosure R₀ L) L b ∈ A) :
    Ideal (IntegralClosure R₀ L) where
  carrier := {b | algebraMap (IntegralClosure R₀ L) L b ∈ A.nonunits}
  add_mem' := fun ha hb => by
    simpa only [Set.mem_setOf_eq, map_add] using add_mem_nonunits A ha hb
  zero_mem' := by
    simpa only [Set.mem_setOf_eq, map_zero] using (A.mem_nonunits_iff_or.mpr (Or.inl rfl))
  smul_mem' := fun c x hx => by
    simpa only [Set.mem_setOf_eq, smul_eq_mul, map_mul] using
      mul_mem_nonunits_of_mem_of_mem_nonunits A (hBA c) hx

theorem mem_placeCenter_iff {A : ValuationSubring L}
    {hBA : ∀ b : IntegralClosure R₀ L, algebraMap (IntegralClosure R₀ L) L b ∈ A}
    {b : IntegralClosure R₀ L} :
    b ∈ placeCenter A hBA ↔ algebraMap (IntegralClosure R₀ L) L b ∈ A.nonunits :=
  Iff.rfl

theorem placeCenter_isPrime (A : ValuationSubring L)
    (hBA : ∀ b : IntegralClosure R₀ L, algebraMap (IntegralClosure R₀ L) L b ∈ A) :
    (placeCenter A hBA).IsPrime := by
  rw [Ideal.isPrime_iff]
  constructor
  · intro htop
    have h1 : (1 : IntegralClosure R₀ L) ∈ placeCenter A hBA := htop ▸ Submodule.mem_top
    rw [mem_placeCenter_iff, map_one] at h1
    exact one_notMem_nonunits_alt A h1
  · intro a b hab
    rw [mem_placeCenter_iff, map_mul] at hab
    rw [mem_placeCenter_iff, mem_placeCenter_iff]
    by_contra hcon
    rw [not_or] at hcon
    obtain ⟨ha, hb⟩ := hcon
    have ha0 : algebraMap (IntegralClosure R₀ L) L a ≠ 0 := fun h =>
      ha (A.mem_nonunits_iff_or.mpr (Or.inl h))
    have hb0 : algebraMap (IntegralClosure R₀ L) L b ≠ 0 := fun h =>
      hb (A.mem_nonunits_iff_or.mpr (Or.inl h))
    have hainv : (algebraMap (IntegralClosure R₀ L) L a)⁻¹ ∈ A := by
      by_contra h
      exact ha (A.mem_nonunits_iff_or.mpr (Or.inr h))
    have hbinv : (algebraMap (IntegralClosure R₀ L) L b)⁻¹ ∈ A := by
      by_contra h
      exact hb (A.mem_nonunits_iff_or.mpr (Or.inr h))
    rcases (A.mem_nonunits_iff_or).mp hab with h0 | hinv
    · exact mul_ne_zero ha0 hb0 h0
    · exact hinv (by rw [mul_inv]; exact MulMemClass.mul_mem hainv hbinv)

theorem placeCenter_under {q : ℕ} (hq : q.Prime) (hR₀ : R₀.LiesOverPrime q)
    {A : ValuationSubring L} (hA : A.LiesOverPrime q)
    (hBA : ∀ b : IntegralClosure R₀ L, algebraMap (IntegralClosure R₀ L) L b ∈ A) :
    (placeCenter A hBA).under R₀ = IsLocalRing.maximalIdeal R₀ := by
  ext r
  rw [Ideal.under_def, Ideal.mem_comap, mem_placeCenter_iff]
  have hco : algebraMap (IntegralClosure R₀ L) L (algebraMap R₀ (IntegralClosure R₀ L) r)
      = algebraMap ℚ L (r : ℚ) := by
    rw [← IsScalarTower.algebraMap_apply R₀ (IntegralClosure R₀ L) L]
    rfl
  rw [hco]
  constructor
  · intro h
    exact (R₀.coe_mem_nonunits_iff).mp
      (mem_nonunits_of_algebraMap_mem_nonunits hq hR₀ hA h)
  · intro h
    exact algebraMap_rat_mem_nonunits_of_mem_nonunits hq hR₀ hA
      ((R₀.coe_mem_nonunits_iff).mpr h)

end PlaceCenter

end ValuationSubring

open Polynomial

namespace ValuationSubring

section ResidueFieldRat

variable {q : ℕ} (hq : q.Prime) {R₀ : ValuationSubring ℚ} (hR₀ : R₀.LiesOverPrime q)

include hq hR₀ in

theorem exists_intCast_residue_eq (x : ResidueField R₀) :
    ∃ n : ℤ, residue R₀ (n : R₀) = x := by
  obtain ⟨r, rfl⟩ := residue_surjective x

  have hden : ¬ q ∣ (r : ℚ).den := not_dvd_den_of_mem hq hR₀ r.2

  have hcop : IsCoprime ((r : ℚ).den : ℤ) ((q : ℕ) : ℤ) := by
    refine Nat.Coprime.isCoprime ?_
    exact (Nat.Prime.coprime_iff_not_dvd hq |>.mpr hden).symm
  obtain ⟨c, d, hcd⟩ := hcop
  refine ⟨c * (r : ℚ).num, ?_⟩

  have hmem : r - ((c * (r : ℚ).num : ℤ) : R₀) ∈ IsLocalRing.maximalIdeal R₀ := by
    rw [← coe_mem_nonunits_iff]
    have hden0 : (((r : ℚ).den : ℕ) : ℚ) ≠ 0 := Nat.cast_ne_zero.mpr (r : ℚ).den_nz
    have hnum : ((r : ℚ).num : ℚ) = (r : ℚ) * ((r : ℚ).den : ℚ) :=
      (div_eq_iff hden0).mp (Rat.num_div_den (r : ℚ))
    have hkey : ((r : R₀) : ℚ) - ((c * (r : ℚ).num : ℤ) : ℚ)
        = (r : ℚ) * (((d : ℚ)) * ((q : ℕ) : ℚ)) := by
      push_cast
      rw [hnum]
      have : (c : ℚ) * ((r : ℚ).den : ℚ) + (d : ℚ) * ((q : ℕ) : ℚ) = 1 := by
        exact_mod_cast congrArg (fun z : ℤ => (z : ℚ)) hcd
      linear_combination (-((r : R₀) : ℚ)) * this
    have hsub : ((r - ((c * (r : ℚ).num : ℤ) : R₀) : R₀) : ℚ)
        = ((r : R₀) : ℚ) - ((c * (r : ℚ).num : ℤ) : ℚ) := by
      push_cast
      ring
    rw [hsub, hkey]
    refine mul_mem_nonunits_of_mem_of_mem_nonunits R₀ r.2 ?_
    exact mul_mem_nonunits_of_mem_of_mem_nonunits R₀ (intCast_mem R₀.toSubring d) hR₀
  exact (Ideal.Quotient.eq.mpr hmem).symm

include hq hR₀ in

theorem residueField_finite_and_card :
    Finite (ResidueField R₀) ∧ Nat.card (ResidueField R₀) = q := by
  haveI : Fact q.Prime := ⟨hq⟩
  haveI : CharP (ResidueField R₀) q := charP_residueField_of_liesOverPrime_def hq hR₀

  set f : ZMod q →+* ResidueField R₀ := ZMod.castHom (dvd_refl q) (ResidueField R₀) with hf
  have hinj : Function.Injective f := f.injective
  have hsurj : Function.Surjective f := by
    intro x
    obtain ⟨n, hn⟩ := exists_intCast_residue_eq hq hR₀ x
    refine ⟨(n : ZMod q), ?_⟩
    rw [map_intCast]
    rw [← hn]
    have : ((n : ℤ) : ResidueField R₀) = residue R₀ ((n : ℤ) : R₀) := by
      simp
    exact this
  have hbij : Function.Bijective f := ⟨hinj, hsurj⟩
  haveI : Finite (ResidueField R₀) := Finite.of_surjective f hsurj
  refine ⟨inferInstance, ?_⟩
  rw [← Nat.card_congr (Equiv.ofBijective f hbij), Nat.card_zmod]

end ResidueFieldRat

end ValuationSubring
