{-# OPTIONS --safe #-}
module Cubical.Data.Int.MoreInts.DiffInt.Properties where

open import Cubical.Foundations.HLevels

open import Cubical.Foundations.Prelude
open import Cubical.Foundations.Univalence

open import Cubical.Data.Int.MoreInts.DiffInt.Base
open import Cubical.Data.Nat as  renaming (_+_ to _+ℕ_ ; _·_ to _*ℕ_)
open import Cubical.Data.Sigma
open import Cubical.Data.Bool

open import Cubical.Relation.Binary.Base
open import Cubical.Relation.Nullary

open import Cubical.HITs.SetQuotients as SetQuotients
open import Cubical.HITs.PropositionalTruncation as PropositionalTruncation
open import Cubical.Foundations.Isomorphism

open BinaryRelation

relIsEquiv : isEquivRel rel
relIsEquiv = equivRel {A =  × } relIsRefl relIsSym relIsTrans
  where
    relIsRefl : isRefl rel
    relIsRefl (a0 , a1) = refl

    relIsSym : isSym rel
    relIsSym (a0 , a1) (b0 , b1) p = sym p

    relIsTrans : isTrans rel
    relIsTrans (a0 , a1) (b0 , b1) (c0 , c1) p0 p1 =
      inj-m+ {m = (b0 +ℕ b1)} ((b0 +ℕ b1) +ℕ (a0 +ℕ c1) ≡⟨ ℕ.+-assoc (b0 +ℕ b1) a0 c1  
            ((b0 +ℕ b1) +ℕ a0) +ℕ c1 ≡[ i ]⟨ ℕ.+-comm b0 b1 i +ℕ a0   +ℕ c1 
            ((b1 +ℕ b0) +ℕ a0) +ℕ c1 ≡[ i ]⟨ ℕ.+-comm (b1 +ℕ b0) a0 i +ℕ c1 
            (a0 +ℕ (b1 +ℕ b0)) +ℕ c1 ≡[ i ]⟨ ℕ.+-assoc a0 b1 b0 i    +ℕ c1 
            (a0 +ℕ b1) +ℕ b0 +ℕ c1 ≡⟨ sym (ℕ.+-assoc (a0 +ℕ b1) b0 c1) 
            (a0 +ℕ b1) +ℕ (b0 +ℕ c1) ≡⟨ cong  p  p . fst +ℕ p .snd) (transport ΣPath≡PathΣ (p0 , p1))
            (b0 +ℕ a1) +ℕ (c0 +ℕ b1) ≡⟨ sym (ℕ.+-assoc b0 a1 (c0 +ℕ b1))
            b0 +ℕ (a1 +ℕ (c0 +ℕ b1)) ≡[ i ]⟨ b0 +ℕ (a1 +ℕ ℕ.+-comm c0 b1 i) 
            b0 +ℕ (a1 +ℕ (b1 +ℕ c0)) ≡[ i ]⟨ b0 +ℕ ℕ.+-comm a1 (b1 +ℕ c0) i 
            b0 +ℕ ((b1 +ℕ c0) +ℕ a1) ≡[ i ]⟨ b0 +ℕ ℕ.+-assoc b1 c0 a1 (~ i) 
            b0 +ℕ (b1 +ℕ (c0 +ℕ a1)) ≡⟨ ℕ.+-assoc b0 b1 (c0 +ℕ a1)
            (b0 +ℕ b1) +ℕ (c0 +ℕ a1)  )

discreteℤ : Discrete 
discreteℤ = discreteSetQuotients relIsEquiv  _ _  discreteℕ _ _)

