use alloy_primitives::Address;
use clickhouse::Row;
use redefined::Redefined;
use reth_rpc_types::beacon::BlsPublicKey;
use rkyv::{Archive, Deserialize as rDeserialize, Serialize as rSerialize};
use serde::{Deserialize, Serialize};
use serde_with::serde_as;
use crate::{
    db::{
        redefined_types::primitives::{AddressRedefined, BlsPublicKeyRedefined},
        searcher::Fund,
    },
    implement_table_value_codecs_with_zc,
    serde_utils::{addresss, option_addresss, option_fund, vec_address, vec_bls_pub_key},
    FastHashSet,
};
#[derive(Debug, Default, Row, PartialEq, Clone, Eq, Serialize, Deserialize, Redefined)]
#[redefined_attr(derive(Debug, PartialEq, Clone, Serialize, rSerialize, rDeserialize, Archive))]
pub struct BuilderInfo {
    pub name: Option<String>,
    #[redefined(same_fields)]
    #[serde(deserialize_with = "option_fund::deserialize")]
    #[serde(default)]
    pub fund: Option<Fund>,
    #[serde(with = "vec_bls_pub_key")]
    #[serde(default)]
    pub pub_keys: Vec<BlsPublicKey>,
    #[serde(with = "vec_address")]
    #[serde(default)]
    pub searchers_eoas: Vec<Address>,
    #[serde(with = "vec_address")]
    #[serde(default)]
    pub searchers_contracts: Vec<Address>,
    #[serde(with = "option_addresss")]
    #[serde(default)]
    pub ultrasound_relay_collateral_address: Option<Address>,
}
impl BuilderInfo {
    pub fn merge(&mut self, other: BuilderInfo) {
        self.name = other.name.or(self.name.take());
        self.fund = other.fund.or(self.fund.take());
        self.pub_keys = self
            .pub_keys
            .iter()
            .chain(other.pub_keys.iter())
            .cloned()
            .collect::<FastHashSet<_>>()
            .into_iter()
            .collect();
        self.searchers_eoas = self
            .searchers_eoas
            .iter()
            .chain(other.searchers_eoas.iter())
            .cloned()
            .collect::<FastHashSet<_>>()
            .into_iter()
            .collect();
        self.searchers_contracts = self
            .searchers_contracts
            .iter()
            .chain(other.searchers_contracts.iter())
            .cloned()
            .collect::<FastHashSet<_>>()
            .into_iter()
            .collect();
        self.ultrasound_relay_collateral_address = other
            .ultrasound_relay_collateral_address
            .or(self.ultrasound_relay_collateral_address.take());
    }
    pub fn describe(&self) -> String {
        let mut description = String::new();
        if let Some(name) = &self.name {
            description.push_str(name);
        } else {
            description.push_str("Unknown Block Builder");
        }
        description
    }
}
implement_table_value_codecs_with_zc!(BuilderInfoRedefined);
#[serde_as]
#[derive(Debug, Default, Row, PartialEq, Clone, Serialize, Deserialize)]
pub struct BuilderInfoWithAddress {
    #[serde(with = "addresss")]
    pub address: Address,
    pub name: Option<String>,
    #[serde(deserialize_with = "option_fund::deserialize")]
    pub fund: Option<Fund>,
    #[serde(with = "vec_bls_pub_key")]
    pub pub_keys: Vec<BlsPublicKey>,
    #[serde(with = "vec_address")]
    pub searchers_eoas: Vec<Address>,
    #[serde(with = "vec_address")]
    pub searchers_contracts: Vec<Address>,
    #[serde(with = "option_addresss")]
    pub ultrasound_relay_collateral_address: Option<Address>,
}
impl BuilderInfoWithAddress {
    pub fn new_with_address(address: Address, info: BuilderInfo) -> Self {
        Self {
            address,
            name: info.name,
            fund: info.fund,
            pub_keys: info.pub_keys,
            searchers_eoas: info.searchers_eoas,
            searchers_contracts: info.searchers_contracts,
            ultrasound_relay_collateral_address: info.ultrasound_relay_collateral_address,
        }
    }
}