\import Algebra.Algebra
\import Algebra.Group
\import Algebra.Group.GroupHom
\import Algebra.Meta
\import Algebra.Module
\import Algebra.Monoid
\import Algebra.Pointed
\import Algebra.Ring
\import Function.Meta
\import Paths
\import Paths.Meta

\instance UnitAlgebra (R : CRing) (A : PseudoAlgebra R) : AAlgebra R (\Sigma R A)
  | zro => (0,0)
  | + s t => (s.1 + t.1, s.2 + t.2)
  | zro-left => ext (zro-left, zro-left)
  | zro-right => ext (zro-right, zro-right)
  | +-assoc => ext (+-assoc, +-assoc)
  | +-comm => ext (+-comm, +-comm)
  | * (a,x) (b,y) => (a * b, a *c y + b *c x + x * y)
  | *-assoc {x} {y} {z} => ext (*-assoc, rewrite (
      *c-ldistr, *c-ldistr, *c-ldistr, *c-ldistr, A.ldistr, A.ldistr, A.rdistr, A.rdistr, A.*-assoc,
      inv *c-assoc, inv *c-assoc, inv *c-assoc, inv *c-assoc,
      inv *c-comm-left, inv *c-comm-left, inv *c-comm-right, inv *c-comm-right,
      R.*-comm {z.1} {x.1}, R.*-comm {z.1} {y.1}) equation.abGroup)
  | ldistr => ext (R.ldistr, rewrite (A.ldistr,*c-ldistr,*c-rdistr) equation.abGroup)
  | rdistr => ext (R.rdistr, rewrite (A.rdistr,*c-ldistr,*c-rdistr) equation.abGroup)
  | negative (a,x) => (negative a, negative x)
  | negative-left => ext (negative-left, negative-left)
  | *c a (b,x) => (a * b, a *c x)
  | *c-assoc => ext (*-assoc, *c-assoc)
  | *c-ldistr => ext (R.ldistr, *c-ldistr)
  | *c-rdistr => ext (R.rdistr, *c-rdistr)
  | ide_*c => ext (ide-left, ide_*c)
  | *c-comm-left => ext (inv *-assoc, rewrite (*c-ldistr, *c-ldistr, *c-assoc, *c-comm-left) $ equation.abGroup $ A.toZero $ inv *c-assoc *> pmap (`*c _) *-comm *> *c-assoc)
  | *c-comm-right => ext (inv *-assoc *> pmap (`* _) *-comm *> *-assoc, rewrite (*c-ldistr, *c-ldistr, inv *c-assoc, inv *c-assoc, inv *c-comm-right) $ equation.abGroup $ A.toZero $ pmap (`*c _) *-comm *> *c-assoc)
  | ide => (1,0)
  | ide-left => ext (ide-left, rewrite (A.*c_zro-right, A.zro_*-left) $ zro-right *> zro-right *> ide_*c)
  | ide-right => ext (ide-right, rewrite (A.*c_zro-right, A.zro_*-right) $ zro-right *> zro-left *> ide_*c)
  | coefMap a => (a,0)
  | coefMap_*c => inv $ ext (ide-right, A.*c_zro-right)
  \where {
    \lemma *n-comm {a : R} {x : A} {n : Nat} : n AddMonoid.*n {UnitAlgebra R A} (a,x) = (n R.*n a, n A.*n x) \elim n
      | 0 => idp
      | suc n => pmap (__ + {UnitAlgebra R A} (a,x)) *n-comm

    \lemma *n-comm1 {a : R} {x : A} {n : Nat} : (n AddMonoid.*n {UnitAlgebra R A} (a,x)).1 = n R.*n a
      => pmap __.1 *n-comm

    \lemma *n-comm2 {a : R} {x : A} {n : Nat} : (n AddMonoid.*n {UnitAlgebra R A} (a,x)).2 = n A.*n x
      => pmap __.2 *n-comm
  }

\func unit-algebra {R : CRing} {A : PseudoAlgebra R} : AddGroupHom A (UnitAlgebra R A) \cowith
  | func x => (0,x)
  | func-+ => ext (inv zro-left, idp)

\instance UnitCAlgebra (R : CRing) (A : PseudoCAlgebra R) : CAlgebra R
  | AAlgebra => UnitAlgebra R A
  | *-comm => ext (*-comm, equation.abGroup $ A.toZero *-comm)