{-# OPTIONS --lossy-unification #-}
module Cubical.Categories.Displayed.Presheaf.Uncurried.Eq.Sets where

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function
open import Cubical.Foundations.HLevels
open import Cubical.Foundations.Isomorphism
open import Cubical.Foundations.Equiv.Dependent
open import Cubical.Foundations.Equiv.Dependent.More
open import Cubical.Foundations.Structure
open import Cubical.Foundations.More hiding (_≡[_]_; rectify)
open import Cubical.Foundations.HLevels.More

open import Cubical.Data.Unit
open import Cubical.Data.Empty renaming (rec to ⊥-rec) hiding (elim)
open import Cubical.Data.Empty.Properties
open import Cubical.Data.Sum.Base renaming (rec to ⊎-rec; elim to ⊎-elim)
open import Cubical.Data.Sum.Properties
open import Cubical.Data.Sigma
import Cubical.Data.Equality as Eq

open import Cubical.Categories.Category.Base
open import Cubical.Categories.Functor.Base
open import Cubical.Categories.Functors.More
open import Cubical.Categories.NaturalTransformation
open import Cubical.Categories.NaturalTransformation.More
open import Cubical.Categories.Instances.Fiber
open import Cubical.Categories.Instances.TotalCategory
open import Cubical.Categories.Instances.Sets
open import Cubical.Categories.Instances.Sets.Properties
open import Cubical.Categories.Presheaf.Base
open import Cubical.Categories.Presheaf.Constructions
open import Cubical.Categories.Presheaf.Morphism.Alt
open import Cubical.Categories.Presheaf.Representable hiding (Elements)
open import Cubical.Categories.Presheaf.Representable.More
open import Cubical.Categories.Presheaf.More

open import Cubical.Categories.Displayed.Base
open import Cubical.Categories.Displayed.Section.Base
open import Cubical.Categories.Displayed.Functor
open import Cubical.Categories.Displayed.Functor.More
open import Cubical.Categories.Displayed.NaturalTransformation
open import Cubical.Categories.Displayed.NaturalTransformation.More
open import Cubical.Categories.Displayed.BinProduct
open import Cubical.Categories.Displayed.Instances.Terminal as Unitᴰ
open import Cubical.Categories.Displayed.Instances.Sets.Base as Setᴰ hiding (_[-][-,_])
open import Cubical.Categories.Displayed.BinProduct
open import Cubical.Categories.Displayed.Instances.BinProduct.More
open import Cubical.Categories.Displayed.Instances.Graph.Presheaf
open import Cubical.Categories.Displayed.Instances.Reindex.Eq
import Cubical.Categories.Displayed.Presheaf.Base as Curried
open import Cubical.Categories.Displayed.Presheaf.Uncurried.Eq.Base

private
  variable
     ℓ' ℓᴰ ℓᴰ' : Level
    ℓA ℓB ℓAᴰ ℓBᴰ : Level
    ℓC ℓC' ℓCᴰ ℓCᴰ' : Level
    ℓD ℓD' ℓDᴰ ℓDᴰ' : Level
    ℓE ℓE' ℓEᴰ ℓEᴰ' : Level
    ℓP ℓQ ℓR ℓPᴰ ℓPᴰ' ℓQᴰ ℓQᴰ' ℓRᴰ : Level

open Category
open Functor
open Functorᴰ
open isIsoOver
open NatTrans
open NatTransᴰ
open NatIso
open NatIsoᴰ
open PshHom
open PshIso

SetIdR : EqIdR (SET )
SetIdR = λ f  Eq.refl

SetIdL : EqIdL (SET )
SetIdL = λ f  Eq.refl

SetAssoc : ReprEqAssoc (SET )
SetAssoc x f g p f⋆g Eq.refl = Eq.refl

Setπ₁NatEq : Allπ₁NatEq {C = SET } BinProductsSET
Setπ₁NatEq X γ = Eq.refl

Set×aF-seq : All×aF-seq {C = SET } BinProductsSET
Set×aF-seq X δ γ = Eq.refl

SetAssoc^op : ReprEqAssoc (SET  ^op)
SetAssoc^op x f g p f⋆g Eq.refl = Eq.refl

SetIdR^op : EqIdR (SET  ^op)
SetIdR^op = λ f  Eq.refl

SetᴰTerminalsⱽ : Terminalsⱽ (SETᴰ  ℓᴰ)
SetᴰTerminalsⱽ X .fst x .fst = Unit*
SetᴰTerminalsⱽ X .fst x .snd = isSetUnit*
SetᴰTerminalsⱽ X .snd .PshIsoEq.isos c .Iso.fun = λ _  tt
SetᴰTerminalsⱽ X .snd .PshIsoEq.isos c .Iso.inv = λ _ x _  tt*
SetᴰTerminalsⱽ X .snd .PshIsoEq.isos c .Iso.sec b = refl
SetᴰTerminalsⱽ X .snd .PshIsoEq.isos c .Iso.ret a = refl
SetᴰTerminalsⱽ X .snd .PshIsoEq.nat c c' f p' p x = Eq.refl

SetᴰTerminalsⱽ^op : Terminalsⱽ ((SETᴰ  ℓᴰ) ^opᴰ)
SetᴰTerminalsⱽ^op X .fst x .fst = ⊥*
SetᴰTerminalsⱽ^op X .fst x .snd = isProp→isSet isProp⊥*
SetᴰTerminalsⱽ^op X .snd .PshIsoEq.isos c .Iso.fun = λ _  tt
SetᴰTerminalsⱽ^op X .snd .PshIsoEq.isos c .Iso.inv = λ _ x ()
SetᴰTerminalsⱽ^op X .snd .PshIsoEq.isos c .Iso.sec b = refl
SetᴰTerminalsⱽ^op X .snd .PshIsoEq.isos c .Iso.ret a =
  isContr→isProp (isContrΠ λ _  isContrΠ⊥*) _ a
SetᴰTerminalsⱽ^op X .snd .PshIsoEq.nat c c' f p' p x = Eq.refl

private
  ⊎-η :  {ℓa ℓb ℓc} {A : Type ℓa} {B : Type ℓb} {C : Type ℓc}
        (f : A  B  C)  ⊎-rec  a  f (inl a))  b  f (inr b))  f
  ⊎-η f = funExt λ { (inl a)  refl ; (inr b)  refl }

