//! Known peer nodes for P2P discovery and connection.

use anyhow::{Context, Result};
use serde::{Deserialize, Serialize};
use std::path::Path;
use tokio::fs;

#[derive(Debug, Clone, Serialize, Deserialize)]
pub struct KnownPeer {
    pub onion: String,
    pub pubkey: String,
    #[serde(default)]
    pub name: Option<String>,
    #[serde(default)]
    pub added_at: Option<String>,
}

#[derive(Debug, Default, Serialize, Deserialize)]
pub struct PeersFile {
    pub peers: Vec<KnownPeer>,
}

const PEERS_FILE: &str = "peers.json";

pub async fn load_peers(data_dir: &Path) -> Result<Vec<KnownPeer>> {
    let path = data_dir.join(PEERS_FILE);
    if !path.exists() {
        return Ok(Vec::new());
    }
    let content = fs::read_to_string(&path)
        .await
        .context("Failed to read peers file")?;
    let file: PeersFile = serde_json::from_str(&content).unwrap_or_default();
    Ok(file.peers)
}

pub async fn save_peers(data_dir: &Path, peers: &[KnownPeer]) -> Result<()> {
    let path = data_dir.join(PEERS_FILE);
    fs::create_dir_all(data_dir).await.context("Failed to create data dir")?;
    let file = PeersFile {
        peers: peers.to_vec(),
    };
    let content = serde_json::to_string_pretty(&file).context("Failed to serialize peers")?;
    fs::write(&path, content).await.context("Failed to write peers file")?;
    Ok(())
}

pub async fn add_peer(data_dir: &Path, peer: KnownPeer) -> Result<Vec<KnownPeer>> {
    let mut peers = load_peers(data_dir).await?;
    let exists = peers.iter().any(|p| p.pubkey == peer.pubkey);
    if !exists {
        peers.push(peer);
        save_peers(data_dir, &peers).await?;
    }
    Ok(peers)
}

pub async fn remove_peer(data_dir: &Path, pubkey: &str) -> Result<Vec<KnownPeer>> {
    let mut peers = load_peers(data_dir).await?;
    peers.retain(|p| p.pubkey != pubkey);
    save_peers(data_dir, &peers).await?;
    Ok(peers)
}
