import Mathlib.RingTheory.Polynomial.Basic
import Mathlib.FieldTheory.PerfectClosure
import Mathlib.Algebra.CharP.Two
import Goppadecoding.nat
import Goppadecoding.sq
import Goppadecoding.diff

open Polynomial

namespace Goppadecoding

section lemmas_char2

theorem zero_in_char_2_if_even {k: Type _} [Field k] [CharP k 2] (n: ℕ)
  (even: Even n): (n:k) = 0 :=
by
  rw[even_iff_exists_two_mul] at even
  cases even with | intro c nc =>
    simp only [nc, Nat.cast_mul, Nat.cast_ofNat, CharTwo.two_eq_zero, zero_mul]

theorem one_in_char_2_if_not_even {k: Type _} [Field k] [CharP k 2] (n: ℕ)
  (odd: ¬Even n): (n:k) = 1 :=
by
  rw[Nat.even_iff_not_odd] at odd
  simp only[not_not] at odd
  rw[odd_iff_exists_bit1] at odd
  unfold bit1 at odd
  unfold bit0 at odd
  cases odd with | intro c nc =>
    simp only [nc, Nat.cast_add, CharTwo.add_self_eq_zero, Nat.cast_one, zero_add]

theorem derivative_is_square {k: Type _} [Field k] [CharP k 2] [PerfectRing k 2] (h: k[X]):
  ∃ q, h.diff = q^2 :=
by
  rw[diff]
  simp
  rw[derivative_apply]
  use sum h fun n a => if Odd n then C (pthRoot k 2 a) * X^((n-1)/2) else 0
  unfold Polynomial.sum
  rw[CharTwo.sum_sq]
  apply Finset.sum_congr
  simp only
  intro n _
  by_cases nparity: Even n
  . simp only [nparity, zero_in_char_2_if_even, mul_zero, map_zero, ge_iff_le, zero_mul, Nat.odd_iff_not_even, not_true, ite_false, ne_eq, zero_pow']
  have n1: (n:k) = 1 := by apply one_in_char_2_if_not_even n nparity
  simp only [n1, mul_one, ge_iff_le, Nat.odd_iff_not_even, nparity, not_false_eq_true, ite_true]
  rw[mul_sq,←pow_mul,sq,←C_mul,←sq]
  simp only [ge_iff_le, pthRoot_pow_p, mul_eq_mul_left_iff, _root_.map_eq_zero]
  left
  congr
  exact (half_times_2_eq_not_even_1 n nparity).symm

theorem squarefree_dvd_derivative {k: Type _} [Field k] [CharP k 2] [PerfectRing k 2] {g h: k[X]}
  (sqfree: Squarefree g) (gh: g ∣ h.diff): g^2 ∣ h.diff :=
by
  cases derivative_is_square h with | intro q hq2 =>
    rw[hq2] at gh
    rw[hq2]
    exact squarefree_dvd_square_2 g q sqfree gh

end lemmas_char2
