-- {-# OPTIONS_GHC -fwarn-incomplete-patterns -Werror #-}

module Data.Bitcoin.PaymentChannel.Internal.Script where

import Data.Bitcoin.PaymentChannel.Internal.Types
import Data.Bitcoin.PaymentChannel.Internal.Serialization
import Data.Bitcoin.PaymentChannel.Internal.Util

import qualified  Network.Haskoin.Internals as HI
import qualified  Network.Haskoin.Util as HU
import qualified  Network.Haskoin.Crypto as HC
import Network.Haskoin.Script
    (Script(..), SigHash(..), ScriptOp(..), opPushData)

import qualified Data.ByteString as B
import qualified Data.ByteString.Char8 as C
import qualified Data.ByteString.Lazy as BL
import qualified Data.Binary as Bin
import Data.Word
import Data.Char as CH

valReceiverSigHash = SigAll True

getSigHashFlag :: BitcoinAmount -> SigHash
getSigHashFlag valueToSender =
    if valueToSender == 0 then
        SigNone True
    else
        SigSingle True

sigHashToByte :: SigHash -> Word8
sigHashToByte = fromIntegral . ord . head . C.unpack . serialize

-- |Generates OP_CHECKLOCKTIMEVERIFY redeemScript
paymentChannelRedeemScript :: SendPubKey -> RecvPubKey -> Word32 -> Script
paymentChannelRedeemScript clientPK serverPK lockTime = Script
     [OP_IF,
         opPushData $ serialize (getPubKey serverPK), OP_CHECKSIGVERIFY,
     OP_ELSE,
         encodeScriptInt lockTime, op_CHECKLOCKTIMEVERIFY, OP_DROP,
     OP_ENDIF,
     opPushData $ serialize (getPubKey clientPK), OP_CHECKSIG]
         where encodeScriptInt i = opPushData $ B.pack $ HI.encodeInt (fromIntegral i)
            -- Note: HI.encodeInt encodes values up to and including 2^31-1 as 4 bytes
            --      and values 2^31 through 2^32-1 (upper limit) as 5 bytes.

-- |scriptSig fulfilling a payment channel redeemScript
paymentTxScriptSig :: PaymentSignature -> PaymentSignature -> Script --ScriptSig
paymentTxScriptSig clientSig serverSig = Script
    [opPushData $ serialize clientSig, --sig including SigHash byte
    opPushData $ serialize serverSig, --sig including SigHash byte
    OP_1]

-- |scriptSig used for the valueSender refund transaction
refundTxScriptSig :: HC.Signature -> Script
refundTxScriptSig clientSig = Script
    [opPushData (B.append (serialize clientSig) hashTypeByte),
    OP_0]
        where hashTypeByte = serialize (SigAll False)

-----Util-----

op_CHECKLOCKTIMEVERIFY = OP_NOP2

scriptToP2SHAddress :: Script -> HC.Address
scriptToP2SHAddress = HC.ScriptAddress . HC.hash160 . HC.getHash256 . HC.hash256 . serialize


getP2SHFundingAddress :: ChannelParameters -> HC.Address
getP2SHFundingAddress = scriptToP2SHAddress . getRedeemScript

getRedeemScript :: ChannelParameters -> Script --RedeemScript
getRedeemScript (CChannelParameters senderPK recvrPK lockTime) =
    paymentChannelRedeemScript senderPK recvrPK (toWord32 lockTime)

getRedeemScriptBS :: ChannelParameters -> B.ByteString
getRedeemScriptBS = serialize . getRedeemScript

getInputScript :: ChannelParameters -> Script -> Script
getInputScript cp scriptSig =
    Script $ scriptOps scriptSig ++ redeemScript
        where
             redeemScript = [opPushData $ getRedeemScriptBS cp]