{-# OPTIONS --without-K --safe #-}

module Categories.Category.Concrete.Properties where

open import Data.Unit.Polymorphic using (; tt)
open import Function.Base using (const; _∘_)
open import Function.Bundles using (Func; _⟨$⟩_)
import Function.Construct.Constant as Const
import Function.Construct.Composition as Comp
open import Level using (Level; lift)
open import Relation.Binary using (Setoid)
import Relation.Binary.Reasoning.Setoid as SR

open import Categories.Adjoint using (_⊣_; Adjoint)
open import Categories.Category.Core using (Category)
open import Categories.Category.Instance.Setoids using (Setoids)
open import Categories.Category.Instance.SingletonSet using () renaming (SingletonSetoid to OneS)
open import Categories.Category.Concrete using (Concrete; RepresentablyConcrete)
open import Categories.Functor.Core using (Functor)
open import Categories.Functor.Representable using (Representable)
open import Categories.Functor.Properties using (Faithful)
import Categories.Morphism.Reasoning as MR
open import Categories.NaturalTransformation using (NaturalTransformation; ntHelper)

open Concrete
open Func

⊣⇒Representable : {o  e : Level} (C : Category o  e) (conc : Concrete C  e)  (F : Functor (Setoids  e) C) 
  F  concretize conc   RepresentablyConcrete C
⊣⇒Representable {_} {} {e} C conc F L = record
  { conc = conc
  ; representable = record
    { A = F.₀ OneS
    ; Iso = record
      { F⇒G = ntHelper record
        { η = λ X  record
          { to = λ x  L.counit.η X C.∘ F.₁ (Const.function OneS (U.F₀ X) x)
          ; cong = λ i≈j  C.∘-resp-≈ʳ (F.F-resp-≈ i≈j)
          }
        ; commute = λ {X} {Y} f {x} 
            let open C.HomReasoning in begin
            L.counit.η Y C.∘ F.₁ (constF Y (U.₁ f ⟨$⟩ x))               ≈⟨ refl⟩∘⟨ F.F-resp-≈ (Setoid.refl (U.₀ Y)) 
            L.counit.η Y C.∘ F.₁ (Comp.function (constF X x) (U.F₁ f)) ≈⟨ pushʳ F.homomorphism 
            ((L.counit.η Y C.∘ F.₁ (U.₁ f)) C.∘ F.₁ (constF X x))      ≈⟨ pushˡ (commute L.counit f) 
            f C.∘ L.counit.η X C.∘ F.₁ (constF X x)                    ≈˘⟨ C.identityʳ 
            (f C.∘ L.counit.η X C.∘ F.₁ (constF X x)) C.∘ C.id         
        }
      ; F⇐G = ntHelper record
        { η = λ c  record
          { to = λ 1⇒c  U.₁ 1⇒c ⟨$⟩ η1
          ; cong = λ i≈j  U.F-resp-≈ i≈j
          }
        ; commute = λ {X} {Y} f {x} 
             let module CH = C.HomReasoning in
             let open SR (U.₀ Y) in
             begin
             U.₁ ((f C.∘ x) C.∘ C.id) ⟨$⟩ η1 ≈⟨ U.F-resp-≈ C.identityʳ 
             U.₁ (f C.∘ x) ⟨$⟩ η1            ≈⟨ U.homomorphism 
             U.₁ f ⟨$⟩ (U.₁ x ⟨$⟩ η1)         
        }
      ; iso = λ X  record
        { isoˡ = λ {x}  L.LRadjunct≈id {OneS} {X} {Const.function OneS (U.F₀ X) x}
        ; isoʳ = λ { {1⇒x} 
          let open C.HomReasoning in begin
          L.counit.η X C.∘ F.₁ (constF X (U.₁ 1⇒x ⟨$⟩ η1))                 ≈⟨ refl⟩∘⟨ F.F-resp-≈ (cong (U.F₁ 1⇒x) (cong (L.unit.η OneS) _)) 
          L.counit.η X C.∘ F.₁ (Comp.function (L.unit.η OneS) (U.₁ 1⇒x))  ≈⟨ L.RLadjunct≈id {OneS} {X} {1⇒x}  
          1⇒x  }
        }
      }
    }
  }
  where
  module C = Category C
  module U = Functor (concretize conc)
  module F = Functor F
  module L = Adjoint L
  open NaturalTransformation
  open MR C
  η1 : Setoid.Carrier (U.₀ (F.₀ OneS))
  η1 = L.unit.η OneS ⟨$⟩ tt
  constF :  {} A  Setoid.Carrier (U.F₀ A)  Func (OneS {}) (U.F₀ A)
  constF A = Const.function OneS (U.F₀ A)