#![forbid(unsafe_code)]
#![warn(missing_docs, missing_debug_implementations, rust_2018_idioms)]

//! # VAPORA Tracking Adapter
//!
//! Integration adapter for `tracking-core` library with VAPORA-specific
//! features.
//!
//! This crate re-exports the standalone `tracking-core` library and adds:
//! - VAPORA agent integration
//! - NATS event streaming (optional)
//! - Task workflow integration
//! - Multi-tenant tracking support
//!
//! ## Example
//!
//! ```ignore
//! use vapora_tracking::prelude::*;
//!
//! #[tokio::main]
//! async fn main() -> Result<(), Box<dyn std::error::Error>> {
//!     // Initialize database
//!     let db = TrackingDb::new("sqlite://tracking.db").await?;
//!
//!     // Create a tracking entry
//!     let entry = TrackingEntry::new(
//!         "/path/to/project",
//!         TrackingSource::CoderChanges,
//!         "Fixed authentication bug".to_string(),
//!     );
//!
//!     // Store it
//!     db.insert_entry(&entry).await?;
//!
//!     Ok(())
//! }
//! ```

// Re-export core tracking types and functionality
pub use tracking_core::*;

/// VAPORA-specific plugin integration
pub mod plugin {
    use std::collections::HashMap;
    use std::path::PathBuf;

    use chrono::Utc;
    use tracking_core::{EntryType, Impact, TrackingDb, TrackingEntry, TrackingSource};
    use uuid::Uuid;

    /// Plugin for integrating tracking with VAPORA agents
    #[derive(Debug, Clone)]
    pub struct TrackingPlugin {
        /// Database instance
        pub db: std::sync::Arc<TrackingDb>,
    }

    impl TrackingPlugin {
        /// Create a new tracking plugin
        pub async fn new(db_url: &str) -> tracking_core::Result<Self> {
            Ok(Self {
                db: std::sync::Arc::new(TrackingDb::new(db_url).await?),
            })
        }

        /// Records task completion as a backend change entry in the tracking
        /// DB.
        pub async fn on_task_completed(&self, task_id: &str) -> tracking_core::Result<()> {
            let entry = TrackingEntry {
                id: Uuid::new_v4(),
                project_path: std::env::current_dir().unwrap_or_else(|_| PathBuf::from(".")),
                source: TrackingSource::WorkflowYaml,
                entry_type: EntryType::Change {
                    impact: Impact::Backend,
                    breaking: false,
                    files_affected: 0,
                },
                timestamp: Utc::now(),
                summary: format!("Task completed: {task_id}"),
                details_link: None,
                metadata: HashMap::new(),
            };
            self.db.insert_entry(&entry).await?;
            tracing::info!(task_id = %task_id, "Task completion tracked");
            Ok(())
        }

        /// Records document creation as a docs change entry in the tracking DB.
        pub async fn on_document_created(&self, doc_path: &str) -> tracking_core::Result<()> {
            let path = std::path::Path::new(doc_path);
            let project_path = path
                .parent()
                .map(|p| p.to_path_buf())
                .unwrap_or_else(|| PathBuf::from("."));

            let entry = TrackingEntry {
                id: Uuid::new_v4(),
                project_path,
                source: TrackingSource::CoderChanges,
                entry_type: EntryType::Change {
                    impact: Impact::Docs,
                    breaking: false,
                    files_affected: 1,
                },
                timestamp: Utc::now(),
                summary: format!("Document created: {doc_path}"),
                details_link: Some(PathBuf::from(doc_path)),
                metadata: HashMap::new(),
            };
            self.db.insert_entry(&entry).await?;
            tracing::info!(doc_path = %doc_path, "Document creation tracked");
            Ok(())
        }
    }
}

/// NATS event streaming integration (optional)
#[cfg(feature = "async-nats")]
pub mod events {
    use std::sync::Arc;

    use crate::TrackingEntry;

    /// Publisher that streams tracking events to NATS subjects.
    ///
    /// Subject format: `vapora.tracking.<source>` where `<source>` is the
    /// serialized [`TrackingSource`](crate::TrackingSource) variant name.
    #[derive(Clone)]
    pub struct NatsPublisher {
        client: Arc<async_nats::Client>,
        subject_prefix: String,
    }

    impl NatsPublisher {
        /// Create a new publisher.
        ///
        /// `subject_prefix` is prepended to the source name, e.g.
        /// `"vapora.tracking"` produces `"vapora.tracking.CoderChanges"`.
        pub fn new(client: Arc<async_nats::Client>, subject_prefix: impl Into<String>) -> Self {
            Self {
                client,
                subject_prefix: subject_prefix.into(),
            }
        }

        /// Publish a `tracking.entry.created` event for `entry`.
        ///
        /// The payload is JSON-encoded.  Errors are returned to the caller so
        /// they can decide whether to retry or log-and-continue.
        pub async fn publish_entry_created(
            &self,
            entry: &TrackingEntry,
        ) -> tracking_core::Result<()> {
            let subject = format!("{}.{:?}", self.subject_prefix, entry.source);
            let payload = serde_json::to_vec(entry).map_err(|e| {
                tracking_core::TrackingError::StorageError(format!(
                    "Failed to serialize entry: {e}"
                ))
            })?;

            self.client
                .publish(subject.clone(), payload.into())
                .await
                .map_err(|e| {
                    tracking_core::TrackingError::StorageError(format!(
                        "NATS publish to {subject} failed: {e}"
                    ))
                })?;

            Ok(())
        }
    }

    impl std::fmt::Debug for NatsPublisher {
        fn fmt(&self, f: &mut std::fmt::Formatter<'_>) -> std::fmt::Result {
            f.debug_struct("NatsPublisher")
                .field("subject_prefix", &self.subject_prefix)
                .finish_non_exhaustive()
        }
    }
}

pub mod prelude {
    //! Prelude for common imports
    pub use tracking_core::{
        EntryType, Estimate, Impact, Priority, Result, TodoStatus, TrackingDb, TrackingEntry,
        TrackingError, TrackingSource,
    };

    pub use crate::plugin::TrackingPlugin;
}

#[cfg(test)]
mod tests {
    use super::*;

    #[test]
    fn test_adapter_exports() {
        // Verify tracking-core types are accessible
        let _source = TrackingSource::CoderChanges;
        let _impact = Impact::Backend;
        let _priority = Priority::High;
    }
}
