{-# OPTIONS --lossy-unification #-}
{-
This file contains
1. A 'strictification' functor
   strictCWskel : CWskel -> CWskel s.t. strictCWskel C ≡ C
   the strictified version of C satisfies the pushout condition
   definitionally
2. The same thing for cellular maps
-}
module Cubical.CW.Strictification where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.GroupoidLaws
open import Cubical.Foundations.Function
open import Cubical.Foundations.Univalence

open import Cubical.Data.Empty as 
open import Cubical.Data.Fin.Inductive.Base
open import Cubical.Data.Sigma
open import Cubical.Data.Sequence
open import Cubical.Data.Nat

open import Cubical.HITs.Sn
open import Cubical.HITs.Pushout

open import Cubical.CW.Base
open import Cubical.CW.Map

open SequenceMap renaming (map to ∣_∣)
open CWskel-fields


-- Strictification of CW skels
module _ { : Level} (B : CWskel ) where
  open CWskel-fields
  strictifyFam :   Type 
  strictifyFam≡ : (n : )  strictifyFam n  fst B n
  strictifyFame : (n : )  fst B n  strictifyFam n
  strictifyFamα : (n : )  Fin (fst (B .snd) n) × S⁻ n  strictifyFam n
  strictifyFame2 : (n : )
     (Pushout (α B n) fst)  (Pushout (strictifyFamα n) fst)
  strictifyFam zero = fst B 0
  strictifyFam (suc n) = Pushout (strictifyFamα n) fst
  strictifyFamα n = fst (strictifyFame n)  α B n
  strictifyFame zero = idEquiv _
  strictifyFame (suc n) =
    compEquiv (e B n)
              (strictifyFame2 n)
  strictifyFame2 n =
    pushoutEquiv _ _ _ _ (idEquiv _) (strictifyFame n) (idEquiv _)
                    _ x  fst (strictifyFame n) (α B n x))
                    _ x  fst x)
  strictifyFam≡ zero = refl
  strictifyFam≡ (suc n) = ua (invEquiv (strictifyFame (suc n)))

  strictCWskel : CWskel 
  fst strictCWskel = strictifyFam
  fst (snd strictCWskel) = card B
  fst (snd (snd strictCWskel)) = strictifyFamα
  fst (snd (snd (snd strictCWskel))) = fst (snd (snd (snd B)))
  snd (snd (snd (snd strictCWskel))) = λ _  idEquiv _

  strict≡Gen :  { ℓ'} {A : Type } {C D : Type ℓ'}
    (α : A  C) (e : C  D) (x : A)
     PathP  i  ua (invEquiv e) i) (fst e (α x)) (α x)
  strict≡Gen α e x i =
    hcomp  k  λ {(i = i0)  fst e (α x)
                   ; (i = i1)  retEq e (α x) k})
          (ua-gluePt (invEquiv e) i (fst e (α x)))

  strict≡GenT' :  { ℓ' ℓ''} {A : Type } {B : Type ℓ'} {C D : Type ℓ''}
    {E : Type (ℓ-max  (ℓ-max ℓ' ℓ''))} (g : A  B)
    (e : C  D)  (α : A  C) (e' : E  Pushout  x₁  α x₁) g)
     PathP  k  ua (invEquiv (compEquiv {C = Pushout (fst e  α) g} e'
                       (pushoutEquiv _ _ _ _ (idEquiv A) e (idEquiv B)
                          i x  fst e (α x)) λ i x  g x))) k
                  Pushout  x₁  strict≡Gen α e x₁ k) g)
            (idEquiv _)
            e'
  strict≡GenT' {A = A} {B} {C} {D} {E} g =
    EquivJ  C e  (α : A  C) (e' : E  Pushout  x₁  α x₁) g)
     PathP  k  ua (invEquiv (compEquiv {C = Pushout (fst e  α) g} e'
                       (pushoutEquiv _ _ _ _ (idEquiv A) e (idEquiv B)
                          i x  fst e (α x)) λ i x  g x))) k
                   Pushout  x₁  strict≡Gen α e x₁ k) g)
            (idEquiv _) e') λ a 
     EquivJ  E e'
     PathP  k  ua (invEquiv (compEquiv e'
                         (pushoutEquiv a g a g (idEquiv A) (idEquiv D) (idEquiv B)
                            i x  a x)  i  g)))) k
                   Pushout  x₁  strict≡Gen a (idEquiv D) x₁ k) g)
                     (idEquiv (Pushout  x  idfun D (a x)) g)) e')
      (ΣPathPProp isPropIsEquiv
        (transport  k
     PathP  i  (sym (lem g a)
                    sym (cong (ua  invEquiv) (compEquivIdEquiv (pushoutEquiv a g
                        z  idfun D (a z)) g (idEquiv A) (idEquiv D)
                         (idEquiv B)  i₁ x  idfun D (a x))  i₁  g))))) k i
                   Pushout  x₁  strict≡GenId a x₁ (~ k) i) g)
             (idfun _) (idfun _))
        (funExt (main _ _))))
    where
    strict≡GenId :  { ℓ'} {A : Type } {C : Type ℓ'} (α : A  C)(x : A)
        strict≡Gen α (idEquiv C) x
        λ i  ua-gluePt (invEquiv (idEquiv C)) i (α x)
    strict≡GenId {C = C} α x j i =
      hcomp  k  λ {(i = i0)  α x
                     ; (i = i1)  α x
                     ; (j = i1)  ua-gluePt (invEquiv (idEquiv C)) i (α x)})
            (ua-gluePt (invEquiv (idEquiv C)) i (α x))

    lem : (g : A  B) (α : A  D)
       ua (invEquiv (pushoutEquiv α g α g
                       (idEquiv A) (idEquiv D) (idEquiv B) refl refl))
       refl
    lem g a = cong ua
      (cong invEquiv (Σ≡Prop isPropIsEquiv {v = idEquiv _}
                       (funExt λ { (inl x)  refl ; (inr x)  refl
                                 ; (push a i) j  rUnit (push a) (~ j) i}))
                        invEquivIdEquiv _)  uaIdEquiv

    main : (g : A  B) (α : A  D) (w : _)
       PathP  i  Pushout  s  ua-gluePt (invEquiv (idEquiv D)) i (α s)) g)
               w w
    main g α (inl x) i = inl (ua-gluePt (invEquiv (idEquiv D)) i x)
    main g α (inr x) i = inr x
    main g α (push a j) i = push a j

  strict≡α : (n : ) (x : Fin (card B n)) (y : S⁻ n)
     PathP  i  strictifyFam≡ n i)

              (strictifyFamα n (x , y))
              (α B n (x , y))
  strict≡α (suc n) x y =
    strict≡Gen (α B (suc n)) (strictifyFame (suc n)) (x , y)

  strict≡e : (n : )
     PathP  i  strictifyFam≡ (suc n) i
                    Pushout  x  strict≡α n (fst x) (snd x) i) fst)
             (idEquiv _) (e B n)
  strict≡e zero =
    ΣPathPProp  _  isPropIsEquiv _)
    (symP (toPathP (funExt
     λ { (inl x)  ⊥.rec (B .snd .snd .snd .fst x)
       ; (inr x)
          cong (transport  i  Pushout  s  strict≡α zero
                                                    (fst s) (snd s) (~ i)) fst))
                (cong (e B 0 .fst) (transportRefl (invEq (e B 0) (inr x)))
               secEq (e B 0) (inr x))
           λ j  inr (transportRefl x j)})))
  strict≡e (suc n) =
    strict≡GenT' fst (strictifyFame (suc n)) (α B (suc n)) (e B (suc n))

  strict≡ : strictCWskel  B
  fst (strict≡ i) n = strictifyFam≡ n i
  fst (snd (strict≡ i)) = card B
  fst (snd (snd (strict≡ i))) n (x , y) = strict≡α n x y i
  fst (snd (snd (snd (strict≡ i)))) = fst (snd (snd (snd B)))
  snd (snd (snd (snd (strict≡ i)))) n = strict≡e n i

