//! Block types for Moloch.
//!
//! Blocks batch audit events together and link to form the chain.

use chrono::{DateTime, Utc};
use serde::{Deserialize, Serialize};

use crate::crypto::{hash, hash_pair, Hash, PublicKey, SecretKey, Sig};
use crate::error::{Error, Result};
use crate::event::{AuditEvent, EventId};

/// Unique identifier for a block (hash of header).
#[derive(Debug, Clone, Copy, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct BlockHash(pub Hash);

impl BlockHash {
    /// The zero block hash (used for genesis parent).
    pub const ZERO: Self = Self(Hash::ZERO);

    /// Get the underlying hash.
    pub fn as_hash(&self) -> &Hash {
        &self.0
    }

    /// Create a block hash from a header.
    pub fn from_header(header: &BlockHeader) -> Self {
        header.hash()
    }
}

impl std::fmt::Display for BlockHash {
    fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
        write!(f, "{}", self.0)
    }
}

/// Identifies a sealer (block producer).
#[derive(Debug, Clone, PartialEq, Eq, Hash, Serialize, Deserialize)]
pub struct SealerId {
    /// Sealer's public key.
    pub key: PublicKey,
    /// Human-readable name.
    pub name: Option<String>,
}

impl SealerId {
    /// Create a new sealer ID.
    pub fn new(key: PublicKey) -> Self {
        Self { key, name: None }
    }

    /// Add a display name.
    pub fn with_name(mut self, name: impl Into<String>) -> Self {
        self.name = Some(name.into());
        self
    }

    /// Get the unique hash ID for this sealer.
    pub fn id(&self) -> Hash {
        self.key.id()
    }

    /// Get the public key.
    pub fn as_pubkey(&self) -> &PublicKey {
        &self.key
    }
}

/// Block header containing metadata and proofs.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct BlockHeader {
    /// Block height (monotonically increasing).
    pub height: u64,

    /// Hash of parent block header.
    pub parent: BlockHash,

    /// Merkle root of events in this block.
    pub events_root: Hash,

    /// Number of events in this block.
    pub events_count: u32,

    /// MMR root after this block (cumulative chain state).
    pub mmr_root: Hash,

    /// Sealer's timestamp (must be >= parent timestamp), as Unix millis.
    #[serde(with = "chrono::serde::ts_milliseconds")]
    pub timestamp: DateTime<Utc>,

    /// Identity of the sealer who produced this block.
    pub sealer: SealerId,

    /// Sealer's signature over the header (excluding this field).
    pub seal: Sig,
}

impl BlockHeader {
    /// Get the bytes to be signed (everything except the seal).
    pub fn signing_bytes(&self) -> Vec<u8> {
        let signable = SignableHeader {
            height: self.height,
            parent: &self.parent,
            events_root: &self.events_root,
            events_count: self.events_count,
            mmr_root: &self.mmr_root,
            timestamp: self.timestamp,
            sealer: &self.sealer,
        };
        bincode::serialize(&signable).expect("serialization should not fail")
    }

    /// Compute the hash of this header.
    pub fn hash(&self) -> BlockHash {
        BlockHash(hash(&self.signing_bytes()))
    }

    /// Create a new header with the given seal.
    pub fn with_seal(mut self, seal: Sig) -> Self {
        self.seal = seal;
        self
    }

    /// Verify the seal signature.
    pub fn verify_seal(&self) -> Result<()> {
        self.sealer
            .key
            .verify(&self.signing_bytes(), &self.seal)
            .map_err(|_| Error::invalid_block("invalid seal signature"))
    }

    /// Validate this header against its parent.
    pub fn validate(&self, parent: Option<&BlockHeader>) -> Result<()> {
        // Verify seal
        self.verify_seal()?;

        match parent {
            Some(p) => {
                // Height must be parent + 1
                if self.height != p.height + 1 {
                    return Err(Error::invalid_block(format!(
                        "height {} should be {}",
                        self.height,
                        p.height + 1
                    )));
                }

                // Parent hash must match
                if self.parent != p.hash() {
                    return Err(Error::invalid_block("parent hash mismatch"));
                }

                // Timestamp must be >= parent
                if self.timestamp < p.timestamp {
                    return Err(Error::invalid_block("timestamp before parent"));
                }
            }
            None => {
                // Genesis block
                if self.height != 0 {
                    return Err(Error::invalid_block("genesis must have height 0"));
                }
                if self.parent != BlockHash::ZERO {
                    return Err(Error::invalid_block("genesis must have zero parent"));
                }
            }
        }

        Ok(())
    }
}

