// Copyright (c) 2026 Kirky.X
//
// Licensed under the MIT License
// See LICENSE file in the project root for full license information.

//! TracingContext - 追踪上下文管理
//!
//! 提供span生命周期管理功能，包括创建、结束和父子关系。

use crate::tracing::attributes::AttributeValue;
use opentelemetry::global::{self, BoxedSpan, BoxedTracer};
use opentelemetry::trace::{Span, Tracer};
use std::sync::Arc;

/// 追踪上下文
///
/// 管理span的生命周期，当TracingContext被drop时，span会自动结束。
pub struct TracingContext {
    tracer: Arc<BoxedTracer>,
    span: BoxedSpan,
    name: String,
}

impl TracingContext {
    /// 创建新的追踪上下文
    ///
    /// # Arguments
    ///
    /// * `name` - span名称
    pub fn new(name: &str) -> Self {
        let tracer = global::tracer("dbnexus");
        let name = name.to_string(); // 转换为 String 以避免生命周期问题
        let span = tracer.start(name.clone());

        Self {
            tracer: Arc::new(tracer),
            span,
            name,
        }
    }

    /// 获取span名称
    pub fn span_name(&self) -> &str {
        &self.name
    }

    /// 创建子span
    ///
    /// # Arguments
    ///
    /// * `name` - 子span名称
    pub fn start_child(&self, name: &str) -> Self {
        let name = name.to_string(); // 转换为 String 以避免生命周期问题
        let span = self.tracer.span_builder(name.clone()).start(&*self.tracer);

        Self {
            tracer: self.tracer.clone(),
            span,
            name,
        }
    }

    /// 设置单个属性
    ///
    /// # Arguments
    ///
    /// * `key` - 属性键
    /// * `value` - 属性值
    pub fn set_attribute(&mut self, key: &str, value: AttributeValue) {
        self.span.set_attribute(value.to_key_value(key));
    }

    /// 设置多个属性
    ///
    /// # Arguments
    ///
    /// * `attributes` - 属性列表，每个元素是 (key, value) 元组
    pub fn set_attributes(&mut self, attributes: Vec<(String, AttributeValue)>) {
        for (key, value) in attributes {
            self.set_attribute(&key, value);
        }
    }

    /// 记录错误信息
    ///
    /// # Arguments
    ///
    /// * `error` - 错误对象，实现std::error::Error trait
    pub fn record_error(&mut self, error: &dyn std::error::Error) {
        use opentelemetry::trace::Status;

        let error_message = error.to_string();
        self.span.set_status(Status::Error {
            description: error_message.into(),
        });
    }
}

impl Drop for TracingContext {
    /// 当TracingContext被drop时，结束span
    fn drop(&mut self) {
        self.span.end();
    }
}
