{-# OPTIONS --safe #-}

module Cubical.Modalities.Instances.DoubleNegation where

open import Cubical.Modalities.Modality

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Function using (_∘_; const)
open import Cubical.Foundations.HLevels using (hProp; isProp→isContrPath)
open import Cubical.Foundations.Structure using (⟨_⟩)

open import Cubical.Data.Empty using (⊥*; isProp⊥*)
open import Cubical.Data.Sigma using (_×_; ΣPathP)


module GeneralizedDoubleNegation { : Level} (Y : hProp ) where

  -- Generalized negation with respect to the proposition Y.
  ¬ : Type   Type 
  ¬ A = A   Y 

  ¬¬ : Type   Type 
  ¬¬ = ¬  ¬

  isStableProp : Type   Type 
  isStableProp A = isProp A × (¬¬ A  A)

  module _ {A : Type } where

    η : A  ¬¬ A
    η a f = f a

    isPropIsStableProp : isProp (isStableProp A)
    isPropIsStableProp x y = ΣPathP (isPropIsProp _ _ , funExt  _  fst x _ _))

    isContr→isStableProp : isContr A  isStableProp A
    isContr→isStableProp c = (isContr→isProp c) , const (fst c)

    isProp¬ : isProp (¬ A)
    isProp¬ x y = funExt  _  snd Y _ _)

    tripleNegationReduction : ¬ (¬ (¬ A))  ¬ A
    tripleNegationReduction f a = f (η a)

  module _ {A : Type } where
    isProp¬¬ : isProp (¬¬ A)
    isProp¬¬ = isProp¬

    isStableProp¬¬ : isStableProp (¬¬ A)
    isStableProp¬¬ = isProp¬¬ , tripleNegationReduction

  map¬¬ : {A B : Type }  (A  B)  ¬¬ A  ¬¬ B
  map¬¬ f = _∘ (_∘ f)

  modality : Modality 
  Modality.isModal modality = isStableProp
  Modality.isPropIsModal modality = isPropIsStableProp
  Modality.◯ modality = ¬¬
  Modality.◯-isModal modality = isStableProp¬¬
  Modality.η modality = η
  Modality.◯-elim modality {A = A} {B = B} B-modal f x =
    snd (B-modal x) (map¬¬  a  substB (f a)) x)
    where
      substB : {x y : ¬¬ A}  B x  B y
      substB {x} {y} = subst B (isProp¬¬ x y)
  Modality.◯-elim-β modality B-modal f a = fst (B-modal _) _ _
  Modality.◯-=-isModal modality x y =
    isContr→isStableProp (isProp→isContrPath isProp¬¬ _ _)

doubleNegationModality : { : Level}  Modality 
doubleNegationModality = GeneralizedDoubleNegation.modality (⊥* , isProp⊥*)