{-# OPTIONS --safe #-}
module Cubical.Algebra.CommAlgebra.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Function
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Structure using (⟨_⟩; withOpaqueStr)
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Univalence
open import Cubical.Foundations.Transport
open import Cubical.Foundations.Path

open import Cubical.Data.Sigma

open import Cubical.Algebra.CommRing
open import Cubical.Algebra.CommRing.Univalence
open import Cubical.Algebra.Ring

open import Cubical.Reflection.RecordEquiv

private
  variable
     ℓ' ℓ'' ℓ''' : Level

CommAlgebra : (R : CommRing ) (ℓ' : Level)  Type _
CommAlgebra R ℓ' = Σ[ A  CommRing ℓ' ] CommRingHom R A

module _ {R : CommRing } where
  CommAlgebra→CommRing : (A : CommAlgebra R ℓ')  CommRing ℓ'
  CommAlgebra→CommRing = fst

  ⟨_⟩ₐ : (A : CommAlgebra R ℓ')  Type ℓ'
   A ⟩ₐ = A .fst .fst

  {-
    Contrary to most algebraic structures, this one only contains
    law and structure of a CommAlgebra, which it is *in addition*
    to its CommRing structure.
  -}
  record CommAlgebraStr (A : Type ℓ') : Type (ℓ-suc (ℓ-max  ℓ')) where
    open CommRingStr {{...}}
    instance
      _ : CommRingStr (R .fst)
      _ = (R .snd)

    field
      crStr : CommRingStr A
      _⋆_ :  R   A  A
      ⋆Assoc : (r s :  R ) (x : A)  (r · s)  x  r  (s  x)
      ⋆DistR+ : (r :  R ) (x y : A)  r  (CommRingStr._+_ crStr x y)  CommRingStr._+_ crStr(r  x) (r  y)
      ⋆DistL+ : (r s :  R ) (x : A)  (r + s)  x  CommRingStr._+_ crStr (r  x) (s  x)
      ⋆IdL    : (x : A)  1r  x  x
      ⋆AssocL : (r :  R ) (x y : A)  CommRingStr._·_ crStr (r  x) y  r  (CommRingStr._·_ crStr x y)
    infixl 7 _⋆_

  {- TODO: make laws opaque -}
  CommAlgebra→CommAlgebraStr : (A : CommAlgebra R ℓ')  CommAlgebraStr  A ⟩ₐ
  CommAlgebra→CommAlgebraStr A =
    let open CommRingStr ⦃...⦄
        instance
          _ : CommRingStr (R .fst)
          _ = R .snd
          _ = A .fst .snd
    in record
       { crStr = A .fst .snd
       ; _⋆_ = λ r x  (A .snd .fst r) · x
       ; ⋆Assoc = λ r s x  cong ( x) (IsCommRingHom.pres· (A .snd .snd) r s)  sym (·Assoc _ _ _)
       ; ⋆DistR+ = λ r x y  ·DistR+ _ _ _
       ; ⋆DistL+ = λ r s x  cong ( x) (IsCommRingHom.pres+ (A .snd .snd) r s)  ·DistL+ _ _ _
       ; ⋆IdL = λ x  cong ( x) (IsCommRingHom.pres1 (A .snd .snd))  ·IdL x
       ; ⋆AssocL = λ r x y  sym (·Assoc (A .snd .fst r) x y)
       }


{-
   Homomorphisms of CommAlgebras
   -----------------------------
   This is defined as a record instead of a Σ-type to make type inference work
   better.
-}
  record IsCommAlgebraHom (A : CommAlgebra R ℓ') (B : CommAlgebra R ℓ'') (f :  A ⟩ₐ   B ⟩ₐ) : Type (ℓ-max  (ℓ-max ℓ' ℓ'')) where
    no-eta-equality
    field
      isCommRingHom : IsCommRingHom (A .fst .snd) f (B .fst .snd)
      commutes : (f , isCommRingHom) ∘cr snd A  snd B

    open IsCommRingHom isCommRingHom public
    open CommRingStr ⦃...⦄
    open CommAlgebraStr ⦃...⦄
    private instance
      _ = CommAlgebra→CommAlgebraStr A
      _ = CommAlgebra→CommAlgebraStr B
      _ = B .fst .snd
    pres⋆ : (r :  R ) (x :  A ⟩ₐ)  f (r  x)  r  f x
    pres⋆ r x = f (r  x)                    ≡⟨ pres· (A .snd .fst r) x 
                (f (A .snd .fst r)) · (f x)  ≡⟨ cong ( (f x)) (cong  g  g .fst r) commutes) 
                r  f x 

  unquoteDecl IsCommAlgebraHomIsoΣ = declareRecordIsoΣ IsCommAlgebraHomIsoΣ (quote IsCommAlgebraHom)

  isPropIsCommAlgebraHom : (A : CommAlgebra R ℓ') (B : CommAlgebra R ℓ'') (f :  A ⟩ₐ   B ⟩ₐ)
     isProp (IsCommAlgebraHom A B f)
  isPropIsCommAlgebraHom A B f =
    isOfHLevelRetractFromIso 1 IsCommAlgebraHomIsoΣ $
    isPropΣ (isPropIsCommRingHom (A .fst .snd) f (B .fst .snd))
             λ _  isSetΣSndProp (isSet→ is-set)  _  isPropIsCommRingHom _ _ _) _ _
    where
    open CommRingStr (B .fst .snd) using (is-set)

  CommAlgebraHom : (A : CommAlgebra R ℓ') (B : CommAlgebra R ℓ'')  Type _
  CommAlgebraHom A B = Σ[ f  ( A ⟩ₐ   B ⟩ₐ) ]  IsCommAlgebraHom A B f

  CommRingHom→CommAlgebraHom :
    {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''}
     (f : CommRingHom (A .fst) (B .fst))
     f ∘cr snd A  snd B
     CommAlgebraHom A B
  CommRingHom→CommAlgebraHom f commutes .fst = f .fst
  CommRingHom→CommAlgebraHom f commutes .snd =
    record { isCommRingHom = f .snd ; commutes = commutes }

  CommAlgebraHom→CommRingHom : {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''}
                              CommAlgebraHom A B
                              CommRingHom (CommAlgebra→CommRing A) (CommAlgebra→CommRing B)
  CommAlgebraHom→CommRingHom f = f .fst , IsCommAlgebraHom.isCommRingHom (f .snd)

  ⟨_⟩ᵣ→ = CommAlgebraHom→CommRingHom

  CommAlgebraHom→Triangle : {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''}
                              (f : CommAlgebraHom A B)
                               f ⟩ᵣ→ ∘cr A .snd   B .snd
  CommAlgebraHom→Triangle f = IsCommAlgebraHom.commutes (f .snd)

  idCAlgHom : (A : CommAlgebra R ℓ')  CommAlgebraHom A A
  idCAlgHom A = CommRingHom→CommAlgebraHom (idCommRingHom (fst A)) (CommRingHom≡ refl)

  idCommAlgebraHom = idCAlgHom

  compCommAlgebraHom : {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''} {C : CommAlgebra R ℓ'''}
                       (f : CommAlgebraHom A B)  (g : CommAlgebraHom B C)
                       CommAlgebraHom A C
  compCommAlgebraHom {A = A} {B = B} {C = C} f g =
    CommRingHom→CommAlgebraHom ( g ⟩ᵣ→ ∘cr  f ⟩ᵣ→) pasting
    where
      opaque
        pasting : ( g ⟩ᵣ→ ∘cr  f ⟩ᵣ→) ∘cr snd A  snd C
        pasting =
          CommRingHom≡ $
                  ( g ⟩ᵣ→ ∘cr ( f ⟩ᵣ→ ∘cr snd A)) .fst ≡⟨ cong  h  ( g ⟩ᵣ→ ∘cr h) .fst) (CommAlgebraHom→Triangle f) 
                  ( g ⟩ᵣ→ ∘cr snd B) .fst             ≡⟨ cong fst (CommAlgebraHom→Triangle g) 
                  (C .snd .fst) 

  ⟨_⟩ₐ→ : {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''} (f : CommAlgebraHom A B)   A ⟩ₐ   B ⟩ₐ
   f ⟩ₐ→ = f .fst

  _$ca_ : {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''}  (φ : CommAlgebraHom A B)  (x :  A ⟩ₐ)   B ⟩ₐ
  _$ca_ φ x = φ .fst x

  infixr 9 _∘ca_ -- same as functions
  _∘ca_ : {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''} {C : CommAlgebra R ℓ'''}
         CommAlgebraHom B C  CommAlgebraHom A B  CommAlgebraHom A C
  g ∘ca f = compCommAlgebraHom f g

  opaque
    CommAlgebraHom≡ :
      {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''} {f g : CommAlgebraHom A B}
       f .fst  g .fst
       f  g
    CommAlgebraHom≡ {B = B} p = Σ≡Prop  _  isPropIsCommAlgebraHom _ _ _) p
      where open CommRingStr (B .fst .snd) using (is-set)


{- Equivalences of CommAlgebras -}
  CommAlgebraEquiv : (A : CommAlgebra R ℓ') (B : CommAlgebra R ℓ'')  Type _
  CommAlgebraEquiv A B = Σ[ f  ( A ⟩ₐ   B ⟩ₐ) ] IsCommAlgebraHom A B (f .fst)

  idCAlgEquiv : (A : CommAlgebra R ℓ')  CommAlgebraEquiv A A
  idCAlgEquiv A = (idEquiv  A ⟩ₐ) , isHom
    where
      opaque
        isHom : IsCommAlgebraHom A A (idfun  A ⟩ₐ)
        isHom = record { isCommRingHom = idCommRingHom (A .fst) .snd ;
                         commutes = CommRingHom≡ refl }

  CommAlgebraEquiv≡ :
      {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''} {f g : CommAlgebraEquiv A B}
       f .fst .fst  g .fst .fst
       f  g
  CommAlgebraEquiv≡ {B = B} p =
    Σ≡Prop (isPropIsCommAlgebraHom _ _  fst) (Σ≡Prop isPropIsEquiv p)

  isSetCommAlgebraEquiv : (A : CommAlgebra R ℓ') (B : CommAlgebra R ℓ'')
                           isSet (CommAlgebraEquiv A B)
  isSetCommAlgebraEquiv A B =
     isSetΣSndProp (isSetΣSndProp (isSet→ isSetB) isPropIsEquiv)
                   (isPropIsCommAlgebraHom _ _  fst)
     where open CommRingStr (B .fst .snd) using () renaming (is-set to isSetB)

  CommAlgebraHomFromCommRingHom :
    {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''}
     (f : CommRingHom (A .fst) (B .fst))
     ((r :  R ) (x :  A ⟩ₐ)  f .fst (CommAlgebraStr._⋆_ (CommAlgebra→CommAlgebraStr A) r x)
                                  CommAlgebraStr._⋆_ (CommAlgebra→CommAlgebraStr B) r (f .fst x))
     CommAlgebraHom A B
  CommAlgebraHomFromCommRingHom {A = A} {B = B} f pres⋆ = CommRingHom→CommAlgebraHom f
    let open CommRingStr ⦃...⦄
        open CommAlgebraStr ⦃...⦄
        instance
          _ = A .fst .snd
          _ = B .fst .snd
          _ = CommAlgebra→CommAlgebraStr B
    in CommRingHom≡
      (funExt  (r :  R ) 
              f .fst (A .snd .fst r)        ≡⟨ cong  u  f .fst u) (sym (·IdR _)) 
              f .fst ((A .snd .fst r) · 1r) ≡⟨ pres⋆ r (CommRingStr.1r (A .fst .snd)) 
              r  (f .fst 1r)               ≡⟨ cong (r ⋆_) (IsCommRingHom.pres1 (f .snd)) 
              r  1r                        ≡⟨ ·IdR _ 
              B .snd .fst r ))

  CommAlgebraEquivFromCommRingEquiv :
    {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''}
     (f : CommRingEquiv (A .fst) (B .fst))
     ((f .fst .fst , f .snd)  ∘cr A .snd  B .snd)
     CommAlgebraEquiv A B
  CommAlgebraEquivFromCommRingEquiv f p .fst = f .fst
  CommAlgebraEquivFromCommRingEquiv f p .snd = record { isCommRingHom = f .snd ; commutes = p }


{- Convenient forgetful functions -}
module _ {R : CommRing } where
  CommAlgebra→Ring : (A : CommAlgebra R ℓ')  Ring ℓ'
  CommAlgebra→Ring A = CommRing→Ring (fst A)

  CommAlgebra→CommRingStr : (A : CommAlgebra R ℓ')  CommRingStr  A ⟩ₐ
  CommAlgebra→CommRingStr A = A .fst .snd

  CommAlgebra→Set : (A : CommAlgebra R ℓ')  hSet ℓ'
  CommAlgebra→Set A =  A ⟩ₐ , is-set
    where open CommRingStr (CommAlgebra→CommRingStr A) using (is-set)

  isSetCommAlgebraHom : (A : CommAlgebra R ℓ') (B : CommAlgebra R ℓ'')
                         isSet (CommAlgebraHom A B)
  isSetCommAlgebraHom A B = isSetΣSndProp (isSet→ is-set)  _  isPropIsCommAlgebraHom _ _ _)
    where open CommRingStr (CommAlgebra→CommRingStr B) using (is-set)

  CommAlgebraHom→RingHom : {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''}
                              CommAlgebraHom A B
                              RingHom (CommAlgebra→Ring A) (CommAlgebra→Ring B)
  CommAlgebraHom→RingHom = CommRingHom→RingHom  CommAlgebraHom→CommRingHom

  CommAlgebraEquiv→CommAlgebraHom : {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''}
                              CommAlgebraEquiv A B
                              CommAlgebraHom A B
  CommAlgebraEquiv→CommAlgebraHom f = (f .fst .fst , f .snd)

  CommAlgebraEquiv→CommRingHom : {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''}
                              CommAlgebraEquiv A B
                              CommRingHom (CommAlgebra→CommRing A) (CommAlgebra→CommRing B)
  CommAlgebraEquiv→CommRingHom = CommAlgebraHom→CommRingHom  CommAlgebraEquiv→CommAlgebraHom

  CommAlgebraEquiv→CommRingEquiv :
                             {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''}
                              CommAlgebraEquiv A B
                              CommRingEquiv (CommAlgebra→CommRing A) (CommAlgebra→CommRing B)
  CommAlgebraEquiv→CommRingEquiv e = (e .fst) , (IsCommAlgebraHom.isCommRingHom (e .snd))

  ⟨_⟩ₐ≃ :
        {A : CommAlgebra R ℓ'} {B : CommAlgebra R ℓ''}
         CommAlgebraEquiv A B
          A ⟩ₐ   B ⟩ₐ
   e ⟩ₐ≃ =  CommAlgebraEquiv→CommAlgebraHom e ⟩ₐ→