{-# OPTIONS --without-K --rewriting --overlapping-instances --instance-search-depth=4 #-}

open import lib.Basics
open import lib.Equivalence2 hiding (linv; rinv)
open import lib.Univalence2
open import lib.NType2
open import lib.types.Sigma
open import lib.types.LoopSpace
open import 2Semigroup
open import 2SGrpMap
open import 2Grp
open import PostMultMap

module Hmtpy2Grp where

-- homotopy 2-groups of 2-types (i.e., loop spaces)

module _ {i} {X : Type i} where

  module _ (x : X) {{trX : has-level 1 (x == x)}} where

    open CohGrp

    Loop2Grp : CohGrp (x == x)
    id Loop2Grp = idp
    mu Loop2Grp = _∙_
    lam Loop2Grp p = idp
    rho Loop2Grp = ∙-unit-r
    al Loop2Grp p₁ p₂ p₃ = ! (∙-assoc p₁ p₂ p₃)
    tr Loop2Grp = tri-id
    pent Loop2Grp = pent-id
    inv Loop2Grp = !
    linv Loop2Grp = !-inv-l
    rinv Loop2Grp p = ! (!-inv-r p)
    zz₁ Loop2Grp = zz-id1
    zz₂ Loop2Grp = zz-id2

  instance
    Loop2Grp-instance : {x : X} {{trX : has-level 1 (x == x)}}  CohGrp (x == x)
    Loop2Grp-instance {x} = Loop2Grp x

  module _ {j} {G : Type j} {{η : WkSGrp G}} (x : X) {{trX : has-level 1 (x == x)}} where

    open WkSGrp {{...}}
    
    record Loop2Map : Type (lmax i j) where
      constructor loop2map
      field
        loop' : G  x == x
        loop-comp' : (a b : G)  loop' a  loop' b == loop' (mu a b)
        loop-assoc' : (a b c : G)  
          ∙-assoc (loop' a) (loop' b) (loop' c) 
          ap  p  loop' a  p) (loop-comp' b c) 
          loop-comp' a (mu b c)
            ==
          ap  p  p  loop' c) (loop-comp' a b) 
          loop-comp' (mu a b) c ∙'
          ! (ap loop' (al a b c))
    open Loop2Map public
    
    record Loop2Map-∙ : Type (lmax i j) where
      constructor loop2map-∙
      field
        loop∙ : G  x == x
        loop-comp∙ : (a b : G)  loop∙ a  loop∙ b == loop∙ (mu a b)
        loop-assoc' : (a b c : G)  
          ∙-assoc (loop∙ a) (loop∙ b) (loop∙ c) 
          ap  p  loop∙ a  p) (loop-comp∙ b c) 
          loop-comp∙ a (mu b c)
            ==
          ap  p  p  loop∙ c) (loop-comp∙ a b) 
          loop-comp∙ (mu a b) c 
          ! (ap loop∙ (al a b c))
    open Loop2Map-∙ public

    loop-2map-forg : Loop2Map  WkSGrpWkHom {{η}} {{sgrp (Loop2Grp x)}}
    map-wk (loop-2map-forg f) = loop' f
    map-comp-wk (loop-2map-forg f) = loop-comp' f

    open WkSGrpHom
    open WkSGrpHomStr {{...}}
    
    wksgrp-to-loop : WkSGrpHom {{η}} {{sgrp (Loop2Grp x)}}  Loop2Map
    loop' (wksgrp-to-loop f) = map f
    loop-comp' (wksgrp-to-loop _) = map-comp
    loop-assoc' (wksgrp-to-loop f) a b c = =ₛ-out $
      ∙-assoc (map f a) (map f b) (map f c) ◃∙
      ap  p  map f a  p) (map-comp b c) ◃∙
      map-comp a (mu b c) ◃∎
        =ₛ₁⟨ 0 & 1 & ! (!-! (∙-assoc (map f a) (map f b) (map f c))) 
      ! (! (∙-assoc (map f a) (map f b) (map f c))) ◃∙
      ap  p  map f a  p) (map-comp b c) ◃∙
      map-comp a (mu b c) ◃∎
        =ₛ⟨ =ₛ-in (map-al a b c) 
      ap  p  p  map f c) (map-comp a b) ◃∙
      (map-comp (mu a b) c 
      ! (ap (map f) (al a b c))) ◃∎
        =ₛ₁⟨ 1 & 1 & ∙=∙' (map-comp (mu a b) c) (! (ap (map f) (al a b c))) 
      ap  p  p  map f c) (map-comp a b) ◃∙
      (map-comp (mu a b) c ∙'
      ! (ap (map f) (al a b c))) ◃∎
        =ₛ₁⟨ idp 
      (ap  p  p  map f c) (map-comp a b) 
      map-comp (mu a b) c ∙'
      ! (ap (map f) (al a b c))) ◃∎ ∎ₛ

    loop-to-wksgrp : Loop2Map-∙  WkSGrpHom {{η}} {{sgrp (Loop2Grp x)}}
    map (loop-to-wksgrp f) = loop∙ f
    WkSGrpHomStr.map-comp (str (loop-to-wksgrp f)) = loop-comp∙ f
    WkSGrpHomStr.map-al (str (loop-to-wksgrp f)) a b c = =ₛ-out $
      ! (! (∙-assoc (loop∙ f a) (loop∙ f b) (loop∙ f c))) ◃∙
      ap (_∙_ (loop∙ f a)) (loop-comp∙ f b c) ◃∙
      loop-comp∙ f a (mu b c) ◃∎
        =ₛ₁⟨ 0 & 1 & !-! (∙-assoc (loop∙ f a) (loop∙ f b) (loop∙ f c)) 
      ∙-assoc (loop∙ f a) (loop∙ f b) (loop∙ f c) ◃∙
      ap (_∙_ (loop∙ f a)) (loop-comp∙ f b c) ◃∙
      loop-comp∙ f a (mu b c) ◃∎
        =ₛ⟨ =ₛ-in (loop-assoc' f a b c) 
      ap  p  p  loop∙ f c) (loop-comp∙ f a b) ◃∙
      (loop-comp∙ f (WkSGrp.mu η a b) c 
      ! (ap (loop∙ f) (WkSGrp.al η a b c))) ◃∎
        =ₛ₁⟨ idp 
      (ap  v  v  loop∙ f c) (loop-comp∙ f a b) 
      loop-comp∙ f (mu a b) c 
      ! (ap (loop∙ f) (al a b c))) ◃∎ ∎ₛ