private
  _ : Dec→Bool (discreteℤ [ (3 , 5) ] [ (4 , 6) ])  true
  _ = refl

  _ : Dec→Bool (discreteℤ [ (3 , 5) ] [ (4 , 7) ])  false
  _ = refl

  _+ℕ'_ : ( × )  ( × )  ( × )
  (n₁ , n₂) +ℕ' (m₁ , m₂) = (n₁ +ℕ m₁ , n₂ +ℕ m₂)

  [_-ℕ'_] :     
  [ x -ℕ' y ] = [ x , y ]

  ℤ-cancelˡ :  {a b} (c : )  [ (c ℕ.+ a) -ℕ' (c +ℕ b) ]  [ a -ℕ' b ]
  ℤ-cancelˡ {a} {b} c = eq/ _ _ (tmp a b c)
    where tmp :  a b c  rel (c +ℕ a , c +ℕ b) (a , b)
          tmp a b c =
            c +ℕ a +ℕ b
              ≡⟨ cong  x  x +ℕ b) (ℕ.+-comm c a) 
            a +ℕ c +ℕ b
              ≡⟨ sym(ℕ.+-assoc a c b) 
            a +ℕ (c +ℕ b) 

  ℤ-cancelʳ :  {a b} (c : )  [ a +ℕ c -ℕ' b +ℕ c ]  [ a -ℕ' b ]
  ℤ-cancelʳ {a} {b} c = eq/ _ _ (tmp a b c)
    where tmp :  a b c  rel (a +ℕ c , b +ℕ c) (a , b)
          tmp a b c =
            a +ℕ c +ℕ b
              ≡⟨ sym(ℕ.+-assoc a c b) 
            a +ℕ (c +ℕ b)
              ≡⟨ cong  x  a +ℕ x) (ℕ.+-comm c b) 
            a +ℕ (b +ℕ c) 

  -- right congruence
  +-right-congruence :  x y z  rel y z  rel (x +ℕ' y) (x +ℕ' z)
  +-right-congruence x y z  p =
    (fst x +ℕ fst y) +ℕ (snd x +ℕ snd z)
      ≡⟨ cong  x'  (fst x +ℕ fst y) +ℕ x') (ℕ.+-comm (snd x) (snd z)) 
    (fst x +ℕ fst y) +ℕ (snd z +ℕ snd x)
      ≡⟨ ℕ.+-assoc (fst x +ℕ fst y) (snd z) (snd x) 
    fst x +ℕ fst y +ℕ snd z +ℕ snd x
      ≡⟨ cong  x'  x' +ℕ snd x) (sym (ℕ.+-assoc (fst x) (fst y) (snd z))) 
    fst x +ℕ (fst y +ℕ snd z) +ℕ snd x
      ≡⟨ cong  x'  fst x +ℕ x' +ℕ snd x) p 
    fst x +ℕ (fst z +ℕ snd y) +ℕ snd x
      ≡⟨ cong  x'  x' +ℕ snd x) (ℕ.+-assoc (fst x) (fst z) (snd y)) 
    fst x +ℕ fst z +ℕ snd y +ℕ snd x
      ≡⟨ sym (ℕ.+-assoc (fst x +ℕ fst z) (snd y) (snd x)) 
    fst x +ℕ fst z +ℕ (snd y +ℕ snd x)
      ≡⟨ cong  x'  fst x +ℕ fst z +ℕ x') (ℕ.+-comm (snd y) (snd x)) 
    fst x +ℕ fst z +ℕ (snd x +ℕ snd y) 

  +-left-congruence :  x y z  rel x y  rel (x +ℕ' z) (y +ℕ' z)
  +-left-congruence x y z p =
    (fst x +ℕ fst z) +ℕ (snd y +ℕ snd z)
      ≡⟨ cong  x'  x' +ℕ (snd y +ℕ snd z)) (ℕ.+-comm (fst x) (fst z)) 
    (fst z +ℕ fst x) +ℕ (snd y +ℕ snd z)
      ≡⟨ ℕ.+-assoc (fst z +ℕ fst x) (snd y) (snd z) 
    fst z +ℕ fst x +ℕ snd y +ℕ snd z
      ≡⟨ cong  x'  x' +ℕ snd z) (sym (ℕ.+-assoc (fst z) (fst x) (snd y))) 
    fst z +ℕ (fst x +ℕ snd y) +ℕ snd z
      ≡⟨ cong  x'  fst z +ℕ x' +ℕ snd z) p 
    fst z +ℕ (fst y +ℕ snd x) +ℕ snd z
      ≡⟨ cong  x'  x' +ℕ snd z) (ℕ.+-assoc (fst z) (fst y) (snd x)) 
    fst z +ℕ fst y +ℕ snd x +ℕ snd z
      ≡⟨ sym (ℕ.+-assoc (fst z +ℕ fst y) (snd x) (snd z)) 
    fst z +ℕ fst y +ℕ (snd x +ℕ snd z)
      ≡⟨ cong  x'  x' +ℕ (snd x +ℕ snd z)) (ℕ.+-comm (fst z) (fst y)) 
    fst y +ℕ fst z +ℕ (snd x +ℕ snd z) 

