pmat 3.15.0

PMAT - Zero-config AI context generation and code quality toolkit (CLI, MCP, HTTP)
#![cfg_attr(coverage_nightly, coverage(off))]
// Sprint 79+: Presentar-terminal Brick architecture (ratatui-free)
// Uses presentar_terminal for Jidoka verification gates and zero-allocation rendering

#[cfg(feature = "tui")]
use async_trait::async_trait;
#[cfg(feature = "tui")]
use std::collections::HashMap;
#[cfg(feature = "tui")]
use std::path::PathBuf;
#[cfg(feature = "tui")]
use std::sync::{Arc, RwLock};
#[cfg(feature = "tui")]
use thiserror::Error;
#[cfg(feature = "tui")]
use tokio::sync::mpsc;

// Presentar types available for future full TUI implementation
// Currently using stub implementation - full Brick widgets TBD
#[cfg(feature = "tui")]
#[allow(unused_imports)]
use presentar_core::{Brick, BrickAssertion, BrickBudget, Constraints, Size, Widget};
// presentar_terminal disabled until published to crates.io
// #[cfg(feature = "tui")]
// use presentar_terminal::{Meter, Table, TuiApp, TuiConfig};

#[cfg(feature = "tui")]
use crate::demo::protocol_harness::{DemoProtocol, ProtocolMetadata};

#[cfg(feature = "tui")]
#[derive(Debug, Clone, Copy, PartialEq)]
enum ControlFlow {
    Continue,
    Exit,
}

#[cfg(feature = "tui")]
#[derive(Debug, Clone, Copy, Default, PartialEq, Eq)]
enum PanelId {
    #[default]
    FileTree,
    Analysis,
    Dag,
}

#[cfg(feature = "tui")]
impl PanelId {
    fn next(self) -> Self {
        match self {
            Self::FileTree => Self::Analysis,
            Self::Analysis => Self::Dag,
            Self::Dag => Self::FileTree,
        }
    }
}

#[cfg(feature = "tui")]
#[derive(Default)]
struct TuiState {
    selected_panel: PanelId,
    analysis_results: AnalysisResults,
    scroll_offset: usize,
    filter: String,
    selected_index: usize,
    progress: f32,
}

#[cfg(feature = "tui")]
impl TuiState {
    fn cycle_panel(&mut self) {
        self.selected_panel = self.selected_panel.next();
    }
}

#[cfg(feature = "tui")]
#[derive(Default)]
struct AnalysisResults {
    hotspots: Vec<Hotspot>,
    files: Vec<FileInfo>,
    dag_nodes: HashMap<String, NodeInfo>,
}

#[cfg(feature = "tui")]
#[derive(Debug, Clone)]
struct Hotspot {
    file_path: PathBuf,
    description: String,
    severity: Severity,
    metric_value: f32,
}

#[cfg(feature = "tui")]
#[derive(Debug, Clone)]
enum Severity {
    Critical,
    Warning,
    Info,
}

#[cfg(feature = "tui")]
#[derive(Debug, Clone)]
struct FileInfo {
    path: PathBuf,
    complexity: f32,
    size_kb: u64,
}

#[cfg(feature = "tui")]
#[derive(Debug, Clone)]
struct NodeInfo {
    id: String,
    name: String,
    kind: String,
}

#[cfg(feature = "tui")]
#[derive(Debug, Clone)]
struct AnalysisUpdate {
    update_type: UpdateType,
    progress: f32,
}

#[cfg(feature = "tui")]
#[derive(Debug, Clone)]
enum UpdateType {
    FileDiscovered(PathBuf),
    ComplexityComputed(FileComplexity),
    ChurnAnalyzed(FileChurn),
    DagBuilt(DagInfo),
    Complete,
}

#[cfg(feature = "tui")]
#[derive(Debug, Clone)]
struct FileComplexity {
    path: PathBuf,
    cyclomatic: f32,
    cognitive: f32,
}

#[cfg(feature = "tui")]
#[derive(Debug, Clone)]
struct FileChurn {
    path: PathBuf,
    commits: u32,
    lines_changed: u32,
}

#[cfg(feature = "tui")]
#[derive(Debug, Clone)]
struct DagInfo {
    node_count: usize,
    edge_count: usize,
}

// ============================================================================
// TuiDemoOutput - Demo output for protocol harness
// ============================================================================

#[cfg(feature = "tui")]
#[derive(Debug, Clone)]
/// Tui demo output.
pub struct TuiDemoOutput {
    pub content: String,
}

#[cfg(feature = "tui")]
impl Default for TuiDemoOutput {
    fn default() -> Self {
        Self {
            content: String::new(),
        }
    }
}

// ============================================================================
// TuiDemoError - Error types for TUI demo
// ============================================================================

#[cfg(feature = "tui")]
#[derive(Debug, Error)]
/// Error variants for tui demo operations.
pub enum TuiDemoError {
    #[error("TUI initialization failed: {0}")]
    Init(String),
    #[error("Render error: {0}")]
    Render(String),
    #[error("Channel error: {0}")]
    Channel(String),
}

// ============================================================================
// TuiRequest / TuiResponse - Request/Response types for demo
// ============================================================================

#[cfg(feature = "tui")]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
/// Request for tui operation.
pub struct TuiRequest {
    pub action: String,
    pub params: HashMap<String, serde_json::Value>,
}

#[cfg(feature = "tui")]
#[derive(Debug, Clone, serde::Serialize, serde::Deserialize)]
/// Response from tui operation.
pub struct TuiResponse {
    pub success: bool,
    pub message: String,
}