-- a few ad-hoc lemmas for Ω's action on  maps, described below

module RA1 {i j} {X : Type i} {Y : Type j} (f : X  Y) where

  abstract
    red-aux1 : {x y z w : X} (p₁ : x == y) (p₂ : y == z) (p₃ : z == w) 
      ! (! (∙-assoc (ap f p₁) (ap f p₂) (ap f p₃))) 
      ap (_∙_ (ap f p₁)) (∙-ap f p₂ p₃) 
      ∙-ap f p₁ (p₂  p₃)
      ==
      ap  v  v  ap f p₃) (∙-ap f p₁ p₂) 
      ∙-ap f (p₁  p₂) p₃ 
      ! (ap (ap f) (! (∙-assoc p₁ p₂ p₃)))
    red-aux1 idp idp _ = idp

    red-aux2 :  {k} {Z : Type k} (g : Y  Z) {x y z : X}
      (p₁ : x == y) (p₂ : y == z)  
      ∙-ap g (ap f p₁) (ap f p₂) 
      ap (ap g) (∙-ap f p₁ p₂)
      ==
      ! (ap2 _∙_ (ap-∘ g f p₁) (ap-∘ g f p₂)) 
      ∙-ap (g  f) p₁ p₂ 
      ap-∘ g f (p₁  p₂)
    red-aux2 g idp idp = idp

open RA1 public

module RA2 {i} {X : Type i} where

  abstract
    red-aux3 : {x y z : X} (p₁ : x == y) (p₂ : y == z)
      
      idp
      ==
      ! (ap2 _∙_ (ap-idf p₁) (ap-idf p₂))  ∙-ap  x  x) p₁ p₂  ap-idf (p₁  p₂)
    red-aux3 idp idp = idp

open RA2 public

open CohGrpHom
open WkSGrpHomStr

