use super::traits::{Observer, ObserverEvent, ObserverMetric};
use std::any::Any;

/// Human-readable progress observer for interactive CLI sessions.
///
/// This observer prints compact `>` / `<` progress lines without exposing
/// prompt contents. It is intended to be opt-in (e.g. `--verbose`).
pub struct VerboseObserver;

impl VerboseObserver {
    pub fn new() -> Self {
        Self
    }
}

impl Observer for VerboseObserver {
    fn record_event(&self, event: &ObserverEvent) {
        match event {
            ObserverEvent::LlmRequest {
                provider,
                model,
                messages_count,
            } => {
                eprintln!("> Thinking");
                eprintln!(
                    "> Send (provider={}, model={}, messages={})",
                    provider, model, messages_count
                );
            }
            ObserverEvent::LlmResponse {
                duration, success, ..
            } => {
                let ms = u64::try_from(duration.as_millis()).unwrap_or(u64::MAX);
                eprintln!("< Receive (success={success}, duration_ms={ms})");
            }
            ObserverEvent::ToolCallStart { tool } => {
                eprintln!("> Tool {tool}");
            }
            ObserverEvent::ToolCall {
                tool,
                duration,
                success,
            } => {
                let ms = u64::try_from(duration.as_millis()).unwrap_or(u64::MAX);
                eprintln!("< Tool {tool} (success={success}, duration_ms={ms})");
            }
            ObserverEvent::TurnComplete => {
                eprintln!("< Complete");
            }
            ObserverEvent::CodeSessionCompleted {
                status,
                changed_files,
                commands,
                validations,
                blockers,
                delegated,
                ..
            } => {
                eprintln!(
                    "< Code session {status} (files={}, commands={}, validations={}, blockers={}, delegated={})",
                    changed_files.len(),
                    commands.len(),
                    validations.len(),
                    blockers.len(),
                    delegated
                );
            }
            _ => {}
        }
    }

    #[inline(always)]
    fn record_metric(&self, _metric: &ObserverMetric) {}

    fn name(&self) -> &str {
        "verbose"
    }

    fn as_any(&self) -> &dyn Any {
        self
    }
}

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

    #[test]
    fn verbose_name() {
        assert_eq!(VerboseObserver::new().name(), "verbose");
    }

    #[test]
    fn verbose_events_do_not_panic() {
        let obs = VerboseObserver::new();
        obs.record_event(&ObserverEvent::LlmRequest {
            provider: "openrouter".into(),
            model: "claude".into(),
            messages_count: 3,
        });
        obs.record_event(&ObserverEvent::LlmResponse {
            provider: "openrouter".into(),
            model: "claude".into(),
            duration: Duration::from_millis(12),
            success: true,
            error_message: None,
        });
        obs.record_event(&ObserverEvent::ToolCallStart {
            tool: "shell".into(),
        });
        obs.record_event(&ObserverEvent::ToolCall {
            tool: "shell".into(),
            duration: Duration::from_millis(2),
            success: true,
        });
        obs.record_event(&ObserverEvent::TurnComplete);
        obs.record_event(&ObserverEvent::CodeSessionCompleted {
            session_id: "sess-1".into(),
            status: "completed".into(),
            summary: "Updated tests".into(),
            changed_files: vec!["src/lib.rs".into()],
            commands: vec!["cargo test".into()],
            validations: vec!["pass:cargo test".into()],
            blockers: vec![],
            pending_work: vec![],
            delegated: false,
        });
    }
}
