-- NOTE with-K
module Data.Nat.BoundedMonoInj-is-Id where

open import Type
open import Function.NP using (Endo)
open import Data.Zero using (𝟘 ; 𝟘-elim)
open import Data.Nat.NP using (; zero; suc; sucx≰x; module ℕ≤; _≤_; _<_; z≤n; s≤s; ≤-pred ; suc-injective)

open import Data.Nat.Properties using (≤-step; ≤-steps; <-trans)
open import Data.Sum using (_⊎_ ; inj₁ ; inj₂)

open import Relation.Nullary using (¬_)
open import Relation.Binary.PropositionalEquality using (_≡_; refl; subst)

split-≤ :  {x y}  x  y  x  y  x < y
split-≤ {zero} {zero} p = inj₁ refl
split-≤ {zero} {suc y} p = inj₂ (s≤s z≤n)
split-≤ {suc x} {zero} ()
split-≤ {suc x} {suc y} (s≤s p) with split-≤ {x} {y} p
... | inj₁ q rewrite q = inj₁ refl
... | inj₂ q = inj₂ (s≤s q)

<→≤ :  {x y}  x < y  x  y
<→≤ (s≤s p) = ≤-steps 1 p

Monotone :   Endo   
Monotone ub f =  {x y}  x  y  y < ub  f x  f y

IsInj :   Endo   
IsInj ub f =  {x y}  x < ub  y < ub  f x  f y  x  y

Bounded :   Endo   
Bounded ub f =  x  x < ub  f x < ub

module M (f :   ) {ub}
         (f-mono : Monotone ub f)
         (f-inj : IsInj ub f)
         (f-bounded : Bounded ub f) where

 f-mono-< :  {x y}  x < y  y < ub  f x < f y
 f-mono-< {x} {y} p y<ub with split-≤ (f-mono {x} {y} (<→≤ p) y<ub)
 ... | inj₁ q = 𝟘-elim (sucx≰x y (subst  z  suc z  y) (f-inj {x} {y} (<-trans p y<ub) y<ub q) p))
 ... | inj₂ q = q

 le :  n  suc n < ub  f (suc n)  n  f n < n
 le n 1+n<ub p = ℕ≤.trans (f-mono-< {n} {suc n} ℕ≤.refl 1+n<ub) p

 fp :  b  b < ub  Bounded (suc b) f  f b  b
 fp b b<ub bub with split-≤ (bub b ℕ≤.refl)
 ... | inj₁ p = suc-injective p
 ... | inj₂ p = 𝟘-elim (bo b b<ub (≤-pred p))
   where
     bo :  b  b < ub  ¬(f b < b)
     bo zero _ ()
     bo (suc b) b<ub (s≤s p) = bo b (ℕ≤.trans (s≤s (≤-step ℕ≤.refl)) b<ub) (le b b<ub p)

 ob :  b  b  ub  Bounded b f   x  x < b  f x  x
 ob zero b≤ub bub _ ()
 ob (suc b) b≤ub bub x pf with split-≤ pf
 ... | inj₁ p rewrite suc-injective p = fp b b≤ub bub
 ... | inj₂ p = ob b (<→≤ b≤ub) ((λ y y<b  ℕ≤.trans (f-mono-< y<b b≤ub) (ℕ≤.reflexive (fp b b≤ub bub)))) x (≤-pred p)

 is-id :  x  x < ub  f x  x
 is-id = ob ub ℕ≤.refl f-bounded