open import GpdCont.Prelude
module GpdCont.SetBundle.Base ( : Level) where

open import GpdCont.TwoCategory.Base
open import GpdCont.TwoCategory.Displayed.Base using (TwoCategoryStrᴰ ; TwoCategoryᴰ)
open import GpdCont.TwoCategory.Displayed.LocallyThin as LT using (IsLocallyThinOver ; LocallyThinOver)
open import GpdCont.TwoCategory.HomotopyGroupoid
open import GpdCont.TwoCategory.Isomorphism using (module LocalIso)


open import Cubical.Foundations.HLevels
open import Cubical.Data.Sigma using (ΣPath≃PathΣ)

{-# INJECTIVE_FOR_INFERENCE ⟨_⟩ #-}

private
  module hGpdCat = TwoCategory (hGpdCat )
  variable
    G H K : hGpdCat.ob
    φ ψ ρ : hGpdCat.hom G H

  S₀ : hGpdCat.ob  Type _
  S₀ G =  G   hSet 

  S₁ : {G H : hGpdCat.ob} (φ : hGpdCat.hom G H) (X : S₀ G) (Y : S₀ H)  Type _
  S₁ φ X Y =  g   Y (φ g)    X g 

  S₂ :  {G H} {φ ψ : hGpdCat.hom G H}
     {X : S₀ G} {Y : S₀ H}
     (p : φ  ψ)
     (φᴰ : S₁ φ X Y) (ψᴰ : S₁ ψ X Y)
     Type 
  S₂ {X} {Y} p φᴰ ψᴰ = PathP  i   g   Y (p i g)    X g ) φᴰ ψᴰ

  {-# INJECTIVE_FOR_INFERENCE S₁ #-}
  {-# INJECTIVE_FOR_INFERENCE S₂ #-}

  isProp-S₂ :  {G H} {φ ψ : hGpdCat.hom G H}
     {X : S₀ G} {Y : S₀ H}
     (p : φ  ψ)
     (φᴰ : S₁ φ X Y) (ψᴰ : S₁ ψ X Y)
     isProp (S₂ {Y = Y} p φᴰ ψᴰ)
  isProp-S₂ {X} {Y} p = isOfHLevelPathP' {A = Motive} 1 isSetMotive where
    Motive : (i : I)  Type _
    Motive i =  g   Y (p i g)    X g 

    isSetMotive : isSet (Motive i1)
    isSetMotive = isSetΠ λ g  isSet→ (str (X g))

  variable
    X : S₀ G
    Y : S₀ H

  S₁-id :  {G} (X : S₀ G)  S₁ (hGpdCat.id-hom G) X X
  S₁-id X g = id  X g 

  S₁-comp :  {G H K : hGpdCat.ob} {φ : hGpdCat.hom G H} {ψ : hGpdCat.hom H K}
     {X : S₀ G} {Y : S₀ H} {Z : S₀ K}
     S₁ φ X Y  S₁ ψ Y Z  S₁ (φ hGpdCat.∙₁ ψ) X Z
  S₁-comp {φ} φᴰ ψᴰ = λ g  ψᴰ (φ g)  φᴰ g

  S₂-id :  (φᴰ : S₁ φ X Y)  S₂ {Y = Y} (refl′ φ) φᴰ φᴰ
  S₂-id = refl′

  S₂-trans :  {X : S₀ G} {Y : S₀ H} {φᴰ : S₁ φ X Y} {ψᴰ : S₁ ψ X Y} {ρᴰ : S₁ ρ X Y}
     {p : φ  ψ} {q : ψ  ρ}
     S₂ {Y = Y} p φᴰ ψᴰ
     S₂ {Y = Y} q ψᴰ ρᴰ
     S₂ {Y = Y} (p  q) φᴰ ρᴰ
  S₂-trans {G} {H} {X} {Y} pᴰ qᴰ = compPathP' {A = hGpdCat.hom G H} {B = λ φ  S₁ φ X Y} pᴰ qᴰ

  -- Ahh yes, horizontal composition of dependent paths. What a beauty.
  -- This is defined in terms of horizontal composition of 1-cells:
  -- 2-cells (pᴰ : φ₁ᴰ ⇒ φ₂ᴰ), (qᴰ : ψ₁ᴰ ⇒ ψ₂ᴰ) are homotopies between 1-cells.
  -- Thus, at each point (i : I) along the homotopy, we can compose the 1-cells
  -- (pᴰ i : X → Y) and (qᴰ i : Y → Z).
  S₂-comp :  {G H K : hGpdCat.ob}
     {φ₁ φ₂ : hGpdCat.hom G H}
     {ψ₁ ψ₂ : hGpdCat.hom H K}
     {p : φ₁  φ₂}
     {q : ψ₁  ψ₂}
     {X : S₀ G} {Y : S₀ H} {Z : S₀ K}
     {φ₁ᴰ : S₁ φ₁ X Y}
     {φ₂ᴰ : S₁ φ₂ X Y}
     {ψ₁ᴰ : S₁ ψ₁ Y Z}
     {ψ₂ᴰ : S₁ ψ₂ Y Z}
     (pᴰ : S₂ {Y = Y} p φ₁ᴰ φ₂ᴰ)
     (qᴰ : S₂ {Y = Z} q ψ₁ᴰ ψ₂ᴰ)
     S₂ {φ = φ₁ hGpdCat.∙₁ ψ₁} {ψ = φ₂ hGpdCat.∙₁ ψ₂} {Y = Z} (p hGpdCat.∙ₕ q)
      (S₁-comp {φ = φ₁} {ψ = ψ₁} {Z = Z} φ₁ᴰ ψ₁ᴰ)
      (S₁-comp {φ = φ₂} {ψ = ψ₂} {Z = Z} φ₂ᴰ ψ₂ᴰ)
  S₂-comp {p} {q} {Z} pᴰ qᴰ i = S₁-comp {φ = p i} {ψ = q i} {Z = Z} (pᴰ i) (qᴰ i)

  SetBundleStrᴰ : TwoCategoryStrᴰ (hGpdCat ) (ℓ-suc )   S₀ S₁ S₂
  SetBundleStrᴰ .TwoCategoryStrᴰ.id-homᴰ = S₁-id
  SetBundleStrᴰ .TwoCategoryStrᴰ.comp-homᴰ = S₁-comp
  SetBundleStrᴰ .TwoCategoryStrᴰ.id-relᴰ = S₂-id
  SetBundleStrᴰ .TwoCategoryStrᴰ.transᴰ = S₂-trans
  SetBundleStrᴰ .TwoCategoryStrᴰ.comp-relᴰ = S₂-comp

  isLocallyThinBundleOver : IsLocallyThinOver (hGpdCat ) _ _ _ S₀ S₁ S₂ SetBundleStrᴰ
  isLocallyThinBundleOver .IsLocallyThinOver.is-prop-relᴰ {s} = isProp-S₂ s
  isLocallyThinBundleOver .IsLocallyThinOver.comp-hom-assocᴰ fᴰ gᴰ hᴰ = refl
  isLocallyThinBundleOver .IsLocallyThinOver.comp-hom-unit-leftᴰ gᴰ = refl
  isLocallyThinBundleOver .IsLocallyThinOver.comp-hom-unit-rightᴰ fᴰ = refl

SetBundleᵀ : LocallyThinOver (hGpdCat ) (ℓ-suc )  
SetBundleᵀ .LocallyThinOver.ob[_] = S₀
SetBundleᵀ .LocallyThinOver.hom[_] = S₁
SetBundleᵀ .LocallyThinOver.rel[_] {yᴰ = Y} = S₂ {Y = Y}
SetBundleᵀ .LocallyThinOver.two-category-structureᴰ = SetBundleStrᴰ
SetBundleᵀ .LocallyThinOver.is-locally-thinᴰ = isLocallyThinBundleOver

SetBundleᴰ : TwoCategoryᴰ (hGpdCat ) (ℓ-suc )  
SetBundleᴰ = LocallyThinOver.toTwoCategoryᴰ SetBundleᵀ

SetBundle : TwoCategory (ℓ-suc )  
SetBundle = LT.TotalTwoCategory.∫ (hGpdCat ) SetBundleᵀ

private
  module SetBundleᴰ = TwoCategoryᴰ SetBundleᴰ
  module SetBundle = TwoCategory SetBundle

SetBundle₂≃Path :  {x y} {f g : SetBundle.hom x y}  (SetBundle.rel {y = y} f g)  (f  g)
SetBundle₂≃Path = ΣPath≃PathΣ

module SetBundleNotation where
  open TwoCategory SetBundle public
  open TwoCategoryᴰ SetBundleᴰ public
  open LocallyThinOver SetBundleᵀ public using (relᴰPathP ; relᴰ≡ ; relΣPathP ; is-prop-relᴰ)

  Base : ob  hGroupoid 
  Base = fst

  isGroupoidBase : (x : ob)  isGroupoid  Base x 
  isGroupoidBase = str  fst

  isSetHomᴰ :  {x y : hGpdCat.ob} (f : hGpdCat.hom x y) (xᴰ : ob[ x ]) (yᴰ : ob[ y ])  isSet (hom[ f ] xᴰ yᴰ)
  isSetHomᴰ f xᴰ _ = isSetΠ2 λ j _  str (xᴰ j)

  Fiber : (x : ob) (b :  Base x )  hSet 
  Fiber (B , F) b = F b

  homBase[_,_] : (x y : ob) (f : hom x y)   Base x    Base y 
  homBase[_,_] x y = fst

  homBase : {x y : ob} (f : hom x y)   Base x    Base y 
  homBase {x} {y} = homBase[ x , y ]

  homFiber[_,_] : (x y : ob) (f : hom x y)  (b :  Base x )   Fiber y (homBase[ x , y ] f b)    Fiber x b 
  homFiber[_,_] x y = snd

  homFiber : {x y : ob} (f : hom x y)  (b :  Base x )   Fiber y (homBase[ x , y ] f b)    Fiber x b 
  homFiber {x} {y} = homFiber[ x , y ]

isLocallyGroupoidalSetBundle : LocalIso.isLocallyGroupoidal SetBundle
isLocallyGroupoidalSetBundle {x = G , X} {y = H , Y} {f = f , fᴰ} {g = g , gᴰ} (r , rᴰ) = goal where
  open import Cubical.Data.Sigma using (ΣPathP)

  r-inv : LocalIso.hasLocalInverse (hGpdCat _) r
  r-inv = isLocallyGroupoidalHGpdCat _ r

  module r-inv = LocalIso.isLocalInverse (r-inv .snd)

  r⁻ : hGpdCat.rel g f
  r⁻ = r-inv .fst

  rᴰ⁻ : S₂ {Y = Y} r⁻ gᴰ fᴰ
  rᴰ⁻ = symP rᴰ

  goal : LocalIso.hasLocalInverse SetBundle (r , rᴰ)
  goal .fst = r⁻ , rᴰ⁻
  goal .snd .LocalIso.isLocalInverse.dom-id i .fst = r-inv.dom-id i
  goal .snd .LocalIso.isLocalInverse.dom-id i .snd = rCancelP'  φ  S₁ φ X Y) r rᴰ i
  goal .snd .LocalIso.isLocalInverse.codom-id i .fst = r-inv.codom-id i
  goal .snd .LocalIso.isLocalInverse.codom-id i .snd = lCancelP'  φ  S₁ φ X Y) r rᴰ i

private module Sanity where
  sanity₀ : (SetBundle.ob)  (Σ[ G  hGroupoid  ] ( G   hSet ))
  sanity₀ = refl

  sanity₁ :  {X Y} {Xᴰ Yᴰ}  (SetBundle.hom (X , Xᴰ) (Y , Yᴰ))  (Σ[ f  ( X    Y ) ]  g   Yᴰ (f g)    Xᴰ g )
  sanity₁ = refl

  sanity₂ :  {X Y : SetBundle.ob} {f g : SetBundle.hom X Y} 
    (SetBundle.rel {y = Y} f g)  (Σ[ p  f .fst  g .fst ] PathP  i  (g : fst (X .fst))  fst (Y .snd (p i g))  fst (X .snd g)) (f .snd) (g .snd))
  sanity₂ = refl