use crate::storage::Storage;
use heed::types::{SerdeRmp, Str};
use heed::{Database, DatabaseFlags, RoTxn};
use nostr_sdk::prelude::*;
use serde::{Deserialize, Serialize};
use std::error::Error;

#[derive(Clone, Debug, PartialEq, Eq)]
pub enum EvRelationship {
    // NIP-01, NIP-10 replies
    Reply,

    // NIP-03 OpenTimestamps Attestations for Events
    Timestamp,

    // NIP-09 Event Deletion
    Deletion { by: PublicKey, reason: String },

    // NIP-25 Reactions
    Reaction { by: PublicKey, reaction: String },

    // NIP-32 Labeling
    Labels { label: String, namespace: String },

    // NIP-51 Lists
    ListMutesThread,
}

#[derive(Debug, Serialize, Deserialize)]
pub struct EventRelationship<'a> {
    #[serde(borrow)]
    pub dst_event_id: &'a str,
    pub rtype: &'a str,
}

/* Event relationships database */
type EvRelDatabaseDatabase<'a> = Database<Str, SerdeRmp<EventRelationship<'a>>>;

impl Storage {
    pub fn evrels_db(
        &self,
    ) -> Result<EvRelDatabaseDatabase<'_>, Box<dyn Error + Send + Sync>> {
        let mut wtxn = self.env.write_txn()?;
        let db = self
            .env
            .database_options()
            .types::<Str, SerdeRmp<EventRelationship>>()
            .flags(DatabaseFlags::DUP_SORT)
            .name("event_relations_dup00")
            .create(&mut wtxn)?;

        wtxn.commit()?;
        Ok(db)
    }

    pub fn event_relation_store(
        &self,
        _rtxn: &mut RoTxn,
        src_event_id: EventId,
        dst_event_id: EventId,
        rtype: &str,
    ) -> Result<(), Box<dyn Error>> {
        let seid = src_event_id.to_hex();
        let deid = dst_event_id.to_hex();

        if let Ok(db) = self.evrels_db() {
            let mut wtxn = self.env.write_txn()?;

            let rel = EventRelationship {
                dst_event_id: deid.as_str(),
                rtype,
            };

            let _ = db.put(&mut wtxn, seid.as_str(), &rel);

            wtxn.commit()?;

            return Ok(());
        }

        Err(Box::from("err"))
    }

    pub fn find_event_relations<'c>(
        &'c self,
        rtxn: &'c mut RoTxn,
        src_event_id: EventId,
        rtype: &str,
    ) -> Result<Vec<EventId>, Box<dyn Error + Send + Sync>> {
        let seid = src_event_id.to_hex();
        let mut ids: Vec<EventId> = Vec::new();

        if let Ok(db) = self.evrels_db() {
            let Some(values) = db.get_duplicates(rtxn, seid.as_str())? else {
                println!("none for {}", seid);
                return Ok(ids);
            };

            for val in values {
                let (_, rel) = val?;

                if rel.rtype == rtype {
                    let evid = EventId::parse(rel.dst_event_id).unwrap();
                    ids.push(evid);
                }
            }

            return Ok(ids);
        }
        Err(Box::from("err"))
    }
}