SetᴰBPⱽ^op : BinProductsⱽ ((SETᴰ  ℓᴰ) ^opᴰ)
SetᴰBPⱽ^op {x = X} P Q = UEⱽ→Reprⱽ _ SetIdR^op ueⱽ
  where
    ueⱽ : UEⱽ (((SETᴰ _ _ ^opᴰ) [-][-, P ]) ×ⱽPsh ((SETᴰ _ _ ^opᴰ) [-][-, Q ])) SetIdR^op
    ueⱽ .UEⱽ.v x .fst =  P x    Q x 
    ueⱽ .UEⱽ.v x .snd = isSet⊎ (P x .snd) (Q x .snd)
    ueⱽ .UEⱽ.e =  x  inl) ,  x  inr)
    ueⱽ .UEⱽ.universal .isPshIsoEq.nIso (Z , R , x⟨z⟩) .fst (p , q) x = ⊎-rec (p x) (q x)
    ueⱽ .UEⱽ.universal .isPshIsoEq.nIso c .snd .fst b = refl
    ueⱽ .UEⱽ.universal .isPshIsoEq.nIso c .snd .snd a = funExt λ x  ⊎-η (a x)

SetᴰBPⱽ : BinProductsⱽ (SETᴰ  ℓᴰ)
SetᴰBPⱽ {x = X} P Q = UEⱽ→Reprⱽ _ SetIdR ueⱽ
  where
    ueⱽ : UEⱽ ((SETᴰ _ _ [-][-, P ]) ×ⱽPsh (SETᴰ _ _ [-][-, Q ])) SetIdR
    ueⱽ .UEⱽ.v x .fst =  P x  ×  Q x 
    ueⱽ .UEⱽ.v x .snd = isSet× (P x .snd) (Q x .snd)
    ueⱽ .UEⱽ.e =  x (p , q)  p) ,  x (p , q)  q)
    ueⱽ .UEⱽ.universal .isPshIsoEq.nIso (Z , R , x⟨z⟩) .fst (p , q) r z = p r z , q r z
    ueⱽ .UEⱽ.universal .isPshIsoEq.nIso c .snd .fst b = refl
    ueⱽ .UEⱽ.universal .isPshIsoEq.nIso c .snd .snd a = refl

SetᴰFibration : Fibration (SETᴰ  ℓᴰ) SetAssoc
SetᴰFibration {} {ℓᴰ} {X} {Y} f Q = UEⱽ→Reprⱽ _ SetIdR fibUE
  where
    fibUE : UEⱽ (yoRecEq (SET  [-, Y ]) (SetAssoc Y) f *Presheafᴰ (SETᴰ  ℓᴰ [-][-, Q ])) SetIdR
    fibUE .UEⱽ.v x = Q (f x)
    fibUE .UEⱽ.e x q = q
    fibUE .UEⱽ.universal .isPshIsoEq.nIso (Z , R , x⟨z⟩) = IsoToIsIso idIso

