//   Copyright 2024. The Tari Project
//
//   Redistribution and use in source and binary forms, with or without modification, are permitted provided that the
//   following conditions are met:
//
//   1. Redistributions of source code must retain the above copyright notice, this list of conditions and the following
//   disclaimer.
//
//   2. Redistributions in binary form must reproduce the above copyright notice, this list of conditions and the
//   following disclaimer in the documentation and/or other materials provided with the distribution.
//
//   3. Neither the name of the copyright holder nor the names of its contributors may be used to endorse or promote
//   products derived from this software without specific prior written permission.
//
//   THIS SOFTWARE IS PROVIDED BY THE COPYRIGHT HOLDERS AND CONTRIBUTORS "AS IS" AND ANY EXPRESS OR IMPLIED WARRANTIES,
//   INCLUDING, BUT NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR A PARTICULAR PURPOSE ARE
//   DISCLAIMED. IN NO EVENT SHALL THE COPYRIGHT HOLDER OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, INDIRECT, INCIDENTAL,
//   SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR
//   SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY,
//   WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF THE
//   USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF SUCH DAMAGE.

use std::collections::BTreeMap;

use borsh::BorshSerialize;
use serde::{Deserialize, Serialize};

use crate::MaxSizeBytes;

const MAX_DATA_SIZE: usize = 256;
type ExtraFieldValue = MaxSizeBytes<MAX_DATA_SIZE>;

#[repr(u8)]
#[derive(Clone, Debug, Ord, PartialOrd, Eq, PartialEq, Serialize, Deserialize, BorshSerialize)]
#[borsh(use_discriminant = true)]
pub enum ExtraFieldKey {
    SidechainId = 0x00,
    Custom = 0xff,
}

#[derive(Clone, Debug, Deserialize, Serialize, Default, BorshSerialize)]
#[cfg_attr(feature = "ts", derive(ts_rs::TS), ts(export))]
pub struct ExtraData(
    #[cfg_attr(feature = "ts", ts(type = "Record<string, any>"))] BTreeMap<ExtraFieldKey, ExtraFieldValue>,
);

impl ExtraData {
    pub const fn new() -> Self {
        Self(BTreeMap::new())
    }

    pub fn insert(&mut self, key: ExtraFieldKey, value: ExtraFieldValue) -> &mut Self {
        self.0.insert(key, value);
        self
    }

    pub fn get(&self, key: &ExtraFieldKey) -> Option<&ExtraFieldValue> {
        self.0.get(key)
    }

    pub fn contains_key(&self, key: &ExtraFieldKey) -> bool {
        self.0.contains_key(key)
    }
}