module _ {i j} {X₁ : Ptd i} {X₂ : Ptd j}
  {{tr₁ : has-level 2 (de⊙ X₁)}} {{tr₂ : has-level 2 (de⊙ X₂)}} where

  Loop2Grp-map-str : (φ : X₁ ⊙→ X₂)  CohGrpHomStr (Ω-fmap φ)
  map-comp (Loop2Grp-map-str φ) p₁ p₂ = ∙-Ω-fmap φ p₁ p₂
  map-al (Loop2Grp-map-str (f , idp)) p₁ p₂ p₃ = red-aux1 f p₁ p₂ p₃ 

  Loop2Grp-map : (φ : X₁ ⊙→ X₂)  CohGrpHom
  map (Loop2Grp-map φ) = Ω-fmap φ
  str (Loop2Grp-map φ) = Loop2Grp-map-str φ

module _ {i j k} {X₁ : Ptd i} {X₂ : Ptd j} {X₃ : Ptd k} {{tr₁ : has-level 2 (de⊙ X₁)}}
  {{tr₂ : has-level 2 (de⊙ X₂)}} {{tr₃ : has-level 2 (de⊙ X₃)}} where

  Loop2Grp-map-∘ : (φ₂ : X₂ ⊙→ X₃) (φ₁ : X₁ ⊙→ X₂)
      CohGrpNatIso (Loop2Grp-map (φ₂ ⊙∘ φ₁)) (Loop2Grp-map φ₂ ∘2G Loop2Grp-map φ₁)
  WkSGrpNatIso.θ (Loop2Grp-map-∘ (f₂ , idp) (f₁ , idp)) = λ p  ap-∘ f₂ f₁ p
  WkSGrpNatIso.θ-comp (Loop2Grp-map-∘ (f₂ , idp) (f₁ , idp)) = λ p₁ p₂  red-aux2 f₁ f₂ p₁ p₂

module _ {i} (X : Ptd i) {{tr : has-level 2 (de⊙ X)}} where

  Loop2Grp-map-idf : CohGrpNatIso (Loop2Grp-map (⊙idf X)) (cohgrphom _ {{idf2G}})
  WkSGrpNatIso.θ Loop2Grp-map-idf p = ap-idf p
  WkSGrpNatIso.θ-comp Loop2Grp-map-idf p₁ p₂ = red-aux3 p₁ p₂

