{-# OPTIONS --cubical --no-import-sorts -WnoUnsupportedIndexedMatch --allow-unsolved-metas #-}
module AFF2024.Algebra.Basics where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Powerset
open import Cubical.HITs.PropositionalTruncation
open import Cubical.Data.Sigma
open import Cubical.Data.Nat hiding (_+_; _·_)
open import Cubical.Data.Vec hiding (map)
open import Cubical.Algebra.CommRing
open import Cubical.Algebra.CommAlgebra
open import Cubical.Algebra.Polynomials.UnivariateList.Base
open import Cubical.Algebra.CommAlgebra.UnivariatePolyList
open import Cubical.Algebra.CommRing.Instances.Polynomials.UnivariatePolyList
open import Cubical.Relation.Nullary.Base
open import Data.List hiding (map)
open import Data.List.Relation.Unary.All hiding (map)
open import Data.List.Relation.Unary.Any hiding (map)
open import Data.Fin hiding (_+_; _-_)

open import AFF2024.Basics

module _ { : Level} (R…@(R , Rstr) : CommRing ) where
  open CommRingStr Rstr

  CommRing→CommAlgebra : CommAlgebra R… 
  CommRing→CommAlgebra = commAlgebraFromCommRing R… _·_  x y z  sym (·Assoc x y z)) ·DistR+ ·DistL+ ·IdL λ x y z  sym (·Assoc x y z)

module _ { : Level} (R…@(R , Rstr) : CommRing ) where
  open CommRingStr Rstr

  MultivariatePoly… :   CommRing 
  MultivariatePoly… = nUnivariatePolyList R…

  MultivariatePoly :   Type 
  MultivariatePoly n = fst (MultivariatePoly… n)

  data MonicPolynomial : Type  where
    1p    : MonicPolynomial
    _+X*_ : R  MonicPolynomial  MonicPolynomial

  --X : MonicPolynomial
  --X = 0r +X* 1p

  evalM : MonicPolynomial  R  R
  evalM 1p        x = x
  evalM (a +X* f) x = a + x · evalM f x

  data HasPositiveDegree : MonicPolynomial  Type  where
    triv : {f : MonicPolynomial} {a : R}  HasPositiveDegree (a +X* f)

  IsAlgebraicallyClosed : Type 
  IsAlgebraicallyClosed = (f : MonicPolynomial)  HasPositiveDegree f  ∃[ x  R ] evalM f x  0r

module _ { : Level} {R…@(R , Rstr) : CommRing } where
  open CommRingStr Rstr

  eval : Poly R…  R  R
  eval f x = inducedMap R… (CommAlgebra→Algebra (CommRing→CommAlgebra R…)) x f

module _ { : Level} {R…@(R , Rstr) : CommRing } where
  open CommRingStr Rstr

  const : (n : )  R  MultivariatePoly R… n
  const zero    x = x
  const (suc n) x = const n x  []

  var : {n : }  Fin n  MultivariatePoly R… n
  var {suc n} zero = const n 1r  const n 0r  []
  var (suc n) = var n  []

  evalT : {n : }  MultivariatePoly R… n  Vec R n  R
  evalT {zero}  f xs       = f
  evalT {suc n} f (x  xs) = evalT (eval f (const n x)) xs

  evalT' : {n : }  MultivariatePoly R… (suc n)  Vec R n  Poly R…
  evalT' {zero}  f xs       = f
  evalT' {suc n} f (x  xs) = evalT' (eval f (const n x  [])) xs

module Apartness { : Level} (R…@(R , Rstr) : CommRing ) where
  open CommRingStr Rstr
  open Units R…

  _#_ : R  R  Type 
  x # y = (x - y)  

  IsRegular : R  Type 
  IsRegular x = (y : R)  x · y  0r  y  0r

  _##_ : R  R  Type 
  x ## y = IsRegular (x - y)

module _ { : Level} (R…@(R , Rstr) : CommRing ) where
  open CommRingStr Rstr
  open Units R…

  IsField : Type 
  IsField = (xs : List R)  ¬ (All (_≡ 0r) xs)   Any (_∈ ) xs ∥₁

  ≢→inv : IsField  (x : R)  x  0r  x  
  ≢→inv p x e = {!!}
  -- with p (x ∷ []) (λ { (q ∷ qs) → e q })
  -- ... | here px = px

module Degree { : Level} (R…@(R , Rstr) : CommRing ) where
  open CommRingStr Rstr

  0P : Poly R…
  0P = []

  data HasDegree≤ : Poly R…    Type  where
    base : {n : }  HasDegree≤ 0P n
    step : {a : R} {f : Poly R…} {n : }  HasDegree≤ f n  HasDegree≤ (a  f) (suc n)

  degreeBound : (f : Poly R…)  ∃[ n   ] HasDegree≤ f n
  degreeBound []        =  zero , base ∣₁
  degreeBound (a  f)   = map  (n , p)  suc n , step p) (degreeBound f)
  degreeBound (drop0 i) = {!!}