{-# OPTIONS --lossy-unification #-}
module GpdCont.ActionContainer.Base where

open import GpdCont.Prelude
open import GpdCont.Univalence using (ua ; uaCompEquiv ; uaCompEquivSquare)
open import GpdCont.Group.SymmetricGroup
open import GpdCont.GroupAction.Base

open import Cubical.Foundations.Equiv
open import Cubical.Foundations.Function using (uncurry4 ; uncurry3)
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Algebra.Group.Base
open import Cubical.Algebra.Group.Properties using (isPropIsGroup)
open import Cubical.Algebra.Group.Morphisms using (GroupHom ; IsGroupHom)
open import Cubical.Algebra.Group.MorphismProperties using (makeIsGroupHom ; compGroupHom ; isPropIsGroupHom)

record ActionContainer ( : Level) : Type (ℓ-suc ) where
  no-eta-equality
  field
    Shape : Type 
    Pos : (s : Shape)  Type 
    Symm : (s : Shape)  Type 
    action : {s : Shape}  Symm s  (Pos s  Pos s)

  field
    is-set-shape : isSet Shape
    is-set-pos :  s  isSet (Pos s)

  PosSymGroup : (s : Shape)  Group 
  PosSymGroup s = 𝔖 (Pos s , is-set-pos s)

  field
    symm-group-str :  s  GroupStr (Symm s)
    is-group-hom-action :  s  IsGroupHom (symm-group-str s) (action {s}) (str $ PosSymGroup s)

  ShapeSet : hSet 
  ShapeSet .fst = Shape
  ShapeSet .snd = is-set-shape

  PosSet : (s : Shape)  hSet 
  PosSet s .fst = Pos s
  PosSet s .snd = is-set-pos s

  SymmGroup : (s : Shape)  Group 
  SymmGroup s .fst = Symm s
  SymmGroup s .snd = symm-group-str s

  isSetSymm :  s  isSet (Symm s)
  isSetSymm s = symm-group-str s .GroupStr.is-set

  PosLoop : {s : Shape}  Symm s  PosSet s  PosSet s
  PosLoop = TypeOfHLevel≡ 2  ua  action

  _·_ :  {s}  (g h : Symm s)  Symm s
  _·_ {s} = GroupStr._·_ (symm-group-str s)

  symm-id :  {s}  Symm s
  symm-id {s} = GroupStr.1g (symm-group-str s)

  symm-inv :  {s}  Symm s  Symm s
  symm-inv {s} = GroupStr.inv (symm-group-str s)

  opaque
    PosLoopCompSquare : {s : Shape}  (g h : Symm s)  compSquareFiller (PosLoop g) (PosLoop h) (PosLoop (g · h))
    PosLoopCompSquare g h = ΣSquareSet  X  isProp→isSet isPropIsSet) goal where
      goal : compSquareFiller (ua $ action g) (ua $ action h) (ua $ action (g · h))
      goal = coerceCompSquareFiller $
        (ua $ action g)  (ua $ action h) ≡⟨ sym $ uaCompEquiv (action g) (action h) 
        (ua $ action g ∙ₑ action h) ≡⟨ sym $ cong ua (IsGroupHom.pres· (is-group-hom-action _) g h) 
        (ua $ action (g · h)) 

  actionHom :  s  GroupHom (SymmGroup s) (PosSymGroup s)
  actionHom s .fst = action {s}
  actionHom s .snd = is-group-hom-action s

  symmAction : (s : Shape)  Action (SymmGroup s) (PosSet s)
  symmAction s = GroupHom→Action (actionHom s)

  action-pres-1 :  {s}  action (GroupStr.1g (symm-group-str s))  idEquiv (Pos s)
  action-pres-1 = IsGroupHom.pres1 (is-group-hom-action _)

  action-pres-inv :  {s} (g : Symm s)  action (symm-inv g)  invEquiv (action g)
  action-pres-inv = IsGroupHom.presinv (is-group-hom-action _)

  action-pres-· :  {s} (g h : Symm s)  action (g · h)  action g ∙ₑ action h
  action-pres-· = IsGroupHom.pres· (is-group-hom-action _)

open ActionContainer

