\import Algebra.Pointed
\import Algebra.Pointed.PointedHom
\import Category
\import Category.Meta
\import Function (Image, IsInj, IsSurj)
\import Logic
\import Paths
\import Paths.Meta

\instance PointedCat : Cat Pointed
  | Hom X Y => PointedHom X Y
  | id _ => PointedHom.id
  | o => PointedHom.
  | id-left => idp
  | id-right => idp
  | o-assoc => idp
  | univalence => sip (\lam p1 p2 => ext (func-ide {p1}))

\instance AddPointedCat : Cat AddPointed
  | Hom X Y => AddPointedHom X Y
  | id => AddPointedHom.id
  | o => AddPointedHom.
  | id-left => idp
  | id-right => idp
  | o-assoc => idp
  | univalence => sip (\lam p1 p2 => ext (func-zro {p1}))

\type Kernel (f : AddPointedHom) => \Sigma (a : f.Dom) (f a = 0)

\instance KerAddPointed (f : AddPointedHom) : AddPointed (Kernel f)
  | zro => (0, func-zro)

\func KerPointedHom (f : AddPointedHom) : AddPointedHom (KerAddPointed f) f.Dom \cowith
  | func => __.1
  | func-zro => idp

\lemma kernel-inj {f : AddPointedHom} : IsInj (KerPointedHom f)
  => \lam p => ext p

\instance ImageAddPointed (f : AddPointedHom) : AddPointed (Image f)
  | zro => (0, inP (0, func-zro))

\instance ImagePointed (f : PointedHom) : Pointed (Image f)
  | ide => (ide, inP (ide, func-ide))


\func ImagePointedLeftHom (f : PointedHom)  : PointedHom f.Dom (ImagePointed f) \cowith
  | func a => (f a, inP (a, idp))
  | func-ide => ext func-ide

\func ImagePointedRightHom(f : PointedHom) : PointedHom (ImagePointed f) f.Cod \cowith
  | func => __.1
  | func-ide => idp



\func ImageAddPointedLeftHom (f : AddPointedHom) : AddPointedHom f.Dom (ImageAddPointed f) \cowith
  | func a => (f a, inP (a, idp))
  | func-zro => ext func-zro

\func ImageAddPointedRightHom (f : AddPointedHom) : AddPointedHom (ImageAddPointed f) f.Cod \cowith
  | func => __.1
  | func-zro => idp

\lemma image-surj {f : AddPointedHom} : IsSurj (ImageAddPointedLeftHom f)
  => \lam y => TruncP.map y.2 \lam s => (s.1, ext s.2)

\lemma image-inj {f : AddPointedHom} : IsInj (ImageAddPointedRightHom f)
  => \lam p => ext p