{-# OPTIONS --safe #-}

import Data.List as L

open import Ledger.Prelude
open import Ledger.Conway.Abstract
open import Ledger.Conway.Transaction using (TransactionStructure)

module Ledger.Conway.Ledger
  (txs : _) (open TransactionStructure txs)
  (abs : AbstractFunctions txs) (open AbstractFunctions abs)
  where

open import Ledger.Conway.Enact govStructure
open import Ledger.Conway.Gov txs
open import Ledger.Conway.Utxo txs abs
open import Ledger.Conway.Utxow txs abs
open import Ledger.Conway.Certs govStructure

open Tx
open GState
open GovActionState
open EnactState using (cc)


record LEnv : Type where
  field
    slot        : Slot
    ppolicy     : Maybe ScriptHash
    pparams     : PParams
    enactState  : EnactState
    treasury    : Coin


instance
  HasPParams-LEnv : HasPParams LEnv
  HasPParams-LEnv .PParamsOf = LEnv.pparams




record LState : Type where


  constructor ⟦_,_,_⟧ˡ


  field
    utxoSt     : UTxOState
    govSt      : GovState
    certState  : CertState



record HasLState {a} (A : Type a) : Type a where
  field LStateOf : A  LState
open HasLState ⦃...⦄ public

instance
  HasUTxOState-LState : HasUTxOState LState
  HasUTxOState-LState .UTxOStateOf = LState.utxoSt

  HasUTxO-LState : HasUTxO LState
  HasUTxO-LState .UTxOOf = UTxOOf  UTxOStateOf

  HasGovState-LState : HasGovState LState
  HasGovState-LState .GovStateOf = LState.govSt

  HasCertState-LState : HasCertState LState
  HasCertState-LState .CertStateOf = LState.certState

  HasDeposits-LState : HasDeposits LState
  HasDeposits-LState .DepositsOf = DepositsOf  UTxOStateOf

open CertState
open DState

instance
  unquoteDecl HasCast-LEnv HasCast-LState = derive-HasCast
    ((quote LEnv , HasCast-LEnv)  (quote LState , HasCast-LState)  [])


txgov : TxBody  List (GovVote  GovProposal)
txgov txb = map inj₂ txprop ++ map inj₁ txvote
  where open TxBody txb

rmOrphanDRepVotes : CertState  GovState  GovState
rmOrphanDRepVotes cs govSt = L.map (map₂ go) govSt
  where
   ifDRepRegistered : Voter  Type
   ifDRepRegistered (r , c) = r  DRep  c  dom (cs .gState .dreps)

   go : GovActionState  GovActionState
   go gas = record gas { votes = filterKeys ifDRepRegistered (gas .votes) }

allColdCreds : GovState  EnactState   Credential
allColdCreds govSt es =
  ccCreds (es .cc)  concatMapˢ  (_ , st)  proposedCC (st .action)) (fromList govSt)


private variable
  Γ : LEnv
  s s' s'' : LState
  utxoSt utxoSt' : UTxOState
  govSt govSt' : GovState
  certState certState' : CertState
  tx : Tx
  slot : Slot
  ppolicy : Maybe ScriptHash
  pp : PParams
  enactState : EnactState
  treasury : Coin


data _⊢_⇀⦇_,LEDGER⦈_ : LEnv  LState  Tx  LState  Type where

  LEDGER-V :
    let  txb         = tx .body


         open TxBody txb


         rewards     = certState .dState .rewards
    in
     isValid tx  true
      slot , pp , treasury    utxoSt ⇀⦇ tx ,UTXOW⦈ utxoSt'
      epoch slot , pp , txvote , txwdrls , allColdCreds govSt enactState   certState ⇀⦇ txcerts ,CERTS⦈ certState'
      txid , epoch slot , pp , ppolicy , enactState , certState' , dom rewards   rmOrphanDRepVotes certState' govSt ⇀⦇ txgov txb ,GOVS⦈ govSt'
      ────────────────────────────────
       slot , ppolicy , pp , enactState , treasury    utxoSt , govSt , certState  ⇀⦇ tx ,LEDGER⦈  utxoSt' , govSt' , certState' 

  LEDGER-I :
     isValid tx  false
      slot , pp , treasury   utxoSt ⇀⦇ tx ,UTXOW⦈ utxoSt'
      ────────────────────────────────
       slot , ppolicy , pp , enactState , treasury    utxoSt , govSt , certState  ⇀⦇ tx ,LEDGER⦈  utxoSt' , govSt , certState 


pattern LEDGER-V⋯ w x y z = LEDGER-V (w , x , y , z)
pattern LEDGER-I⋯ y z     = LEDGER-I (y , z)


_⊢_⇀⦇_,LEDGERS⦈_ : LEnv  LState  List Tx  LState  Type
_⊢_⇀⦇_,LEDGERS⦈_ = ReflexiveTransitiveClosure {sts = _⊢_⇀⦇_,LEDGER⦈_}