ℤ-isSet : isSet 
ℤ-isSet m n p q = squash/ m n p q

_+_ :     
_+_ = SetQuotients.rec2 ℤ-isSet  x y  [ x +ℕ' y ]) feql feqr
    where
      feql : (a b c :  × ) (r : rel a b)  [ a +ℕ' c ]  [ b +ℕ' c ]
      feql a b c r = eq/ (a +ℕ' c) (b +ℕ' c) (+-left-congruence a b c r)
      feqr : (a b c :  × ) (r : rel b c)  [ a +ℕ' b ]  [ a +ℕ' c ]
      feqr a b c r = eq/ (a +ℕ' b) (a +ℕ' c) (+-right-congruence a b c r)

private
  zero-identityˡ-lem : (a : )(b : )  (Σ ( × ) ( λ (c , d)  [ (c , d) ]   b ))  [ a , a ] + b  b
  zero-identityˡ-lem a b ( (c , d) , p ) =
    [ a , a ] + b           ≡⟨ cong  x  [ a , a ] + x) (sym p) 
    [ a , a ] + [ c , d ]   ≡⟨ ℤ-cancelˡ a 
    [ c , d ]               ≡⟨ p 
    b 

  zero-identityʳ-lem : (a : )(b : )  (Σ ( × ) ( λ (c , d)  [ (c , d) ]   b ))  b + [ a , a ]  b
  zero-identityʳ-lem a b ( (c , d) , p ) =
    b + [ a , a ]           ≡⟨ cong  x  x + [ a , a ]) (sym(p)) 
    [ c , d ] + [ a , a ]   ≡⟨ ℤ-cancelʳ a 
    [ c , d ]               ≡⟨ p 
    b 

zero-identityˡ : (a : ) (b : )  [ a , a ] + b  b
zero-identityˡ a b = PropositionalTruncation.rec (lem2 a b) (zero-identityˡ-lem a b) ([]surjective b)
                     where
                       lem2 : (a : ) (b : )  isProp ([ a , a ] + b  b)
                       lem2 a b = ℤ-isSet ([ a , a ] + b) b

zero-identityʳ : (a : )(b : )  b + [ a , a ]  b
zero-identityʳ a b = PropositionalTruncation.rec (lem2 a b) (zero-identityʳ-lem a b) ([]surjective b)
                     where
                       lem2 : (a : ) (b : )  isProp (b + [ a , a ]  b)
                       lem2 a b = ℤ-isSet (b + [ a , a ]) b

-ℤ_  :   
-ℤ [ a ] = [ snd a , fst a ]
-ℤ eq/ a b r i = eq/ (snd a , fst a) (snd b , fst b) (tmp a b r) i
                  where
                    tmp :  a b  fst a +ℕ snd b  fst b +ℕ snd a  snd a +ℕ fst b  snd b +ℕ fst a
                    tmp a b r =
                      snd a +ℕ fst b ≡⟨ ℕ.+-comm (snd a) (fst b) 
                      fst b +ℕ snd a ≡⟨ sym r 
                      fst a +ℕ snd b ≡⟨ ℕ.+-comm (fst a) (snd b) 
                      snd b +ℕ fst a 
