// LNP/BP Rust Library
// Written in 2020 by
//     Dr. Maxim Orlovsky <orlovsky@pandoracore.com>
//
// To the extent possible under law, the author(s) have dedicated all
// copyright and related and neighboring rights to this software to
// the public domain worldwide. This software is distributed without
// any warranty.
//
// You should have received a copy of the MIT License
// along with this software.
// If not, see <https://opensource.org/licenses/MIT>.

use super::{Genesis, Transition};
use bitcoin::hashes::{sha256t, Hash};

// TODO: Check the data
static MIDSTATE_CONTRACT_ID: [u8; 32] = [
    25, 205, 224, 91, 171, 217, 131, 31, 140, 104, 5, 155, 127, 82, 14, 81, 58, 245, 79, 165, 114,
    243, 110, 60, 133, 174, 103, 187, 103, 230, 9, 106,
];

// TODO: Check the data
static MIDSTATE_TRANSITION_ID: [u8; 32] = [
    25, 205, 224, 91, 171, 217, 131, 31, 140, 104, 5, 155, 127, 82, 14, 81, 58, 245, 79, 165, 114,
    243, 110, 60, 133, 174, 103, 187, 103, 230, 9, 106,
];

tagged_hash!(
    ContractId,
    ContractIdTag,
    MIDSTATE_CONTRACT_ID,
    doc = "Unique contract identifier equivalent to the contract genesis commitment hash"
);

tagged_hash!(
    TransitionId,
    TransitionIdTag,
    MIDSTATE_TRANSITION_ID,
    doc = "Unique transition identifier equivalent to the state transition commitment hash"
);

/// The structure for a specific contract. Contract always have a part of the
/// information that is fully known (we use term *revealed*), i.e. the
/// information related to the state you have issued and the transfers you have
/// created, and partially-known (*partial*), like the one behind zero knowledge
/// proofs, merkle trees and blinded seals; this is an information you received
/// with *consignments* from other parties or that have resulted from the
/// [Stash::forget] and [Stash::prune] operations on your previously-owned
/// (but now transferred) state. To efficiently operate with privacy management
/// the revealed and partial state transitions are kept separate. We re-use
/// the same Transition data structures for both, but use generic polymorphism
/// with associated types to clearly distinguish transitions with partial and
/// revealed data underneath.
pub struct Contract {
    pub genesis: Genesis,
    pub revealed: Vec<Transition>,
    pub partial: Vec<Transition>,
}

mod strict_encoding {
    use std::io;

    use super::*;
    use crate::strict_encoding::{Error, StrictDecode, StrictEncode};

    // TODO: Use derive macros and generalized `tagged_hash!` in the future
    impl StrictEncode for ContractId {
        type Error = Error;

        #[inline]
        fn strict_encode<E: io::Write>(&self, e: E) -> Result<usize, Self::Error> {
            self.into_inner().to_vec().strict_encode(e)
        }
    }

    impl StrictDecode for ContractId {
        type Error = Error;

        #[inline]
        fn strict_decode<D: io::Read>(d: D) -> Result<Self, Self::Error> {
            Ok(
                Self::from_slice(&Vec::<u8>::strict_decode(d)?).map_err(|_| {
                    Error::DataIntegrityError("Wrong SHA-256 hash data size".to_string())
                })?,
            )
        }
    }

    // TODO: Use derive macros and generalized `tagged_hash!` in the future
    impl StrictEncode for TransitionId {
        type Error = Error;

        #[inline]
        fn strict_encode<E: io::Write>(&self, e: E) -> Result<usize, Self::Error> {
            self.into_inner().to_vec().strict_encode(e)
        }
    }

    impl StrictDecode for TransitionId {
        type Error = Error;

        #[inline]
        fn strict_decode<D: io::Read>(d: D) -> Result<Self, Self::Error> {
            Ok(
                Self::from_slice(&Vec::<u8>::strict_decode(d)?).map_err(|_| {
                    Error::DataIntegrityError("Wrong SHA-256 hash data size".to_string())
                })?,
            )
        }
    }
}
