use rand::Rng;

use crate::common::hash::Hash256;
use crate::common::inscriptions::{Address, Genesis, InscriptionNumber, Outpoint};
use crate::common::mime;
use crate::common::tokens::InscriptionProtocol;
use crate::utils::sha256::IntoHash256;

use super::electrs::BlockInfo;

/// Block data that content will pull from dataswamp
#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
pub struct ContentBlockData {
    pub block_info: BlockInfo,
    pub inscriptions: Vec<ContentInscriptionData>,
    pub moves: Vec<ContentMoveData>,
}

#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
pub struct ContentMoveData {
    pub is_creation: bool,
    pub from: Address,
    pub to: Address,
    pub number: InscriptionNumber,
}

#[derive(Clone, serde::Serialize, serde::Deserialize, Debug)]
pub struct ContentInscriptionData {
    pub content_type: mime::Extension,
    // pub content: Vec<u8>,
    pub content_hash: Hash256,
    pub content_len: usize,
    pub genesis: Genesis,
    pub number: InscriptionNumber,
    pub genesis_fee: u64,
    pub protocol: Option<InscriptionProtocol>,
}

impl ContentInscriptionData {
    pub fn randomized(num: InscriptionNumber) -> Self {
        let mut rnd = rand::thread_rng();
        let genesis = Genesis(Outpoint::randomized());
        let genesis_fee = rnd.gen_range(0..1_000_000);
        let content = rnd.gen_range(0..1_000_000).to_string().into_bytes();

        Self {
            content_type: mime::Extension::Other(mime::Other::Bytes),
            content_hash: content.hash_256(),
            content_len: content.len(),
            genesis,
            number: num,
            genesis_fee,
            protocol: None,
        }
    }
}

mod adapter {
    use itertools::Itertools;

    use crate::{
        common::{
            hash::Hash256,
            mime::{Extension, Other},
        },
        external::electrs::{ElectrsDataswampBlock, InscriptionMove, ProtocolKey},
        utils::sha256::IntoHash256,
    };

    use super::{ContentBlockData, ContentInscriptionData, ContentMoveData};

    impl From<ElectrsDataswampBlock> for ContentBlockData {
        fn from(val: ElectrsDataswampBlock) -> Self {
            Self {
                block_info: val.block_info,
                inscriptions: val
                    .inscriptions
                    .into_iter()
                    .map(|v| ContentInscriptionData {
                        content_type: v.content_type.unwrap_or_default().parse().unwrap_or(Extension::Other(Other::Bytes)),
                        content_hash: v.content.as_ref().map(|x| x.hash_256()).unwrap_or_else(|| Hash256::EMPTY),
                        content_len: v.content.as_ref().map(|x| x.len()).unwrap_or_default(),
                        number: v.number,
                        genesis_fee: v.genesis_fee,
                        protocol: val
                            .protocol
                            .get(&ProtocolKey {
                                tx_index: v.tx_index,
                                inscription_number: v.number,
                            })
                            .cloned(),
                        genesis: v.location.genesis,
                    })
                    .collect_vec(),
                moves: val.moves_history.into_iter().map(|v| v.into()).collect_vec(),
            }
        }
    }

    impl From<InscriptionMove> for ContentMoveData {
        fn from(v: InscriptionMove) -> Self {
            Self {
                is_creation: false,
                from: v.from,
                to: v.to,
                number: v.inscription_number,
            }
        }
    }
}