-ℤ squash/ a a₁ p q i i₁ = squash/ (-ℤ a) (-ℤ a₁) (cong  x  -ℤ x) p) (cong  x  -ℤ x) q) i i₁

private
  -ℤ-invʳ-lem : (b : )  (Σ ( × ) ( λ (c , d)  [ (c , d) ]   b ))  b + (-ℤ b)  [ 0 , 0 ]
  -ℤ-invʳ-lem b ( (c , d) , p ) =
    b + (-ℤ b)
      ≡⟨ cong  x  x + (-ℤ b)) (sym p) 
    [ c , d ] + (-ℤ b)
      ≡⟨ cong  x  [ c , d ] + (-ℤ x)) (sym p) 
    [ c +ℕ d , d +ℕ c ]
      ≡⟨ cong  x  [ c +ℕ d , x ]) (ℕ.+-comm d c) 
    [ c +ℕ d , c +ℕ d ]
      ≡⟨ ℤ-cancelˡ c 
    [ d -ℕ' d ]
      ≡⟨ sym(ℤ-cancelʳ 0) 
    [ d +ℕ 0 -ℕ' d +ℕ 0 ]
      ≡⟨ ℤ-cancelˡ d 
    [ 0 , 0 ] 

  -ℤ-invˡ-lem : (b : )  (Σ ( × ) ( λ (c , d)  [ (c , d) ]   b ))  (-ℤ b) + b  [ 0 , 0 ]
  -ℤ-invˡ-lem b ( (c , d) , p ) =
    (-ℤ b) + b
      ≡⟨ cong  x  (-ℤ b) + x) (sym p) 
    (-ℤ b) + [ c , d ]
      ≡⟨ cong  x  (-ℤ x) + [ c , d ]) (sym p) 
    [ d +ℕ c , c +ℕ d ]
      ≡⟨ cong  x  [ x , c +ℕ d ]) (ℕ.+-comm d c) 
    [ c +ℕ d , c +ℕ d ]
      ≡⟨ ℤ-cancelˡ c 
    [ d -ℕ' d ]
      ≡⟨ sym(ℤ-cancelʳ 0) 
    [ d +ℕ 0 -ℕ' d +ℕ 0 ]
      ≡⟨ ℤ-cancelˡ d 
    [ 0 , 0 ] 

_-_ :     
a - b = a + (-ℤ b)

-ℤ-invʳ : (b : )  b + (-ℤ b)  [ 0 , 0 ]
-ℤ-invʳ b = PropositionalTruncation.rec (lem2 b) (-ℤ-invʳ-lem b) ([]surjective b)
             where
               lem2 : (b : )  isProp (b + (-ℤ b)  [ 0 , 0 ])
               lem2 b = ℤ-isSet (b + (-ℤ b)) [ 0 , 0 ]

-ℤ-invˡ : (b : )  (-ℤ b) + b  [ 0 , 0 ]
-ℤ-invˡ b = PropositionalTruncation.rec (lem2 b) (-ℤ-invˡ-lem b) ([]surjective b)
             where
               lem2 : (b : )  isProp ((-ℤ b) + b  [ 0 , 0 ])
               lem2 b = ℤ-isSet ((-ℤ b) + b) [ 0 , 0 ]

+ℤ-assoc :  x y z  x + (y + z)  (x + y) + z
+ℤ-assoc = elimProp3  _ _ _  ℤ-isSet _ _)
     { (a , b) (c , d) (e , f) i  [ ℕ.+-assoc a c e i -ℕ' ℕ.+-assoc b d f i ] })

+ℤ-comm :  x y  x + y  y + x
+ℤ-comm = elimProp2  _ _  ℤ-isSet _ _)
         λ ( a , b ) ( c , d ) i  [ ℕ.+-comm a c i -ℕ'  ℕ.+-comm b d i ]