/// Helper for signing (excludes seal field).
#[derive(Serialize)]
struct SignableHeader<'a> {
    height: u64,
    parent: &'a BlockHash,
    events_root: &'a Hash,
    events_count: u32,
    mmr_root: &'a Hash,
    #[serde(with = "chrono::serde::ts_milliseconds")]
    timestamp: DateTime<Utc>,
    sealer: &'a SealerId,
}

/// A complete block with header and events.
#[derive(Debug, Clone, PartialEq, Eq, Serialize, Deserialize)]
pub struct Block {
    pub header: BlockHeader,
    pub events: Vec<AuditEvent>,
}

impl Block {
    /// Get the block hash.
    pub fn hash(&self) -> BlockHash {
        self.header.hash()
    }

    /// Validate the block (sequential event verification).
    ///
    /// For better performance with many events, use `validate_batch()` instead.
    pub fn validate(&self, parent: Option<&BlockHeader>) -> Result<()> {
        // Validate header
        self.header.validate(parent)?;

        // Validate events count matches
        if self.events.len() as u32 != self.header.events_count {
            return Err(Error::invalid_block(format!(
                "events count mismatch: {} vs {}",
                self.events.len(),
                self.header.events_count
            )));
        }

        // Validate events merkle root
        let computed_root = compute_events_root(&self.events);
        if computed_root != self.header.events_root {
            return Err(Error::invalid_block("events root mismatch"));
        }

        // Validate each event
        for event in &self.events {
            event.validate()?;
        }

        Ok(())
    }

    /// Validate the block using batch signature verification.
    ///
    /// This is 3-8x faster than `validate()` for blocks with many events,
    /// using Arcanum's optimized Ed25519 batch verifier.
    ///
    /// # Performance
    /// - 10 events: ~2x faster
    /// - 100 events: ~4x faster
    /// - 1000 events: ~6-8x faster
    pub fn validate_batch(&self, parent: Option<&BlockHeader>) -> Result<()> {
        // Validate header
        self.header.validate(parent)?;

        // Validate events count matches
        if self.events.len() as u32 != self.header.events_count {
            return Err(Error::invalid_block(format!(
                "events count mismatch: {} vs {}",
                self.events.len(),
                self.header.events_count
            )));
        }

        // Validate events merkle root
        let computed_root = compute_events_root(&self.events);
        if computed_root != self.header.events_root {
            return Err(Error::invalid_block("events root mismatch"));
        }

        // Batch verify all event signatures at once
        crate::batch_verify_events(&self.events)?;

        // Check event timestamps (can't be batched)
        let now = chrono::Utc::now();
        for event in &self.events {
            if event.event_time > now + chrono::Duration::minutes(5) {
                return Err(Error::invalid_event("event_time is in the future"));
            }
        }

        Ok(())
    }

