module IntegerAlgebra where

open import Preliminaries
open import Equivalences

record IntAlg (X : Set) : Set where
  constructor mk-IntAlg
  field
    S : X  X
    Z : X

module _ {X : Set} (X-alg : IntAlg X) where
  private module X = IntAlg X-alg

  record DIntAlg (Y : X  Set) : Set where
    constructor mk-DIntAlg
    field
      S : {x : X}  Y x  Y (X.S .fun x)
      Z : Y X.Z

  record Sec {Y : X  Set} (Y-alg : DIntAlg Y) : Set where
    private module Y = DIntAlg Y-alg
    field
      on-C : (x : X)  Y x
      on-S : (x : X)  on-C (X.S .fun x)  Y.S .fun (on-C x)
      on-Z : on-C X.Z  Y.Z

  nonDIntAlg : {Y : Set} (Y-alg : IntAlg Y)  DIntAlg  x  Y)
  nonDIntAlg Y-alg .DIntAlg.S = IntAlg.S Y-alg
  nonDIntAlg Y-alg .DIntAlg.Z = IntAlg.Z Y-alg

postulate
   : Set
  ℤ-alg : IntAlg 
  ℤ-elim : {Y :   Set} (Y-alg : DIntAlg ℤ-alg Y)  Sec ℤ-alg Y-alg

module  = IntAlg ℤ-alg

module _ {P :   Set} (P-alg : DIntAlg ℤ-alg P) where
  private module P = DIntAlg P-alg

  abstract
    ℤ-ind : (x : )  P x
    ℤ-ind = Sec.on-C (ℤ-elim P-alg)

    ℤ-ind-S : (x : )  ℤ-ind (ℤ.S .fun x)  P.S .fun (ℤ-ind x)
    ℤ-ind-S = Sec.on-S (ℤ-elim P-alg)

    ℤ-ind-Z : ℤ-ind ℤ.Z  P.Z
    ℤ-ind-Z = Sec.on-Z (ℤ-elim P-alg)

module _ {P : Set} (P-alg : IntAlg P) where
  module P = IntAlg P-alg

  abstract
    ℤ-elim-nondep : Sec ℤ-alg (nonDIntAlg ℤ-alg P-alg)
    ℤ-elim-nondep = ℤ-elim _

    ℤ-rec : (x : )  P
    ℤ-rec = ℤ-ind $ nonDIntAlg _ P-alg

    ℤ-rec-S : (x : )  ℤ-rec (ℤ.S .fun x)  P.S .fun (ℤ-rec x)
    ℤ-rec-S = ℤ-ind-S _

    ℤ-rec-inv : (x : )  ℤ-rec (ℤ.S .inv x)  P.S .inv (ℤ-rec x)
    ℤ-rec-inv x = symm (ap (P.S .inv  ℤ-rec) (symm $ ℤ.S .fun-inv x)  ap (P.S .inv) (ℤ-rec-S _)  P.S .inv-fun _)

    ℤ-rec-Z : ℤ-rec ℤ.Z  P.Z
    ℤ-rec-Z = ℤ-ind-Z _

    ℤ-rec-uniq : {f g :   P}  ((x : )  f (ℤ.S .fun x)  P.S .fun (f x))  f ℤ.Z  P.Z 
                 ((x : )  g (ℤ.S .fun x)  P.S .fun (g x))  g ℤ.Z  P.Z 
                 (x : )  f x  g x
    ℤ-rec-uniq {f} {g} fS fZ gS gZ = ℤ-ind $ mk-DIntAlg {Y = λ x  f x  g x}
       {x}  inv-iso (eq-congr (fS x) (gS x)) ∘ₑ ap-iso P.S)
      (fZ  symm gZ)