{-# OPTIONS --cubical --safe #-}

open import Algebra
open import Prelude
open import HITs.PropositionalTruncation
open import HITs.PropositionalTruncation.Sugar

module Algebra.Construct.Cayley {a} {𝑆 : Type a} (mon : Monoid 𝑆) where

open Monoid mon

π’ž : Type a
π’ž = Ξ£[ f ⦂ (𝑆 β†’ 𝑆) ] Γ— βˆ€ x β†’ βˆ₯ f Ξ΅ βˆ™ x ≑ f x βˆ₯


⟦_β‡“βŸ§ : π’ž β†’ 𝑆
⟦ x β‡“βŸ§ = x .fst Ξ΅

⟦_β‡‘βŸ§ : 𝑆 β†’ π’ž
⟦ x β‡‘βŸ§ .fst y = x βˆ™ y
⟦ x β‡‘βŸ§ .snd y = ∣ cong (_βˆ™ y) (βˆ™Ξ΅ x) ∣

β“” : π’ž
β“” .fst x = x
β“” .snd x = ∣ Ξ΅βˆ™ x ∣

open import Relation.Binary
open import HITs.PropositionalTruncation.Equivalence
open import Relation.Binary.Equivalence.Reasoning (trunc-equivalence (≑-equivalence {A = 𝑆}))

_βŠ™_ : π’ž β†’ π’ž β†’ π’ž
(x βŠ™ y) .fst z = x .fst (y .fst z)
(x βŠ™ y) .snd z =
  x .fst (y .fst Ξ΅) βˆ™ z     β‰‹Λ˜βŸ¨ cong (_βˆ™ z) βˆ₯$βˆ₯ (x .snd (y .fst Ξ΅)) ⟩
  x .fst Ξ΅ βˆ™ y .fst Ξ΅ βˆ™ z   β‰‘βŸ¨ assoc (x .fst Ξ΅) (y .fst Ξ΅) z ⟩
  x .fst Ξ΅ βˆ™ (y .fst Ξ΅ βˆ™ z) β‰‹βŸ¨ cong (x .fst Ξ΅ βˆ™_) βˆ₯$βˆ₯ (y .snd z)  ⟩
  x .fst Ξ΅ βˆ™ y .fst z       β‰‹βŸ¨ x .snd (y .fst z) ⟩
  x .fst (y .fst z) ∎

βŠ™-assoc : Associative _βŠ™_
βŠ™-assoc x y z i .fst k = x .fst (y .fst (z .fst k))
βŠ™-assoc x y z i .snd k = squash (((x βŠ™ y) βŠ™ z) .snd k) ((x βŠ™ (y βŠ™ z)) .snd k) i

β“”βŠ™ : βˆ€ x β†’ β“” βŠ™ x ≑ x
β“”βŠ™ x i .fst y = x .fst y
β“”βŠ™ x i .snd y = squash ((β“” βŠ™ x) .snd y) (x .snd y) i

βŠ™β“” : βˆ€ x β†’ x βŠ™ β“” ≑ x
βŠ™β“” x i .fst y = x .fst y
βŠ™β“” x i .snd y = squash ((x βŠ™ β“”) .snd y) (x .snd y) i

cayleyMonoid : Monoid π’ž
Monoid._βˆ™_ cayleyMonoid = _βŠ™_
Monoid.Ξ΅ cayleyMonoid = β“”
Monoid.assoc cayleyMonoid = βŠ™-assoc
Monoid.Ξ΅βˆ™ cayleyMonoid = β“”βŠ™
Monoid.βˆ™Ξ΅ cayleyMonoid = βŠ™β“”

open import Data.Sigma.Properties

module _ (sIsSet : isSet 𝑆) where
  π’ž-leftInv-fst : βˆ€ x y β†’ ⟦ ⟦ x β‡“βŸ§ β‡‘βŸ§ .fst y ≑ x .fst y
  π’ž-leftInv-fst x y = rec (sIsSet (x .fst Ξ΅ βˆ™ y) (x .fst y)) id (x .snd y)

  π’ž-leftInv : βˆ€ x β†’ ⟦ ⟦ x β‡“βŸ§ β‡‘βŸ§ ≑ x
  π’ž-leftInv x = Σ≑Prop (Ξ» f xs ys β†’ funExt Ξ» x β†’ squash (xs x) (ys x)) (funExt (π’ž-leftInv-fst x))

  π’ž-iso : π’ž ⇔ 𝑆
  fun π’ž-iso = ⟦_β‡“βŸ§
  inv π’ž-iso = ⟦_β‡‘βŸ§
  rightInv π’ž-iso = βˆ™Ξ΅
  leftInv π’ž-iso = π’ž-leftInv