module _ {i} (G : Type i) {{trG : has-level 1 G}} where

  open WkSGrp {{...}}
  open WkSGrpHom
  open WkSGrpHomStr {{...}}

  ua-2SGrpMap : WkSGrpHom {{≃-2SGrp G}} {{sgrp (Loop2Grp G)}}
  map ua-2SGrpMap = ua
  map-comp (str ua-2SGrpMap) e₁ e₂ = ! (ua-∘e e₁ e₂)
  map-al (str ua-2SGrpMap) e₁ e₂ e₃ = =ₛ-out $
    ! (! (∙-assoc (ua e₁) (ua e₂) (ua e₃))) ◃∙
    ap  v  ua e₁  v) (! (ua-∘e e₂ e₃)) ◃∙
    ! (ua-∘e e₁ (e₃ ∘e e₂)) ◃∎
      =ₛ₁⟨ 0 & 1 & !-! (∙-assoc (ua e₁) (ua e₂) (ua e₃))  
    _
      =ₛ⟨ ua-∘e-al e₁ e₂ e₃ 
    ap  v  v  ua e₃) (! (ua-∘e e₁ e₂)) ◃∙
    ! (ua-∘e (e₂ ∘e e₁) e₃) ◃∙
    ! (ap ua (pair= idp (prop-has-all-paths _ _))) ◃∎ ∎ₛ

  1tr-2SGrpMap : WkSGrpHom {{sgrp (Loop2Grp G)}} {{sgrp (Loop2Grp {X = 1 -Type i} (G , trG))}}
  map 1tr-2SGrpMap p = pair= p prop-has-all-paths-↓
  map-comp (str 1tr-2SGrpMap) p₁ p₂ =
    Σ-∙ {B = has-level 1} {p = p₁} {p' = p₂} prop-has-all-paths-↓ prop-has-all-paths-↓ 
    ap (pair= (p₁  p₂)) (prop-has-all-paths {{↓-level}} _ _)
  map-al (str 1tr-2SGrpMap) p₁ p₂ p₃ = lemma p₁ p₂ p₃
    where
      lemma : {A₁ A₂ A₃ A₄ : Type i} (q₁ : A₁ == A₂) (q₂ : A₂ == A₃) (q₃ : A₃ == A₄)
        {d₁ : has-level 1 A₁} {d₂ : has-level 1 A₂} {d₃ : has-level 1 A₃} {d₄ : has-level 1 A₄}
        {t₁ : d₁ == d₂ [ has-level 1  q₁ ]} {t₂ : d₂ == d₃ [ has-level 1  q₂ ]}
        {t₃ : d₃ == d₄ [ has-level 1  q₃ ]} {t₈ : d₂ == d₄ [ has-level 1  (q₂  q₃) ]}
        {t₄ : d₁ == d₃ [ has-level 1  (q₁  q₂) ]} {t₅ : (p : A₁ == A₄)  _}
        {t₆ : t₁ ∙ᵈ t₂ == t₄} {t₇ : t₂ ∙ᵈ t₃ == t₈} {t₉ : t₁ ∙ᵈ t₈ == t₅ (q₁  q₂  q₃)}
        {t₁₀ : t₄ ∙ᵈ t₃ == t₅ ((q₁  q₂)  q₃)} 
        ! (! (∙-assoc (pair= q₁ t₁) (pair= q₂ t₂) (pair= q₃ t₃))) 
        ap (_∙_ (pair= q₁ t₁))
          (Σ-∙ {B = has-level 1} {p = q₂} {p' = q₃} t₂ t₃ 
          ap (pair= (q₂  q₃)) t₇) 
        Σ-∙ {B = has-level 1} {p = q₁} {p' = q₂  q₃} t₁ t₈ 
        ap (pair= (q₁  q₂  q₃)) t₉
          ==
        ap  v  v  pair= q₃ t₃)
          (Σ-∙ {B = has-level 1} {p = q₁} {p' = q₂} t₁ t₂ 
          ap (pair= (q₁  q₂)) t₆) 
        (Σ-∙ {B = has-level 1} {p = q₁  q₂} {p' = q₃} t₄ t₃ 
        ap (pair= ((q₁  q₂)  q₃)) t₁₀) 
        ! (ap  p  pair= p (t₅ p)) (! (∙-assoc q₁ q₂ q₃)))
      lemma {A₁} idp idp idp {t₁ = t₁} {t₂} {t₃} {t₆ = idp} {t₇ = idp} {t₉} {t₁₀} = aux t₁ t₂ t₃ t₉ t₁₀
        where
          aux : {x₁ x₂ x₃ x₄ : has-level 1 A₁}
            (r₁ : x₁ == x₂) (r₂ : x₂ == x₃) (r₃ : x₃ == x₄)
            {z : x₁ == x₄} (r₄ : r₁  r₂  r₃ == z) (r₅ : (r₁  r₂)  r₃ == z)
                        
            ! (! (∙-assoc (ap (A₁ ,_) r₁) (ap (A₁ ,_) r₂) (ap (A₁ ,_) r₃))) 
            ap (_∙_ (ap (A₁ ,_) r₁)) (Σ-∙-aux r₂ r₃  idp) 
            Σ-∙-aux r₁ (r₂  r₃)  ap (ap (A₁ ,_)) r₄
            ==
            ap  v  v  ap (A₁ ,_) r₃) (Σ-∙-aux r₁ r₂  idp) 
            (Σ-∙-aux (r₁  r₂) r₃  ap (ap (A₁ ,_)) r₅)  idp
          aux idp idp idp idp r₅ =
            ! (ap  p  ap (ap (A₁ ,_)) p  idp)
              (prop-has-all-paths {{=-preserves-level-instance {{=-preserves-level-instance}}}} r₅ idp))

module _ {i} {G : Type i} {{η : CohGrp G}} where

  open CohGrp η

  2Grp-1Ty-map : WkSGrpHom {{sgrp η}} {{sgrp (Loop2Grp (G , 1trunc))}}
  2Grp-1Ty-map = 1tr-2SGrpMap G ∘2M ua-2SGrpMap G ∘2M mu-≃-map

  2Grp-1Ty-lmap : Loop2Map (G , 1trunc)
  2Grp-1Ty-lmap = wksgrp-to-loop (G , 1trunc) 2Grp-1Ty-map

  fst=-2map : WkSGrpWkHom {{sgrp (Loop2Grp (G , 1trunc))}} {{sgrp (Loop2Grp G)}}
  map-wk fst=-2map = fst=
  map-comp-wk fst=-2map p₁ p₂ = ∙-ap fst p₁ p₂