open import Level
open import Data.List
open import Data.Nat
open import Data.Product
open import Data.Unit

module Normalise where

  private
    record Aggregate {} {t : Set } (_ : t) : Set (Level.suc ) where
      field
        items : List ( λ (t' : Set )  t')

    open Aggregate

    unAggregateTypes :  {}  List (  (t' : Set )  t'))  _
    unAggregateTypes [] = Lift 
    unAggregateTypes ((t , _)  []) = t
    unAggregateTypes ((t , _)  xs) = t × unAggregateTypes xs

    unAggregate :  {} {t : Set } {x : t}  (c : Aggregate x)  unAggregateTypes (items c)
    unAggregate record { items = [] } = lift tt
    unAggregate record { items = items } = f items
      where
        f : (zs : _)  unAggregateTypes zs
        f [] = lift tt
        f ((_ , i)  []) = i
        f ((_ , i)  x  xs) = i , f (x  xs)

  instance
    ×-instance :  {} {t₁ : Set } {t₂ : Set } {x : t₁} {y : t₂} {{_ : Aggregate x}} {{_ : Aggregate y}}  Aggregate (x , y)
    ×-instance {{i}} {{j}} = record { items = items i ++ items j }

  module add {} (t : Set ) where
    instance
      i :  {x : t}  Aggregate x
      i {x} = record { items = (_ , x)  [] }


  refactor :  {ℓ₁ ℓ₂} {t₁ : Set ℓ₁} {t₂ : Set ℓ₂} (x : t₁ × t₂) {{_ : Aggregate x}}  _
  refactor _ {{i}} = unAggregate i

open Normalise

-- example
mess : (((( × ) × ) × ( × )) × (  ))
mess = (((tt , 3) , 7) , (5 , tt)) , λ x  x

clean :  ×  ×  ×  ×  × (  )
clean = refactor mess
  where
    open add (  )
    open add 
    open add 

-- example 2
poly :  {a b c d e : Set}  (((a × b × c) × d) × e)  a × b × c × d × e
poly {a} {b} {c} {d} {e} mess = refactor mess
  where
    open add a
    open add b
    open add c
    open add d
    open add e