import Spa.Lattice.IterProd
import Spa.Isomorphism

namespace Spa

namespace Tuple

universe u

variable {B : Type u}

private def iterOfFun : {n : ℕ} → (Fin n → B) → IterProd B PUnit n
  | 0, _ => PUnit.unit
  | _ + 1, f => (f 0, iterOfFun (Fin.tail f))

private def funOfIter : {n : ℕ} → IterProd B PUnit n → (Fin n → B)
  | 0, _ => Fin.elim0
  | _ + 1, ip => Fin.cons ip.1 (funOfIter ip.2)

private lemma funOfIter_iterOfFun : ∀ {n : ℕ} (f : Fin n → B),
    funOfIter (iterOfFun f) = f
  | 0, _ => funext fun i => i.elim0
  | _ + 1, f => by
    show Fin.cons (f 0) (funOfIter (iterOfFun (Fin.tail f))) = f
    rw [funOfIter_iterOfFun (Fin.tail f), Fin.cons_self_tail]

private lemma iterOfFun_funOfIter : ∀ {n : ℕ} (ip : IterProd B PUnit n),
    iterOfFun (funOfIter ip) = ip
  | 0, PUnit.unit => rfl
  | _ + 1, ip => by
    show (funOfIter ip 0, iterOfFun (Fin.tail (funOfIter ip))) = ip
    rw [show funOfIter ip = Fin.cons ip.1 (funOfIter ip.2) from rfl]
    simp [Fin.cons_zero, Fin.tail_cons, iterOfFun_funOfIter ip.2]

variable [Lattice B]

private lemma funOfIter_mono {n : ℕ} :
    Monotone (funOfIter : IterProd B PUnit n → (Fin n → B)) := by
  induction n with
  | zero => intro _ _ _ i; exact i.elim0
  | succ n ih =>
    intro ip₁ ip₂ h i
    obtain ⟨h1, h2⟩ := Prod.le_def.mp h
    rw [show funOfIter ip₁ = Fin.cons ip₁.1 (funOfIter ip₁.2) from rfl,
        show funOfIter ip₂ = Fin.cons ip₂.1 (funOfIter ip₂.2) from rfl]
    induction i using Fin.cases with
    | zero => rw [Fin.cons_zero, Fin.cons_zero]; exact h1
    | succ j => rw [Fin.cons_succ, Fin.cons_succ]; exact ih h2 j

private lemma iterOfFun_mono {n : ℕ} :
    Monotone (iterOfFun : (Fin n → B) → IterProd B PUnit n) := by
  induction n with
  | zero => intro f g _; exact le_of_eq rfl
  | succ n ih =>
    intro f g h
    exact Prod.le_def.mpr ⟨h 0, ih fun i => h i.succ⟩

instance instFiniteHeight {n : ℕ} [FiniteHeightLattice B] :
    FiniteHeightLattice (Fin n → B) :=
  FiniteHeightLattice.transport funOfIter iterOfFun
    funOfIter_mono iterOfFun_mono iterOfFun_funOfIter funOfIter_iterOfFun

end Tuple

end Spa
