{-

Freudenthal suspension theorem

-}
{-# OPTIONS --safe #-}
module Cubical.Homotopy.Freudenthal where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.GroupoidLaws
open import Cubical.Foundations.Pointed
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Path
open import Cubical.Foundations.Univalence

open import Cubical.Data.Nat
open import Cubical.Data.Nat.Order
open import Cubical.Data.Sigma
open import Cubical.Data.Empty renaming (rec to ⊥-rec)

open import Cubical.HITs.Truncation as Trunc renaming (rec to trRec ; elim to trElim)

open import Cubical.HITs.Susp renaming (toSusp to σ)
open import Cubical.HITs.SmashProduct
open import Cubical.HITs.Nullification
open import Cubical.HITs.S1 hiding (encode)
open import Cubical.HITs.S2
open import Cubical.HITs.S3
open import Cubical.HITs.Sn

open import Cubical.Homotopy.Connected
open import Cubical.Homotopy.WedgeConnectivity
open import Cubical.Homotopy.Loopspace




module _ {} (n : HLevel) {A : Pointed } (connA : isConnected (suc (suc n)) (typ A)) where

  private
    2n+2 = suc n + suc n

    module WC (p : north  north) =
      WedgeConnectivity (suc n) (suc n) A connA A connA
         a b 
          ( (σ A b  p  hLevelTrunc 2n+2 (fiber  x  merid x  merid a ⁻¹) p))
          , isOfHLevelΠ 2n+2 λ _  isOfHLevelTrunc 2n+2
          ))
         a r   a , (rCancel' (merid a)  rCancel' (merid (pt A)) ⁻¹)  r )
         b r   b , r )
        (funExt λ r 
          congS  w   pt A , w )
            (cong (_∙ r) (rCancel' (rCancel' (merid (pt A))))
               lUnit r ⁻¹))

    fwd : (p : north  north) (a : typ A)
       hLevelTrunc 2n+2 (fiber (σ A) p)
       hLevelTrunc 2n+2 (fiber  x  merid x  merid a ⁻¹) p)
    fwd p a = Trunc.rec (isOfHLevelTrunc 2n+2) (uncurry (WC.extension p a))

    isEquivFwd : (p : north  north) (a : typ A)  isEquiv (fwd p a)
    isEquivFwd p a .equiv-proof =
      elim.isEquivPrecompose  _  pt A) (suc n)
         a 
          ( (∀ t  isContr (fiber (fwd p a) t))
          , isProp→isOfHLevelSuc n (isPropΠ λ _  isPropIsContr)
          ))

        (isConnectedPoint (suc n) connA (pt A))
        .equiv-proof
         _  Trunc.elim
           _  isProp→isOfHLevelSuc (n + suc n) isPropIsContr)
          fib 
            subst  k  isContr (fiber k  fib ))
              (cong (Trunc.rec (isOfHLevelTrunc 2n+2)  uncurry)
                (funExt (WC.right p) ⁻¹))
              (subst isEquiv
                (funExt (Trunc.mapId) ⁻¹)
                (idIsEquiv _)
                .equiv-proof  fib )
             ))
        .fst .fst a

    interpolate : (a : typ A)
       PathP  i  typ A  north  merid a i)  x  merid x  merid a ⁻¹) merid
    interpolate a i x j = compPath-filler (merid x) (merid a ⁻¹) (~ i) j

  Code : (y : Susp (typ A))  north  y  Type 
  Code north p = hLevelTrunc 2n+2 (fiber (σ A) p)
  Code south q = hLevelTrunc 2n+2 (fiber merid q)
  Code (merid a i) p =
    Glue
      (hLevelTrunc 2n+2 (fiber (interpolate a i) p))
      
        { (i = i0)  _ , (fwd p a , isEquivFwd p a)
        ; (i = i1)  _ , idEquiv _
        })

  encode : (y : Susp (typ A)) (p : north  y)  Code y p
  encode y = J Code  pt A , rCancel' (merid (pt A)) 

  encodeMerid : (a : typ A)  encode south (merid a)   a , refl 
  encodeMerid a =
    cong (transport  i  gluePath i))
      (funExt⁻ (WC.left refl a) _  λ i   a , lem (rCancel' (merid a)) (rCancel' (merid (pt A))) i )
     transport (PathP≡Path gluePath _ _)
       i   a ,  j k  rCancel-filler' (merid a) i j k) )
    where
    gluePath : I  Type _
    gluePath i = hLevelTrunc 2n+2 (fiber (interpolate a i)  j  merid a (i  j)))

    lem :  {} {A : Type } {x y z : A} (p : x  y) (q : z  y)  (p  q ⁻¹)  q  p
    lem p q = assoc p (q ⁻¹) q ⁻¹ ∙∙ cong (p ∙_) (lCancel q) ∙∙ rUnit p ⁻¹

  contractCodeSouth : (p : north  south) (c : Code south p)  encode south p  c
  contractCodeSouth p =
    Trunc.elim
       _  isOfHLevelPath 2n+2 (isOfHLevelTrunc 2n+2) _ _)
      (uncurry λ a 
        J  p r  encode south p   a , r ) (encodeMerid a))

  isConnectedMerid : isConnectedFun 2n+2 (merid {A = typ A})
  isConnectedMerid p = encode south p , contractCodeSouth p

  isConnectedσ : isConnectedFun 2n+2 (σ A)
  isConnectedσ =
    transport  i  isConnectedFun 2n+2 (interpolate (pt A) (~ i))) isConnectedMerid

isConn→isConnSusp :  {} {A : Pointed }  isConnected 2 (typ A)  isConnected 2 (Susp (typ A))
isConn→isConnSusp {A = A} iscon =  north 
                                , trElim  _  isOfHLevelSuc 1 (isOfHLevelTrunc 2 _ _))
                                         (suspToPropElim (pt A)  _  isOfHLevelTrunc 2 _ _)
                                         refl)

FreudenthalEquiv :  {} (n : HLevel) (A : Pointed )
                 isConnected (2 + n) (typ A)
                 hLevelTrunc ((suc n) + (suc n)) (typ A)
                  hLevelTrunc ((suc n) + (suc n)) (typ (Ω (Susp (typ A) , north)))
FreudenthalEquiv n A iscon = connectedTruncEquiv _
                                                 (σ A)
                                                 (isConnectedσ _ iscon)
FreudenthalIso :  {} (n : HLevel) (A : Pointed )
                 isConnected (2 + n) (typ A)
                 Iso (hLevelTrunc ((suc n) + (suc n)) (typ A))
                      (hLevelTrunc ((suc n) + (suc n)) (typ (Ω (Susp (typ A) , north))))
FreudenthalIso n A iscon = connectedTruncIso _ (σ A) (isConnectedσ _ iscon)