SetᴰFibration^op : Fibration ((SETᴰ  ) ^opᴰ) SetAssoc^op
SetᴰFibration^op {} {X} {Y} f Qᴰ = UEⱽ→Reprⱽ _ SetIdR^op fibUE
  where
    fibUE : UEⱽ (yoRecEq ((SET  ^op) [-, Y ]) (SetAssoc^op Y) f
              *Presheafᴰ (((SETᴰ  ) ^opᴰ) [-][-, Qᴰ ])) SetIdR^op
    fibUE .UEⱽ.v x .fst = Σ[ y   Y  ] (f y  x) ×  Qᴰ y 
    fibUE .UEⱽ.v x .snd =
      isSetΣ (Y .snd) λ y  isSet× (isProp→isSet (X .snd _ _)) (Qᴰ y .snd)
    fibUE .UEⱽ.e y qᴰ = y , refl , qᴰ
    fibUE .UEⱽ.universal .isPshIsoEq.nIso (Z , Rᴰ , g) .fst h x (y , p , qᴰ) =
      subst  x'   Rᴰ (g x') ) p (h y qᴰ)
    fibUE .UEⱽ.universal .isPshIsoEq.nIso (Z , Rᴰ , g) .snd .fst h =
      funExt λ x  funExt λ p  transportRefl (h x p)
    fibUE .UEⱽ.universal .isPshIsoEq.nIso (Z , Rᴰ , g) .snd .snd k =
      funExt λ x  funExt λ { (y , p , qᴰ) 
        J  x' p'  subst  x''   Rᴰ (g x'') ) p' (k (f y) (y , refl , qᴰ))
                     k x' (y , p' , qᴰ))
          (transportRefl _) p }

isCartesianⱽSETᴰ^op : isCartesianⱽ SetAssoc^op ((SETᴰ  ) ^opᴰ)
isCartesianⱽSETᴰ^op = SetᴰTerminalsⱽ^op , (SetᴰBPⱽ^op , SetᴰFibration^op)

isCartesianⱽSETᴰ : isCartesianⱽ SetAssoc (SETᴰ  ℓᴰ)
isCartesianⱽSETᴰ = SetᴰTerminalsⱽ , (SetᴰBPⱽ , SetᴰFibration)

SetᴰLRⱽ : AllLRⱽ (SETᴰ  ℓᴰ) SetAssoc
SetᴰLRⱽ {} {ℓᴰ} = BPⱽ+Fibration→AllLRⱽ (SETᴰ  ℓᴰ) SetAssoc SetᴰBPⱽ SetᴰFibration

SETᴰExpsⱽ : Exponentialsⱽ (SETᴰ  ℓᴰ) SetAssoc SetIdL SetᴰLRⱽ
SETᴰExpsⱽ {} {ℓᴰ} {X} P Q  = UEⱽ→Reprⱽ _ SetIdR expUE
    where
      expUE : UEⱽ (reindPsh (LRⱽF (SETᴰ  ℓᴰ) SetAssoc SetIdL P (SetᴰLRⱽ P)) (SETᴰ  ℓᴰ [-][-, Q ]))
                  SetIdR
      expUE .UEⱽ.v x .fst =  P x    Q x 
      expUE .UEⱽ.v x .snd = isSet→ (Q x .snd)
      expUE .UEⱽ.e x (f , p) = f p
      expUE .UEⱽ.universal .isPshIsoEq.nIso (Z , R , x⟨z⟩) .fst f⟨z,r,p⟩ z r p = f⟨z,r,p⟩ z (r , p)
      expUE .UEⱽ.universal .isPshIsoEq.nIso (Z , R , x⟨z⟩) .snd .fst b = refl
      expUE .UEⱽ.universal .isPshIsoEq.nIso (Z , R , x⟨z⟩) .snd .snd a = refl

SETᴰ∀ : UniversalQuantifiers (SETᴰ  ) SetIdL SetAssoc (isCartesianⱽSETᴰ .snd .snd)
  BinProductsSET Setπ₁NatEq Set×aF-seq
SETᴰ∀ {} X {Y} P = UEⱽ→Reprⱽ _ SetIdR ueⱽ
  where
    ueⱽ : UEⱽ (reindPsh
               (wkF (SETᴰ  ) SetIdL SetAssoc (isCartesianⱽSETᴰ .snd .snd) X
                 c  BinProductsSET (c , X)) (Setπ₁NatEq X) (Set×aF-seq X) Y)
               (SETᴰ   [-][-, P ])) SetIdR
    ueⱽ .UEⱽ.v y .fst =  x   P (y , x) 
    ueⱽ .UEⱽ.v y .snd = isSetΠ λ x  P (y , x) .snd
    ueⱽ .UEⱽ.e (y , x) ∀x∙p = ∀x∙p x
    ueⱽ .UEⱽ.universal .isPshIsoEq.nIso (Z , R , y⟨z⟩) .fst py⟨z,x,r⟩ z r x = py⟨z,x,r⟩ (z , x) r
    ueⱽ .UEⱽ.universal .isPshIsoEq.nIso (Z , R , y⟨z⟩) .snd .fst b = refl
    ueⱽ .UEⱽ.universal .isPshIsoEq.nIso (Z , R , y⟨z⟩) .snd .snd a = refl

isCCCⱽSETᴰ : isCartesianClosedⱽ SetAssoc (SETᴰ  ) SetIdL BinProductsSET Setπ₁NatEq Set×aF-seq
isCCCⱽSETᴰ .fst = isCartesianⱽSETᴰ
isCCCⱽSETᴰ .snd .fst = SETᴰExpsⱽ
isCCCⱽSETᴰ .snd .snd = SETᴰ∀