{-# OPTIONS --safe #-}
module Cubical.Algebra.DirectSum.DirectSumHIT.Properties where

open import Cubical.Foundations.Prelude

open import Cubical.Data.Empty as 
open import Cubical.Data.Sigma

open import Cubical.Relation.Nullary

open import Cubical.Algebra.Group
open import Cubical.Algebra.AbGroup
open import Cubical.Algebra.DirectSum.DirectSumHIT.Base

private variable
   ℓ' : Level

module AbGroupProperties
  (Idx : Type )
  (P : Idx  Type ℓ')
  (AGP : (r : Idx)  AbGroupStr (P r))
  where

  inv : ⊕HIT Idx P AGP  ⊕HIT Idx P AGP
  inv = DS-Rec-Set.f Idx P AGP (⊕HIT Idx P AGP) trunc
           -- elements
           neutral
            r a  base r (AbGroupStr.-_ (AGP r) a))
            xs ys  xs add ys)
           -- eq group
            xs ys zs  addAssoc xs ys zs)
            xs  addRid xs)
            xs ys  addComm xs ys)
           -- eq base
            r  let open AbGroupStr (AGP r) in
                   let open GroupTheory (P r , AbGroupStr→GroupStr (AGP r)) in
                   (cong (base r) inv1g)  (base-neutral r))
            r a b  let open AbGroupStr (AGP r) in
                       let open GroupTheory (P r , AbGroupStr→GroupStr (AGP r)) in
                       ((base r (- a) add base r (- b))   ≡⟨ (base-add r (- a) (- b)) 
                       base r ((- a) + (- b))             ≡⟨ (cong (base r) (sym (invDistr b a))) 
                       base r (- (b + a))                 ≡⟨ cong (base r) (cong (-_) (+Comm b a)) 
                       base r (- (a + b)) ))



  rinv : (z : ⊕HIT Idx P AGP)  z add (inv z)  neutral
  rinv = DS-Ind-Prop.f Idx P AGP  z  z add (inv z)  neutral)  _  trunc _ _)
         -- elements
         (addRid neutral)
          r a  let open AbGroupStr (AGP r) in
                        ((base r a add base r (- a)) ≡⟨ base-add r a (- a) 
                        base r (a + - a)             ≡⟨ cong (base r) (+InvR a) 
                        base r 0g                    ≡⟨ base-neutral r 
                        neutral ))
          {x} {y} p q 
                        (((x add y) add ((inv x) add (inv y)))   ≡⟨ cong  X  X add ((inv x) add (inv y))) (addComm x y) 
                        ((y add x) add (inv x add inv y))        ≡⟨ sym (addAssoc y x (inv x add inv y)) 
                        (y add (x add (inv x add inv y)))        ≡⟨ cong  X  y add X) (addAssoc x (inv x) (inv y)) 
                        (y add ((x add inv x) add inv y))        ≡⟨ cong  X  y add (X add (inv y))) (p) 
                        (y add (neutral add inv y))              ≡⟨ cong  X  y add X) (addComm neutral (inv y)) 
                        (y add (inv y add neutral))              ≡⟨ cong  X  y add X) (addRid (inv y)) 
                        (y add inv y)                            ≡⟨ q 
                        neutral ))

module SubstLemma
  (Idx : Type )
  (G    : Idx  Type ℓ')
  (Gstr : (r : Idx)  AbGroupStr (G r))
  where

  open AbGroupStr

  substG : {k l : Idx}  (x : k  l)  (a : G k)  G l
  substG x a = subst G x a

  substG0 : {k l : Idx}  (p : k  l)  subst G p (0g (Gstr k))  0g (Gstr l)
  substG0 {k} {l} p = J  l p  subst G p (0g (Gstr k))  0g (Gstr l)) (transportRefl _) p

  substG+ : {k : Idx}  (a b : G k)  {l : Idx}   (p : k  l) 
           Gstr l ._+_ (subst G p a) (subst G p b)  subst G p (Gstr k ._+_ a b)
  substG+ {k} a b {l} p = J  l p  Gstr l ._+_ (subst G p a) (subst G p b)  subst G p (Gstr k ._+_ a b))
                         (cong₂ (Gstr k ._+_) (transportRefl _) (transportRefl _)  sym (transportRefl _))
                         p



module DecIndec-BaseProperties
  (Idx  : Type )
  (decIdx : Discrete Idx)
  (G    : Idx  Type ℓ')
  (Gstr : (r : Idx)  AbGroupStr (G r))
  where

  open AbGroupStr
  open SubstLemma Idx G Gstr

  πₖ : (k : Idx)  ⊕HIT Idx G Gstr  G k
  πₖ k = DS-Rec-Set.f _ _ _ _ (is-set (Gstr k))
         (0g (Gstr k))
         base-trad
         (_+_ (Gstr k))
         (+Assoc (Gstr k))
         (+IdR (Gstr k))
         (+Comm (Gstr k))
         base-neutral-eq
         base-add-eq
     where
     base-trad : (l : Idx)  (a : G l)  G k
     base-trad l a with decIdx l k
     ... | yes p = subst G p a
     ... | no ¬p = 0g (Gstr k)

     base-neutral-eq : _
     base-neutral-eq l with decIdx l k
     ... | yes p = substG0 p
     ... | no ¬p = refl

     base-add-eq : _
     base-add-eq l a b with decIdx l k
     ... | yes p = substG+ a b p
     ... | no ¬p = +IdR (Gstr k) _

  πₖ-id : {k : Idx}  (a : G k)  πₖ k (base k a)  a
  πₖ-id {k} a with decIdx k k
  ... | yes p = cong  X  subst G X a) (Discrete→isSet decIdx _ _ _ _)  transportRefl _
  ... | no ¬p = rec (¬p refl)

  πₖ-0g : {k l : Idx}  (a : G l)  (p : k  l  )  πₖ k (base l a)  0g (Gstr k)
  πₖ-0g {k} {l} a ¬q with decIdx l k
  ... | yes p = rec (¬q (sym p))
  ... | no ¬p = refl

  base-inj : {k : Idx}  {a b : G k}  base {AGP = Gstr} k a  base k b  a  b
  base-inj {k} {a} {b} p = sym (πₖ-id a)  cong (πₖ k) p  πₖ-id b

  base-≢ : {k : Idx}  {a : G k}  {l : Idx}  {b : G l}  (p : k  l  ) 
           base {AGP = Gstr} k a  base {AGP = Gstr} l b  (a  0g (Gstr k)) × (b  0g (Gstr l))
  base-≢ {k} {a} {l} {b} ¬p q = helper1 , helper2
    where
    helper1 : a  0g (Gstr k)
    helper1 = sym (πₖ-id a)  cong (πₖ k) q  πₖ-0g b ¬p

    helper2 : b  0g (Gstr l)
    helper2 = sym (πₖ-id b)  cong (πₖ l) (sym q)  πₖ-0g a  x  ¬p (sym x))