-- ArkLib/ToMathlib/MvPolynomial/Equiv.lean

import Mathlib.Algebra.MvPolynomial.Equiv

import ArkLib.ToMathlib.Finsupp.Fin

namespace MvPolynomial

open Function Finsupp Polynomial

noncomputable section

section FinSuccEquivNth

variable {n : ℕ} {σ : Type*} (R : Type*) [CommSemiring R] (p : Fin (n + 1))

def finSuccEquivNth : MvPolynomial (Fin (n + 1)) R ≃ₐ[R] Polynomial (MvPolynomial (Fin n) R) :=
  (renameEquiv R (_root_.finSuccEquiv' p)).trans (optionEquivLeft R (Fin n))

variable {R} {p}

-- Repository definitions used:
content: def insertNth (p : Fin (n + 1)) (y : M) (s : Fin n →₀ M) : Fin (n + 1) →₀ M :=
  Finsupp.equivFunOnFinite.symm (Fin.insertNth p y s : Fin (n + 1) → M)

content: def removeNth (p : Fin (n + 1)) (s : Fin (n + 1) →₀ M) : Fin n →₀ M :=
  Finsupp.equivFunOnFinite.symm (Fin.removeNth p s : Fin n → M)

-- Repository lemmas used:
content: theorem insertNth_self_removeNth : insertNth p (t p) (removeNth p t) = t

content: @[simp]
theorem insertNth_apply_succAbove : insertNth p y s (p.succAbove i) = s i

content: @[simp]
theorem removeNth_apply : removeNth p s i = s (p.succAbove i)

content: @[simp]
theorem insertNth_apply_same : insertNth p y s p = y

-- Local definitions used:
content: def finSuccEquivNth : MvPolynomial (Fin (n + 1)) R ≃ₐ[R] Polynomial (MvPolynomial (Fin n) R) :=
  (renameEquiv R (_root_.finSuccEquiv' p)).trans (optionEquivLeft R (Fin n))

-- Local lemmas used:
content: theorem finSuccEquivNth_eq :
    (finSuccEquivNth R p : MvPolynomial (Fin (n + 1)) R →+* Polynomial (MvPolynomial (Fin n) R)) =
      eval₂Hom (Polynomial.C.comp (C : R →+* MvPolynomial (Fin n) R))
        (Fin.insertNth p Polynomial.X (Polynomial.C ∘ X))

content: theorem finSuccEquivNth_apply (f : MvPolynomial (Fin (n + 1)) R) :
    finSuccEquivNth R p f =
      eval₂Hom (Polynomial.C.comp (C : R →+* MvPolynomial (Fin n) R))
        (Fin.insertNth p Polynomial.X (Polynomial.C ∘ X)) f

-- Target theorem and proof:
theorem finSuccEquivNth_coeff_coeff (m : Fin n →₀ ℕ) (f : MvPolynomial (Fin (n + 1)) R) (i : ℕ) :
    coeff m (Polynomial.coeff (finSuccEquivNth R p f) i) = coeff (m.insertNth p i) f
:= by
  induction' f using MvPolynomial.induction_on' with u a p q hp hq generalizing i m
  · simp only [finSuccEquivNth_apply, coe_eval₂Hom, eval₂_monomial, RingHom.coe_comp, comp_apply,
      prod_pow, Fin.prod_univ_succAbove _ p, Fin.insertNth_apply_same,
      Fin.insertNth_apply_succAbove, Polynomial.coeff_C_mul, coeff_C_mul, coeff_monomial,
      ← map_prod, ← RingHom.map_pow]
    rw [← mul_boole, mul_comm (Polynomial.X ^ u p), Polynomial.coeff_C_mul_X_pow]; congr 1
    obtain rfl | hjmi := eq_or_ne u (m.insertNth p i)
    · simpa only [insertNth_apply_same, if_pos rfl, insertNth_apply_succAbove, monomial_eq, C_1,
        one_mul, prod_pow] using coeff_monomial m m (1 : R)
    · simp only [hjmi, if_false]
      obtain hij | rfl := ne_or_eq i (u p)
      · simp only [hij, if_false, coeff_zero]
      simp only [eq_self_iff_true, if_true]
      have hmj : m ≠ u.removeNth p := by
        rintro rfl
        rw [insertNth_self_removeNth] at hjmi
        contradiction
      simpa only [monomial_eq, C_1, one_mul, prod_pow, Finsupp.removeNth_apply, if_neg hmj.symm]
        using coeff_monomial m (u.removeNth p) (1 : R)
  · simp only [map_add, Polynomial.coeff_add, coeff_add, hp, hq]