ActionContainer≡ :  {} {C D : ActionContainer }
   (shape : C .Shape  D .Shape)
   (pos : PathP  i  shape i  Type ) (C .Pos) (D .Pos))
   (symm : PathP  i  shape i  Group ) (SymmGroup C) (SymmGroup D))
   (action : PathP  i   {s : shape i}   symm i s   (pos i s  pos i s)) (C .action) (D .action))
   C  D
ActionContainer≡ {C} {D} shape pos symm action′ = go where

  opaque
    go-is-set-shape : PathP  i  isSet (shape i)) (C .is-set-shape) (D .is-set-shape)
    go-is-set-shape = isProp→PathP  i  isPropIsSet {A = shape i}) _ _

    go-is-set-pos : PathP  i   s  isSet (pos i s)) (C .is-set-pos) (D .is-set-pos)
    go-is-set-pos = isProp→PathP  i  isPropΠ λ s  isPropIsSet {A = pos i s}) _ _

    go-is-group-hom-action : PathP  i   s  IsGroupHom (symm i s .snd) (action′ i {s}) (str (𝔖 (pos i s , go-is-set-pos i s)))) (C .is-group-hom-action) (D .is-group-hom-action)
    go-is-group-hom-action = isProp→PathP  i  isPropΠ λ _  isPropIsGroupHom _ _) _ _

  go : C  D
  go i .Shape = shape i
  go i .Pos = pos i
  go i .Symm = fst  symm i
  go i .action = action′ i
  go i .is-set-shape = go-is-set-shape i
  go i .is-set-pos = go-is-set-pos i
  go i .symm-group-str = snd  symm i
  go i .is-group-hom-action = go-is-group-hom-action i

mkActionContainer :  {} (S : hSet ) (P :  S   hSet ) (G :  S   Group ) (σ :  s  Action (G s) (P s))  ActionContainer 
mkActionContainer S P G σ .ActionContainer.Shape =  S 
mkActionContainer S P G σ .ActionContainer.Pos = ⟨_⟩  P
mkActionContainer S P G σ .ActionContainer.Symm = ⟨_⟩  G
mkActionContainer S P G σ .ActionContainer.action {s} = σ s .Action.action
mkActionContainer S P G σ .ActionContainer.is-set-shape = str S
mkActionContainer S P G σ .ActionContainer.is-set-pos = str  P
mkActionContainer S P G σ .ActionContainer.symm-group-str = str  G
mkActionContainer S P G σ .ActionContainer.is-group-hom-action s = Action→GroupHom (σ s) .snd

unbundleContainer :  {} (C : ActionContainer )
   Σ[ S  hSet  ]
    Σ[ P  ( S   hSet ) ]
    Σ[ G  ( S   Group ) ]
     s  Action (G s) (P s)
unbundleContainer C = let module C = ActionContainer C in
  λ where
    .fst  C.ShapeSet
    .snd .fst  C.PosSet
    .snd .snd .fst  C.SymmGroup
    .snd .snd .snd  C.symmAction
{-# INLINE unbundleContainer #-}

ActionContainerIsoΣ :  {}  Iso (ActionContainer ) (Σ[ S  hSet  ] Σ[ P  ( S   hSet ) ] Σ[ G  ( S   Group ) ] ((s :  S )  Action (G s) (P s)))
ActionContainerIsoΣ .Iso.fun = unbundleContainer
ActionContainerIsoΣ .Iso.inv = uncurry3 mkActionContainer
ActionContainerIsoΣ .Iso.rightInv _ = refl
ActionContainerIsoΣ .Iso.leftInv C = ActionContainer≡ refl refl symm-group-path refl where
  module Symm s = GroupStr (str (SymmGroup C s))
  symm-group-path : SymmGroup _  SymmGroup C
  symm-group-path i s .fst = Symm C s
  symm-group-path i s .snd .GroupStr.1g = Symm.1g s
  symm-group-path i s .snd .GroupStr._·_ = Symm._·_ s
  symm-group-path i s .snd .GroupStr.inv = Symm.inv s
  symm-group-path i s .snd .GroupStr.isGroup = Symm.isGroup s

ActionContainer≃Σ :  {}  (ActionContainer )  (Σ[ S  hSet  ] Σ[ P  ( S   hSet ) ] Σ[ G  ( S   Group ) ] ((s :  S )  Action (G s) (P s)))
ActionContainer≃Σ = isoToEquiv ActionContainerIsoΣ