// ============================================================================
// TuiDemoAdapter - Presentar-terminal based demo adapter
// ============================================================================

#[cfg(feature = "tui")]
/// Language adapter for tui demo.
pub struct TuiDemoAdapter {
    state: Arc<RwLock<TuiState>>,
    update_rx: Option<mpsc::Receiver<AnalysisUpdate>>,
    update_tx: mpsc::Sender<AnalysisUpdate>,
}

#[cfg(feature = "tui")]
impl TuiDemoAdapter {
    #[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
    /// Create a new instance.
    pub fn new() -> Result<Self, TuiDemoError> {
        let (update_tx, update_rx) = mpsc::channel(100);

        Ok(Self {
            state: Arc::new(RwLock::new(TuiState::default())),
            update_rx: Some(update_rx),
            update_tx,
        })
    }

    #[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
    pub async fn initialize(&mut self) -> Result<(), TuiDemoError> {
        // Presentar-terminal TuiApp would handle terminal init
        // For now, just initialize state
        Ok(())
    }

    #[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
    pub async fn handle_request(
        &mut self,
        request: TuiRequest,
    ) -> Result<TuiResponse, TuiDemoError> {
        // Handle analysis requests
        Ok(TuiResponse {
            success: true,
            message: format!("Handled action: {}", request.action),
        })
    }

    #[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
    pub async fn run_event_loop(&mut self) -> Result<(), TuiDemoError> {
        // Presentar-terminal TuiApp handles the event loop
        // For now, return immediately (non-interactive mode)
        println!("╭─ PMAT Demo TUI (Presentar) ─────────────────────────╮");
        println!("│ Interactive analysis visualization                  │");
        println!("│ Using presentar-terminal Brick architecture         │");
        println!("│ Benefits: Jidoka gates, zero-allocation, 95% cov    │");
        println!("╰─────────────────────────────────────────────────────╯");
        Ok(())
    }

    #[provable_contracts_macros::contract("pmat-core.yaml", equation = "check_compliance")]
    /// Get update sender.
    pub fn get_update_sender(&self) -> mpsc::Sender<AnalysisUpdate> {
        self.update_tx.clone()
    }

    pub async fn run(&mut self) -> Result<TuiDemoOutput, TuiDemoError> {
        // Presentar-terminal TuiApp handles the event loop
        // For now, return a placeholder output
        // Full implementation would use TuiApp::new(root_widget)?.run()

        let mut output = String::new();
        output.push_str("╭─ PMAT Demo TUI (Presentar) ─────────────────────────╮\n");
        output.push_str("│ Interactive analysis visualization                  │\n");
        output.push_str("│ Using presentar-terminal Brick architecture         │\n");
        output.push_str("│ Benefits: Jidoka gates, zero-allocation, 95% cov    │\n");
        output.push_str("╰─────────────────────────────────────────────────────╯\n");

        Ok(TuiDemoOutput { content: output })
    }
}

#[cfg(feature = "tui")]
impl Default for TuiDemoAdapter {
    fn default() -> Self {
        Self::new().expect("Failed to create TuiDemoAdapter")
    }
}

#[cfg(feature = "tui")]
#[async_trait]
impl DemoProtocol for TuiDemoAdapter {
    type Request = TuiRequest;
    type Response = TuiResponse;
    type Error = TuiDemoError;

    async fn decode_request(&self, raw: &[u8]) -> Result<Self::Request, Self::Error> {
        serde_json::from_slice(raw).map_err(|e| TuiDemoError::Init(e.to_string()))
    }

    async fn encode_response(&self, resp: Self::Response) -> Result<Vec<u8>, Self::Error> {
        serde_json::to_vec(&resp).map_err(|e| TuiDemoError::Render(e.to_string()))
    }

    async fn get_protocol_metadata(&self) -> ProtocolMetadata {
        ProtocolMetadata {
            name: "tui",
            version: "2.0.0",
            description: "Terminal User Interface using presentar-terminal".to_string(),
            request_schema: serde_json::json!({}),
            response_schema: serde_json::json!({}),
            example_requests: vec![],
            capabilities: vec![
                "interactive".to_string(),
                "real-time".to_string(),
                "keyboard-navigation".to_string(),
                "presentar-brick".to_string(),
            ],
        }
    }

    async fn execute_demo(&self, request: Self::Request) -> Result<Self::Response, Self::Error> {
        Ok(TuiResponse {
            success: true,
            message: format!("Executed demo action: {}", request.action),
        })
    }
}

// ============================================================================
// Tests
// ============================================================================

#[cfg(all(test, feature = "tui"))]
mod tests {
    use super::*;

    #[test]
    fn test_panel_cycling() {
        let mut state = TuiState::default();
        assert_eq!(state.selected_panel, PanelId::FileTree);

        state.cycle_panel();
        assert_eq!(state.selected_panel, PanelId::Analysis);

        state.cycle_panel();
        assert_eq!(state.selected_panel, PanelId::Dag);

        state.cycle_panel();
        assert_eq!(state.selected_panel, PanelId::FileTree);
    }

    #[test]
    fn test_adapter_creation() {
        let adapter = TuiDemoAdapter::new();
        assert!(adapter.is_ok());
    }

    #[tokio::test]
    async fn test_adapter_metadata() {
        let adapter = TuiDemoAdapter::new().unwrap();
        let meta = adapter.get_protocol_metadata().await;
        assert_eq!(meta.version, "2.0.0");
        assert!(meta.capabilities.contains(&"presentar-brick".to_string()));
    }
}