{-# OPTIONS --without-K #-}
module sets.nat.struct where

open import sum
open import equality
open import function
open import container.core
open import container.w
open import sets.empty
open import sets.unit
open import sets.nat.core
open import sets.fin
open import sets.vec.dependent
open import hott.level

ℕ-c : Container _ _ _
ℕ-c = record
  { I = 
  ; A = λ _  Fin 2
  ; B =  ∷∷  ∷∷ ⟦⟧
  ; r = λ _  tt }

open Container ℕ-c

ℕ-algebra-iso : (  )  
ℕ-algebra-iso = record
  { to = λ { (inj₁ _)  zero ; (inj₂ n)  suc n }
  ; from = λ { zero  inj₁ tt ; (suc n)  inj₂ n }
  ; iso₁ = λ { (inj₁ _)  refl ; (inj₂ n)  refl }
  ; iso₂ = λ { zero  refl ; (suc n)  refl } }

private
  inℕ : F  _  ) tt  
  inℕ (zero , u) = 0
  inℕ (suc zero , u) = suc (u tt)
  inℕ (suc (suc ()) , u)

ℕ-struct-iso :   W ℕ-c tt
ℕ-struct-iso = iso f g α β
  where
    f :   W ℕ-c tt
    f 0 = sup (# 0)  ())
    f (suc n) = sup (# 1)  _  f n)

    g : W ℕ-c tt  
    g = fold ℕ-c  i  inℕ) tt

    α : (n : )  g (f n)  n
    α zero = refl
    α (suc n) = ap suc (α n)

    β : (n : W ℕ-c tt)  f (g n)  n
    β (sup zero u) = ap (sup zero) (funext λ ())
    β (sup (suc zero) u) = ap (sup (# 1)) (funext  x  β (u tt)))
    β (sup (suc (suc ())) u)

private
  F-struct-iso :  {i}(X :   Set i)  F X tt  (  X tt)
  F-struct-iso X = begin
      ( Σ (A tt) λ a  B a  X tt )
    ≅⟨ sym≅ (⊎-Σ-iso  a  B a  X tt)) 
      ( (  X tt)  (  X tt) )
    ≅⟨ ⊎-ap-iso (contr-⊤-iso ⊥-initial) Π-left-unit 
      (   X tt )
    
    where open ≅-Reasoning

ℕ-initial :  {i} (X :   Set i)
           (x₀ : X 0)(f :  n  X n  X (suc n))
           contr ( Σ ((n : )  X n) λ x
                   (x₀  x 0)
                  × (∀ n  f n (x n)  x (suc n)) )
ℕ-initial X x₀ f = iso-level ℕ-alg-iso (W-section-contr ℕ-c 𝓧)
  where
    ψ :  x  ((b : B (proj₁ x))  X (proj₂ x b))  X (inℕ x)
    ψ (zero , u) v = x₀
    ψ (suc zero , u) v = f (u tt) (v tt)
    ψ (suc (suc ()) , u) v

    P :  i (n : W ℕ-c i)  Set _
    P i n = X (invert ℕ-struct-iso n)

    θ :  i x  ((b : B (proj₁ x))  P tt (proj₂ x b))  P i (inW ℕ-c i x)
    θ i (a , u) v = ψ (a , invert ℕ-struct-iso ∘' u) v

    𝓧 : AlgFib ℕ-c _
    𝓧 = P , θ

    ℕ-alg-iso : AlgSection ℕ-c 𝓧 
              ( Σ ((n : )  X n) λ x
               (x₀  x 0)
              × (∀ n  f n (x n)  x (suc n)) )
    ℕ-alg-iso = begin
        AlgSection ℕ-c 𝓧
      ≅⟨ ( Σ-ap-iso Π-left-unit λ g  iso≡ Π-left-unit) 
        ( Σ ((w : W ℕ-c tt)  P tt w) λ g
         ( _≡_ {A = (x : F (W ℕ-c) tt)  P tt (inW ℕ-c tt x)}
             x  θ tt x  b  g (proj₂ x b)))
             x  g (inW ℕ-c tt x)) ) )
      ≅⟨ sym≅ ( Σ-ap-iso (Π-ap-iso ℕ-struct-iso λ _  refl≅) λ g
          iso≡ (Π-ap-iso (sym≅ (F-ap-iso  i  sym≅ ℕ-struct-iso) tt)) λ x
                 refl≅ ) ) 
        ( Σ ((n : )  X n) λ g
         ( _≡_ {A = (x : F  _  ) tt)  X (inℕ x)}
             x  ψ x  b  g (proj₂ x b)))
             x  g (inℕ x)) ) )
      ≅⟨ ( Σ-ap-iso refl≅ λ g
          iso≡ (Π-ap-iso (F-struct-iso  _  )) λ _  refl≅) ) 
        ( let φ = invert (F-struct-iso  _  ))
        in Σ ((n : )  X n) λ g
         ( _≡_ {A = (x :   )  X (inℕ (φ x))}
             x  ψ (φ x)  b  g (proj₂ (φ x) b)))
             x  g (inℕ (φ x))) ) )
      ≅⟨ ( Σ-ap-iso refl≅ λ x  iso≡ ⊎-universal ) 
        ( Σ ((n : )  X n) λ x
         ( _≡_ {A = (  X 0) × ((n : )  X (suc n))}
            ((λ _  x₀) ,  n  f n (x n)))
            ((λ _  x 0) ,  n  x (suc n))) ) )
      ≅⟨ ( Σ-ap-iso refl≅ λ x  sym≅ ×-split-iso ) 
        ( Σ ((n : )  X n) λ x
         (_≡_ {A =   X 0}  _  x₀)  _  x 0))
        × (_≡_ {A = (n : )  X (suc n)}  n  f n (x n))  n  x (suc n))) )
      ≅⟨ ( Σ-ap-iso refl≅ λ x  ×-ap-iso (iso≡ Π-left-unit) (sym≅ strong-funext-iso) ) 
        ( Σ ((n : )  X n) λ x
         (x₀  x 0)
        × (∀ n  f n (x n)  x (suc n)) )
      
      where
        open ≅-Reasoning

ℕ-initial-simple :  {i} {X : Set i} (x₀ : X)
                  contr ( Σ (  X) λ x
                          (x₀  x 0)
                         × (∀ n  x n  x (suc n)) )
ℕ-initial-simple {X = X} x₀
  = ((λ _  x₀) , refl , λ _  refl)
  ,  u  contr⇒prop (ℕ-initial  _  X) x₀  _ x  x)) _ u)

ℕ-elim-shift :  {i}{X :   Set i}
              ((n : )  X n)
              ( (X 0) × ((n : )  X (suc n)) )
ℕ-elim-shift {i}{X} = begin
    ((n : )  X n)
  ≅⟨ (Π-ap-iso (sym≅ ℕ-algebra-iso) λ _  refl≅) 
    ((n :   )  X (apply ℕ-algebra-iso n))
  ≅⟨ ⊎-universal 
    ((  X 0) × ((n : )  X (suc n)))
  ≅⟨ ×-ap-iso Π-left-unit refl≅ 
    (X 0 × ((n : )  X (suc n)))
  
  where
    open ≅-Reasoning