{-# OPTIONS --safe --lossy-unification #-}

-- This file contains definition of CW complexes and skeleta.

module Cubical.CW.Base where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Function
open import Cubical.Foundations.Pointed

open import Cubical.Data.Nat renaming (_+_ to _+ℕ_)
open import Cubical.Data.Nat.Order
open import Cubical.Data.Fin.Inductive.Base
open import Cubical.Data.Sigma
open import Cubical.Data.Sequence
open import Cubical.Data.FinSequence

open import Cubical.HITs.Sn
open import Cubical.HITs.Pushout
open import Cubical.HITs.Susp
open import Cubical.HITs.SequentialColimit
open import Cubical.HITs.SphereBouquet
open import Cubical.HITs.PropositionalTruncation as PT

open import Cubical.Algebra.AbGroup
open import Cubical.Algebra.AbGroup.Instances.FreeAbGroup

open import Cubical.Relation.Nullary

open Sequence



private
  variable
     ℓ' : Level

--- CW complexes ---
-- Definition of (the skeleton) of an arbitrary CW complex
-- New def: X 0 is empty and C (suc n) is pushout
yieldsCWskel : (  Type )  Type 
yieldsCWskel X =
  Σ[ f  (  ) ]
    Σ[ α  ((n : )  (Fin (f n) × (S⁻ n))  X n) ]
      ((¬ X zero) ×
      ((n : )  X (suc n)  Pushout (α n) fst))

CWskel : ( : Level)  Type (ℓ-suc )
CWskel  = Σ[ X  (  Type ) ] (yieldsCWskel X)

module CWskel-fields (C : CWskel ) where
  card = C .snd .fst
  A = Fin  card
  α = C .snd .snd .fst
  e = C .snd .snd .snd .snd

  ℤ[A_] : (n : )  AbGroup ℓ-zero
  ℤ[A n ] = ℤ[Fin (snd C .fst n) ]

-- Technically, a CW complex should be the sequential colimit over the following maps
CW↪ : (T : CWskel )  (n : )  fst T n  fst T (suc n)
CW↪ (X , f , α , e₀ , e₊) n x = invEq (e₊ n) (inl x)

-- But if it stabilises, no need for colimits.
yieldsFinCWskel : (n : ) (X :   Type )  Type 
yieldsFinCWskel n X =
  Σ[ CWskel  yieldsCWskel X ] ((k : )  isEquiv (CW↪ (X , CWskel) (k +ℕ n)))

-- ... which should give us finite CW complexes.
finCWskel : ( : Level)  (n : )  Type (ℓ-suc )
finCWskel  n = Σ[ C  (  Type ) ] (yieldsFinCWskel n C)

finCWskel→CWskel : (n : )  finCWskel  n  CWskel 
finCWskel→CWskel n C = fst C , fst (snd C)

realiseSeq : CWskel   Sequence 
Sequence.obj (realiseSeq (C , p)) = C
Sequence.map (realiseSeq C) = CW↪ C _

realiseFinSeq : (m : )  CWskel   FinSequence m 
realiseFinSeq m C = Sequence→FinSequence m (realiseSeq C)

-- realisation of CW complex from skeleton
realise : CWskel   Type 
realise C = SeqColim (realiseSeq C)

-- Finally: definition of CW complexes
isCW : (X : Type )  Type (ℓ-suc )
isCW { = } X = Σ[ X'  CWskel  ] X  realise X'

CW : ( : Level)  Type (ℓ-suc )
CW  = Σ[ A  Type  ]  isCW A ∥₁

CWexplicit : ( : Level)  Type (ℓ-suc )
CWexplicit  = Σ[ A  Type  ] (isCW A)

-- Finite CW complexes
isFinCW : (X : Type )  Type (ℓ-suc )
isFinCW { = } X =
  Σ[ m   ] (Σ[ X'  finCWskel  m ] X  realise (finCWskel→CWskel m X'))

finCW : ( : Level)  Type (ℓ-suc )
finCW  = Σ[ A  Type  ]  isFinCW A ∥₁

finCW∙ : ( : Level)  Type (ℓ-suc )
finCW∙  = Σ[ A  Pointed  ]  isFinCW (fst A) ∥₁

finCWexplicit : ( : Level)  Type (ℓ-suc )
finCWexplicit  = Σ[ A  Type  ] (isFinCW A)

isFinCW→isCW : (X : Type )  isFinCW X  isCW X
isFinCW→isCW X (n , X' , str) = (finCWskel→CWskel n X') , str

finCW→CW : finCW   CW 
finCW→CW (X , p) = X , PT.map (isFinCW→isCW X) p


-- morphisms
_→ᶜʷ_ : CW   CW ℓ'  Type (ℓ-max  ℓ')
C →ᶜʷ D = fst C  fst D

--the cofibre of the inclusion of X n into X (suc n)
cofibCW :  {} (n : ) (C : CWskel )  Type 
cofibCW n C = cofib (CW↪ C n)

--...is basically a sphere bouquet
cofibCW≃bouquet :  {} (n : ) (C : CWskel )
   cofibCW n C  SphereBouquet n (Fin (snd C .fst n))
cofibCW≃bouquet n C = Bouquet≃-gen n (snd C .fst n) (α n) e
  where
  s = Bouquet≃-gen
  α = C .snd .snd .fst
  e = C .snd .snd .snd .snd n

--sending X (suc n) into the cofibCW
to_cofibCW : (n : ) (C : CWskel )  fst C (suc n)  cofibCW n C
to_cofibCW n C x = inr x

--the connecting map of the long exact sequence
δ-pre :  {A : Type } {B : Type ℓ'} (conn : A  B)
   cofib conn  Susp A
δ-pre conn (inl x) = north
δ-pre conn (inr x) = south
δ-pre conn (push a i) = merid a i

δ : (n : ) (C : CWskel )  cofibCW n C  Susp (fst C n)
δ n C = δ-pre (CW↪ C n)

-- send the stage n to the realization (the same as incl, but with explicit args and type)
CW↪∞ : (C : CWskel )  (n : )  fst C n  realise C
CW↪∞ C n x = incl x

CW↪Iterate :  {} (T : CWskel ) (n m : )  fst T n  fst T (m +ℕ n)
CW↪Iterate T n zero = idfun _
CW↪Iterate T n (suc m) x = CW↪ T (m +ℕ n) (CW↪Iterate T n m x)

finCW↑ : (n m : )  (m  n)  finCWskel  n  finCWskel  m
fst (finCW↑ m n p C) = fst C
fst (snd (finCW↑ m n p C)) = snd C .fst
snd (snd (finCW↑ m n p C)) k =
  subst  r  isEquiv (CW↪ (fst C , snd C .fst) r))
        (sym (+-assoc k (fst p) m)  cong (k +ℕ_) (snd p))
        (snd C .snd (k +ℕ fst p))