    /// Validate the block using fully parallel processing.
    ///
    /// Uses batch signature verification (the main speedup) combined with
    /// parallel canonical bytes computation for large blocks (1000+ events).
    ///
    /// Note: Parallel merkle tree is not used because BLAKE3 is already
    /// SIMD-accelerated, making parallelization overhead counterproductive.
    ///
    /// # Performance
    /// - Uses all available CPU cores for signature verification
    /// - 100 events: ~2.5x faster than sequential
    /// - 500 events: ~2.5x faster than sequential
    /// - 1000+ events: ~2.7x faster than sequential (parallel canonical bytes kicks in)
    ///
    /// # When to Use
    /// - Blocks with many events where signature verification dominates
    /// - For bulk validation of historical blocks
    pub fn validate_parallel(&self, parent: Option<&BlockHeader>) -> Result<()> {
        // Validate header (single signature, not worth parallelizing)
        self.header.validate(parent)?;

        // Validate events count matches
        if self.events.len() as u32 != self.header.events_count {
            return Err(Error::invalid_block(format!(
                "events count mismatch: {} vs {}",
                self.events.len(),
                self.header.events_count
            )));
        }

        // Sequential merkle root (faster than parallel due to BLAKE3 SIMD)
        let computed_root = compute_events_root(&self.events);
        if computed_root != self.header.events_root {
            return Err(Error::invalid_block("events root mismatch"));
        }

        // Use parallel canonical bytes for large batches, otherwise batch only
        if self.events.len() >= 1000 {
            crate::batch_verify_events_parallel(&self.events)?;
        } else {
            crate::batch_verify_events(&self.events)?;
        }

        // Check event timestamps (fast, not worth parallelizing)
        let now = chrono::Utc::now();
        for event in &self.events {
            if event.event_time > now + chrono::Duration::minutes(5) {
                return Err(Error::invalid_event("event_time is in the future"));
            }
        }

        Ok(())
    }

    /// Get event IDs in this block.
    pub fn event_ids(&self) -> Vec<EventId> {
        self.events.iter().map(|e| e.id()).collect()
    }
}

/// Compute the merkle root of a list of events.
pub fn compute_events_root(events: &[AuditEvent]) -> Hash {
    if events.is_empty() {
        return Hash::ZERO;
    }

    // Get leaf hashes
    let mut hashes: Vec<Hash> = events.iter().map(|e| e.id().0).collect();

    // Pad to power of 2
    while hashes.len() & (hashes.len() - 1) != 0 {
        hashes.push(*hashes.last().unwrap());
    }

    // Build tree bottom-up
    while hashes.len() > 1 {
        let mut next_level = Vec::with_capacity(hashes.len() / 2);
        for pair in hashes.chunks(2) {
            next_level.push(hash_pair(pair[0], pair[1]));
        }
        hashes = next_level;
    }

    hashes[0]
}

/// Compute the merkle root using parallel hashing.
///
/// Uses Rayon to parallelize:
/// 1. Leaf hash computation (event ID extraction)
/// 2. Each level of the merkle tree (when level is large enough)
///
/// # Performance
/// - 100 events: ~1.2x faster than sequential
/// - 1000 events: ~2-3x faster than sequential
/// - Automatically falls back to sequential for small inputs
pub fn compute_events_root_parallel(events: &[AuditEvent]) -> Hash {
    use rayon::prelude::*;

    if events.is_empty() {
        return Hash::ZERO;
    }

    // Parallel leaf hash extraction
    let mut hashes: Vec<Hash> = events.par_iter().map(|e| e.id().0).collect();

    // Pad to power of 2
    while hashes.len() & (hashes.len() - 1) != 0 {
        hashes.push(*hashes.last().unwrap());
    }

    // Build tree bottom-up with parallel levels for large trees
    while hashes.len() > 1 {
        if hashes.len() >= 64 {
            // Parallel hash pairing for large levels
            let pairs: Vec<_> = hashes.chunks(2).collect();
            hashes = pairs
                .par_iter()
                .map(|pair| hash_pair(pair[0], pair[1]))
                .collect();
        } else {
            // Sequential for small levels (parallelization overhead not worth it)
            let mut next_level = Vec::with_capacity(hashes.len() / 2);
            for pair in hashes.chunks(2) {
                next_level.push(hash_pair(pair[0], pair[1]));
            }
            hashes = next_level;
        }
    }

    hashes[0]
}

/// Builder for creating blocks.
pub struct BlockBuilder {
    parent: Option<BlockHeader>,
    events: Vec<AuditEvent>,
    sealer: SealerId,
    mmr_root: Hash,
}

impl BlockBuilder {
    /// Create a new block builder.
    pub fn new(sealer: SealerId) -> Self {
        Self {
            parent: None,
            events: Vec::new(),
            sealer,
            mmr_root: Hash::ZERO,
        }
    }

    /// Set the parent block.
    pub fn parent(mut self, parent: BlockHeader) -> Self {
        self.parent = Some(parent);
        self
    }

