{-# LANGUAGE DataKinds #-}
{-# LANGUAGE LambdaCase #-}

module Cardano.CLI.EraBased.Script.Type
  ( -- * Script requirements per context
    SimpleScriptRequirements (..)
  , PlutusSpendingScriptRequirements (..)
  , PlutusMintingScriptRequirements (..)
  , PlutusNonAssetScriptRequirements (..)

    -- * Command-level sum types
  , AnySpendScript (..)
  , AnyMintScript (..)
  , AnyNonAssetScript (..)

    -- * Datum
  , ScriptDatumOrFileSpending (..)

    -- * Errors
  , CliScriptWitnessError (..)
  )
where

import Cardano.Api
import Cardano.Api.Ledger qualified as L

import Cardano.CLI.Type.Common

data CliScriptWitnessError
  = PlutusScriptWitnessLanguageNotSupportedInEra
      L.Language
      AnyShelleyBasedEra
  deriving Int -> CliScriptWitnessError -> ShowS
[CliScriptWitnessError] -> ShowS
CliScriptWitnessError -> String
(Int -> CliScriptWitnessError -> ShowS)
-> (CliScriptWitnessError -> String)
-> ([CliScriptWitnessError] -> ShowS)
-> Show CliScriptWitnessError
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> CliScriptWitnessError -> ShowS
showsPrec :: Int -> CliScriptWitnessError -> ShowS
$cshow :: CliScriptWitnessError -> String
show :: CliScriptWitnessError -> String
$cshowList :: [CliScriptWitnessError] -> ShowS
showList :: [CliScriptWitnessError] -> ShowS
Show

instance Error CliScriptWitnessError where
  prettyError :: forall ann. CliScriptWitnessError -> Doc ann
prettyError = \case
    PlutusScriptWitnessLanguageNotSupportedInEra Language
version AnyShelleyBasedEra
era ->
      Doc ann
"Plutus script version " Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Language -> Doc ann
forall a ann. Show a => a -> Doc ann
pshow Language
version Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> Doc ann
" is not supported in era " Doc ann -> Doc ann -> Doc ann
forall a. Semigroup a => a -> a -> a
<> AnyShelleyBasedEra -> Doc ann
forall a ann. Show a => a -> Doc ann
pshow AnyShelleyBasedEra
era

data ScriptDatumOrFileSpending
  = PotentialDatum (Maybe ScriptDataOrFile)
  | InlineDatum
  deriving Int -> ScriptDatumOrFileSpending -> ShowS
[ScriptDatumOrFileSpending] -> ShowS
ScriptDatumOrFileSpending -> String
(Int -> ScriptDatumOrFileSpending -> ShowS)
-> (ScriptDatumOrFileSpending -> String)
-> ([ScriptDatumOrFileSpending] -> ShowS)
-> Show ScriptDatumOrFileSpending
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> ScriptDatumOrFileSpending -> ShowS
showsPrec :: Int -> ScriptDatumOrFileSpending -> ShowS
$cshow :: ScriptDatumOrFileSpending -> String
show :: ScriptDatumOrFileSpending -> String
$cshowList :: [ScriptDatumOrFileSpending] -> ShowS
showList :: [ScriptDatumOrFileSpending] -> ShowS
Show

-- | Simple script provided either on disk or as a reference input.
-- Shared across all script contexts since simple scripts have no
-- context-specific fields.
data SimpleScriptRequirements
  = OnDiskSimpleScript (File ScriptInAnyLang In)
  | ReferenceSimpleScript TxIn
  deriving Int -> SimpleScriptRequirements -> ShowS
[SimpleScriptRequirements] -> ShowS
SimpleScriptRequirements -> String
(Int -> SimpleScriptRequirements -> ShowS)
-> (SimpleScriptRequirements -> String)
-> ([SimpleScriptRequirements] -> ShowS)
-> Show SimpleScriptRequirements
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> SimpleScriptRequirements -> ShowS
showsPrec :: Int -> SimpleScriptRequirements -> ShowS
$cshow :: SimpleScriptRequirements -> String
show :: SimpleScriptRequirements -> String
$cshowList :: [SimpleScriptRequirements] -> ShowS
showList :: [SimpleScriptRequirements] -> ShowS
Show

-- | Plutus script requirements for spending. Spending is the only context
-- that carries an optional datum (CIP-69).
data PlutusSpendingScriptRequirements
  = OnDiskPlutusSpendingScript
      (File ScriptInAnyLang In)
      ScriptDatumOrFileSpending
      -- ^ Optional Datum (CIP-69)
      ScriptDataOrFile
      -- ^ Redeemer
      ExecutionUnits
  | ReferencePlutusSpendingScript
      TxIn
      -- ^ TxIn with reference script
      AnySLanguage
      ScriptDatumOrFileSpending
      -- ^ Optional Datum (CIP-69)
      ScriptDataOrFile
      -- ^ Redeemer
      ExecutionUnits
  deriving Int -> PlutusSpendingScriptRequirements -> ShowS
[PlutusSpendingScriptRequirements] -> ShowS
PlutusSpendingScriptRequirements -> String
(Int -> PlutusSpendingScriptRequirements -> ShowS)
-> (PlutusSpendingScriptRequirements -> String)
-> ([PlutusSpendingScriptRequirements] -> ShowS)
-> Show PlutusSpendingScriptRequirements
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PlutusSpendingScriptRequirements -> ShowS
showsPrec :: Int -> PlutusSpendingScriptRequirements -> ShowS
$cshow :: PlutusSpendingScriptRequirements -> String
show :: PlutusSpendingScriptRequirements -> String
$cshowList :: [PlutusSpendingScriptRequirements] -> ShowS
showList :: [PlutusSpendingScriptRequirements] -> ShowS
Show

-- | Plutus script requirements for minting. Minting requires a 'PolicyId' so
-- the CLI can validate that every policy being minted has a corresponding
-- script witness and vice versa (see @createTxMintValue@). For on-disk scripts
-- the 'PolicyId' is computed from the script hash; for reference scripts the
-- user must supply it because the script bytes aren't available locally.
data PlutusMintingScriptRequirements
  = OnDiskPlutusMintingScript
      (File ScriptInAnyLang In)
      ScriptDataOrFile
      -- ^ Redeemer
      ExecutionUnits
  | ReferencePlutusMintingScript
      TxIn
      -- ^ TxIn with reference script
      AnySLanguage
      PolicyId
      -- ^ Needed for plutus minting scripts
      ScriptDataOrFile
      -- ^ Redeemer
      ExecutionUnits
  deriving Int -> PlutusMintingScriptRequirements -> ShowS
[PlutusMintingScriptRequirements] -> ShowS
PlutusMintingScriptRequirements -> String
(Int -> PlutusMintingScriptRequirements -> ShowS)
-> (PlutusMintingScriptRequirements -> String)
-> ([PlutusMintingScriptRequirements] -> ShowS)
-> Show PlutusMintingScriptRequirements
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PlutusMintingScriptRequirements -> ShowS
showsPrec :: Int -> PlutusMintingScriptRequirements -> ShowS
$cshow :: PlutusMintingScriptRequirements -> String
show :: PlutusMintingScriptRequirements -> String
$cshowList :: [PlutusMintingScriptRequirements] -> ShowS
showList :: [PlutusMintingScriptRequirements] -> ShowS
Show

-- | Plutus script requirements for non-asset contexts (certificates, voting,
-- withdrawals, proposals). These contexts need neither a datum nor a policy id,
-- so they share a single type.
data PlutusNonAssetScriptRequirements
  = OnDiskPlutusNonAssetScript
      (File ScriptInAnyLang In)
      ScriptDataOrFile
      -- ^ Redeemer
      ExecutionUnits
  | ReferencePlutusNonAssetScript
      TxIn
      -- ^ TxIn with reference script
      AnySLanguage
      ScriptDataOrFile
      -- ^ Redeemer
      ExecutionUnits
  deriving Int -> PlutusNonAssetScriptRequirements -> ShowS
[PlutusNonAssetScriptRequirements] -> ShowS
PlutusNonAssetScriptRequirements -> String
(Int -> PlutusNonAssetScriptRequirements -> ShowS)
-> (PlutusNonAssetScriptRequirements -> String)
-> ([PlutusNonAssetScriptRequirements] -> ShowS)
-> Show PlutusNonAssetScriptRequirements
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> PlutusNonAssetScriptRequirements -> ShowS
showsPrec :: Int -> PlutusNonAssetScriptRequirements -> ShowS
$cshow :: PlutusNonAssetScriptRequirements -> String
show :: PlutusNonAssetScriptRequirements -> String
$cshowList :: [PlutusNonAssetScriptRequirements] -> ShowS
showList :: [PlutusNonAssetScriptRequirements] -> ShowS
Show

-- | A spending script witness — simple or Plutus.
data AnySpendScript
  = AnySpendScriptSimple SimpleScriptRequirements
  | AnySpendScriptPlutus PlutusSpendingScriptRequirements
  deriving Int -> AnySpendScript -> ShowS
[AnySpendScript] -> ShowS
AnySpendScript -> String
(Int -> AnySpendScript -> ShowS)
-> (AnySpendScript -> String)
-> ([AnySpendScript] -> ShowS)
-> Show AnySpendScript
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> AnySpendScript -> ShowS
showsPrec :: Int -> AnySpendScript -> ShowS
$cshow :: AnySpendScript -> String
show :: AnySpendScript -> String
$cshowList :: [AnySpendScript] -> ShowS
showList :: [AnySpendScript] -> ShowS
Show

-- | A minting script witness — simple or Plutus.
-- Simple minting scripts are split into on-disk and reference variants because
-- the 'PolicyId' for on-disk scripts is computed from the script hash at read
-- time, while reference scripts require the user to supply it via the CLI.
data AnyMintScript
  = AnyMintScriptSimpleOnDisk (File ScriptInAnyLang In)
  | AnyMintScriptSimpleRef TxIn PolicyId
  | AnyMintScriptPlutus PlutusMintingScriptRequirements
  deriving Int -> AnyMintScript -> ShowS
[AnyMintScript] -> ShowS
AnyMintScript -> String
(Int -> AnyMintScript -> ShowS)
-> (AnyMintScript -> String)
-> ([AnyMintScript] -> ShowS)
-> Show AnyMintScript
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> AnyMintScript -> ShowS
showsPrec :: Int -> AnyMintScript -> ShowS
$cshow :: AnyMintScript -> String
show :: AnyMintScript -> String
$cshowList :: [AnyMintScript] -> ShowS
showList :: [AnyMintScript] -> ShowS
Show

-- | A non-asset script witness — simple or Plutus.
-- Used for certificates, voting, withdrawals, and proposals.
data AnyNonAssetScript
  = AnyNonAssetScriptSimple SimpleScriptRequirements
  | AnyNonAssetScriptPlutus PlutusNonAssetScriptRequirements
  deriving Int -> AnyNonAssetScript -> ShowS
[AnyNonAssetScript] -> ShowS
AnyNonAssetScript -> String
(Int -> AnyNonAssetScript -> ShowS)
-> (AnyNonAssetScript -> String)
-> ([AnyNonAssetScript] -> ShowS)
-> Show AnyNonAssetScript
forall a.
(Int -> a -> ShowS) -> (a -> String) -> ([a] -> ShowS) -> Show a
$cshowsPrec :: Int -> AnyNonAssetScript -> ShowS
showsPrec :: Int -> AnyNonAssetScript -> ShowS
$cshow :: AnyNonAssetScript -> String
show :: AnyNonAssetScript -> String
$cshowList :: [AnyNonAssetScript] -> ShowS
showList :: [AnyNonAssetScript] -> ShowS
Show