{-# OPTIONS --safe #-}
module Cubical.Data.NatPlusOne.MoreNats.AssocNat.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.HLevels

open import Cubical.Data.Empty
open import Cubical.Data.Unit
open import Cubical.Data.Nat hiding (_+_)

infixl 6 _+₁_

data ℕ₊₁ : Type where
  one : ℕ₊₁
  _+₁_ : ℕ₊₁  ℕ₊₁  ℕ₊₁
  assoc : (a b c : ℕ₊₁)   a +₁ (b +₁ c)  a +₁ b +₁ c
  trunc : isSet ℕ₊₁

module Elim {ℓ'} {B : ℕ₊₁  Type ℓ'}
  (one* : B one) (_+₁*_ : {m n : ℕ₊₁}  B m  B n  B (m +₁ n))
  (assoc* : {x y z : ℕ₊₁} (x' : B x) (y' : B y) (z' : B z)
             PathP  i  B (assoc x y z i))
            (x' +₁* (y' +₁* z')) ((x' +₁* y') +₁* z'))
  (trunc* : (n : ℕ₊₁)  isSet (B n)) where

  f : (n : ℕ₊₁)  B n
  f one = one*
  f (m +₁ n) = f m +₁* f n
  f (assoc x y z i) = assoc* (f x) (f y) (f z) i
  f (trunc m n p q i j) =
    isOfHLevel→isOfHLevelDep 2 trunc* (f m) (f n)
    (cong f p) (cong f q) (trunc m n p q) i j

module ElimProp {ℓ'} {B : ℕ₊₁  Type ℓ'} (BProp : {n : ℕ₊₁}  isProp (B n))
  (one* : B one) (_+₁*_ : {m n : ℕ₊₁}  B m  B n  B (m +₁ n)) where

  f : (n : ℕ₊₁)  B n
  f = Elim.f {B = B} one* _+₁*_
         {x} {y} {z} x' y' z' 
          toPathP (BProp (transport  i  B (assoc x y z i))
          (x' +₁* (y' +₁* z'))) ((x' +₁* y') +₁* z')))
        λ n  isProp→isSet BProp

module Rec {ℓ'} {B : Type ℓ'} (BType : isSet B)
  (one* : B) (_+₁*_ : B  B  B)
  (assoc* : (a b c : B)  a +₁* (b +₁* c)  (a +₁* b) +₁* c) where

  f : ℕ₊₁  B
  f = Elim.f one*  m n  m +₁* n) assoc* λ _  BType

private
  constraintNumber :   Type
  constraintNumber zero = 
  constraintNumber (suc _) = Unit

  fromNat' : (n : )  _ : constraintNumber n   ℕ₊₁
  fromNat' zero  () 
  fromNat' (suc zero) = one
  fromNat' (suc (suc n)) = fromNat' (suc n) +₁ one

instance
  NumN : HasFromNat ℕ₊₁
  NumN = record { Constraint = constraintNumber ; fromNat = fromNat' }