-- Associated elimination principle
module _ { ℓ'} {P : CWskel   Type ℓ'}
  (e : (B : CWskel )  P (strictCWskel B)) where

  elimStrictCW : (B : _)  P B
  elimStrictCW B = subst P (strict≡ B) (e B)

  elimStrictCWβ : (B : _)  elimStrictCW (strictCWskel B)  e B
  elimStrictCWβ B =
     j  subst P  i  H strictCWskel (funExt  x  sym (strict≡ x))) B i j)
                 (e (strict≡ B j)))
     transportRefl (e B)
    where
    H :  {} {A : Type }  (F : A  A) (s :  x  x)  F) (a : A)
       Square  i  F (s (~ i) a)) refl  i  s (~ i) (F a)) refl
    H = J> λ _  refl

-- Strictification of cellular maps
module _ { ℓ'} {C : CWskel } {D : CWskel ℓ'}
  (f : cellMap (strictCWskel C) (strictCWskel D)) where

  strictMapFun : (n : )  strictifyFam C n  strictifyFam D n
  strictMapComm : (n : ) (x : strictifyFam C n) 
      strictMapFun n x   f  n x
  strictMapFun zero x =  f  0 x
  strictMapFun (suc n) (inl x) = inl (strictMapFun n x)
  strictMapFun (suc n) (inr x) =  f  (suc n) (inr x)
  strictMapFun (suc (suc n)) (push c i) =
    (((λ i  inl (strictMapComm (suc n) (α (strictCWskel C) (suc n) c) i))
         comm f (suc n) (α (strictCWskel C) (suc n) c))
         cong ( f  (suc (suc n))) (push c)) i
  strictMapComm zero x = refl
  strictMapComm (suc n) (inl x) =  i  inl (strictMapComm n x i))  comm f n x
  strictMapComm (suc n) (inr x) = refl
  strictMapComm (suc (suc n)) (push c i) j =
    compPath-filler'
      ((λ i  inl (strictMapComm (suc n) (α (strictCWskel C) (suc n) c) i))
         comm f (suc n) (α (strictCWskel C) (suc n) c))
      (cong ( f  (suc (suc n))) (push c)) (~ j) i

  strictCwMap : cellMap (strictCWskel C) (strictCWskel D)
  SequenceMap.map strictCwMap = strictMapFun
  SequenceMap.comm strictCwMap n x = refl

  strictCwMap≡ : strictCwMap  f
  ∣_∣ (strictCwMap≡ i) n x = strictMapComm n x i
  comm (strictCwMap≡ i) n x j =
   compPath-filler ((λ i₁  inl (strictMapComm n x i₁))) (comm f n x) j i