    /// Add events.
    pub fn events(mut self, events: Vec<AuditEvent>) -> Self {
        self.events = events;
        self
    }

    /// Set the MMR root (computed externally).
    pub fn mmr_root(mut self, root: Hash) -> Self {
        self.mmr_root = root;
        self
    }

    /// Build and seal the block.
    pub fn seal(self, key: &SecretKey) -> Block {
        let (height, parent_hash) = match &self.parent {
            Some(p) => (p.height + 1, p.hash()),
            None => (0, BlockHash::ZERO),
        };

        let events_root = compute_events_root(&self.events);
        let events_count = self.events.len() as u32;

        let header = BlockHeader {
            height,
            parent: parent_hash,
            events_root,
            events_count,
            mmr_root: self.mmr_root,
            timestamp: Utc::now(),
            sealer: self.sealer,
            seal: Sig::empty(),
        };

        let seal = key.sign(&header.signing_bytes());
        let header = header.with_seal(seal);

        Block {
            header,
            events: self.events,
        }
    }
}

#[cfg(test)]
mod tests {
    use super::*;
    use crate::crypto::SecretKey;
    use crate::event::{ActorId, ActorKind, EventType, ResourceId, ResourceKind};

    fn test_sealer() -> (SecretKey, SealerId) {
        let key = SecretKey::generate();
        let sealer = SealerId::new(key.public_key()).with_name("test-sealer");
        (key, sealer)
    }

    fn test_event(key: &SecretKey) -> AuditEvent {
        let actor = ActorId::new(key.public_key(), ActorKind::User);
        let resource = ResourceId::new(ResourceKind::Repository, "test");

        AuditEvent::builder()
            .now()
            .event_type(EventType::Push {
                force: false,
                commits: 1,
            })
            .actor(actor)
            .resource(resource)
            .sign(key)
            .unwrap()
    }

    #[test]
    fn test_genesis_block() {
        let (key, sealer) = test_sealer();
        let event = test_event(&key);

        let block = BlockBuilder::new(sealer).events(vec![event]).seal(&key);

        assert_eq!(block.header.height, 0);
        assert_eq!(block.header.parent, BlockHash::ZERO);
        assert!(block.validate(None).is_ok());
    }

    #[test]
    fn test_block_chain() {
        let (key, sealer) = test_sealer();

        // Genesis
        let genesis = BlockBuilder::new(sealer.clone())
            .events(vec![test_event(&key)])
            .seal(&key);

        assert!(genesis.validate(None).is_ok());

        // Block 1
        let block1 = BlockBuilder::new(sealer.clone())
            .parent(genesis.header.clone())
            .events(vec![test_event(&key)])
            .seal(&key);

        assert!(block1.validate(Some(&genesis.header)).is_ok());
        assert_eq!(block1.header.height, 1);
        assert_eq!(block1.header.parent, genesis.hash());

        // Block 2
        let block2 = BlockBuilder::new(sealer)
            .parent(block1.header.clone())
            .events(vec![test_event(&key), test_event(&key)])
            .seal(&key);

        assert!(block2.validate(Some(&block1.header)).is_ok());
        assert_eq!(block2.header.height, 2);
    }

    #[test]
    fn test_empty_block() {
        let (key, sealer) = test_sealer();

        let block = BlockBuilder::new(sealer).events(vec![]).seal(&key);

        assert!(block.validate(None).is_ok());
        assert_eq!(block.header.events_count, 0);
        assert_eq!(block.header.events_root, Hash::ZERO);
    }

    #[test]
    fn test_events_root_deterministic() {
        let key = SecretKey::generate();
        let events = vec![test_event(&key), test_event(&key)];

        let root1 = compute_events_root(&events);
        let root2 = compute_events_root(&events);

        assert_eq!(root1, root2);
    }

    #[test]
    fn test_tampered_block_fails() {
        let (key, sealer) = test_sealer();

        let mut block = BlockBuilder::new(sealer)
            .events(vec![test_event(&key)])
            .seal(&key);

        // Tamper with height
        block.header.height = 999;

        // Validation should fail (signature doesn't match)
        assert!(block.validate(None).is_err());
    }
}
