use anyhow::Result;
use opentelemetry::{global, KeyValue};
use pi_logger::observability::init_observability_from_optional_path;
use std::{
    path::{Path, PathBuf},
    thread,
    time::{Duration, Instant},
};

fn local_only_log_test() {
    tracing::info!(
        target: "pi_logger_example::local_only",
        module = "local_only",
        test_kind = "local_log_test",
        "本地日志测试:这条日志只应写入本地文件,不应上传到采集器"
    );
}

fn log_compatibility_test() {
    log::info!(
        target: "pi_logger_example::log_compat",
        "log 宏兼容测试:log::info! 已进入 observability"
    );
    log::debug!(
        target: "pi_logger_example::log_compat",
        "log 宏兼容测试:target override 开启后 log::debug! 也会输出"
    );
}

fn remote_log_test() {
    tracing::info!(
        target: "pi_logger_example::remote_test",
        id = 100_u64,
        module = "remote_test",
        test_kind = "remote_log_test",
        status = "ok",
        retry_count = 1_u64,
        sampled = true,
        "远端日志测试:全部 field_rules 匹配,这条日志应上传到采集器"
    );

    tracing::info!(
        target: "pi_logger_example::remote_test",
        id = 101_u64,
        module = "remote_test",
        test_kind = "remote_log_test",
        status = "ok",
        retry_count = 1_u64,
        sampled = true,
        "远端日志测试:id != 100,这条日志不应上传到采集器"
    );

    tracing::info!(
        target: "pi_logger_example::remote_test",
        id = 100_u64,
        module = "remote_test",
        test_kind = "local_log_test",
        status = "ok",
        retry_count = 1_u64,
        sampled = true,
        "远端日志测试:test_kind 不包含 remote,这条日志不应上传到采集器"
    );

    tracing::info!(
        target: "pi_logger_example::remote_test",
        id = 100_u64,
        module = "local_test",
        test_kind = "remote_log_test",
        status = "ok",
        retry_count = 1_u64,
        sampled = true,
        "远端日志测试:module 不是 remote 开头,这条日志不应上传到采集器"
    );

    tracing::info!(
        target: "pi_logger_example::remote_test",
        id = 100_u64,
        module = "remote_test",
        test_kind = "remote_log_test",
        status = "failed",
        retry_count = 1_u64,
        sampled = true,
        "远端日志测试:status 不在 [ok, retry] 中,这条日志不应上传到采集器"
    );

    tracing::info!(
        target: "pi_logger_example::remote_test",
        id = 100_u64,
        module = "remote_test",
        test_kind = "remote_log_test",
        status = "retry",
        retry_count = 4_u64,
        sampled = true,
        "远端日志测试:retry_count > 3,这条日志不应上传到采集器"
    );

    tracing::info!(
        target: "pi_logger_example::remote_test",
        id = 100_u64,
        module = "remote_test",
        test_kind = "remote_log_test",
        status = "ok",
        retry_count = 1_u64,
        sampled = false,
        "远端日志测试:sampled != true,这条日志不应上传到采集器"
    );
}

fn metrics_report_test() {
    let meter = global::meter("pi_logger_example");
    let request_counter = meter
        .u64_counter("pi_logger_demo_requests_total")
        .with_description("指标上报测试:demo 请求总数")
        .build();
    let request_duration = meter
        .f64_histogram("pi_logger_demo_request_duration_ms")
        .with_description("指标上报测试:demo 请求耗时")
        .with_unit("ms")
        .build();
    let in_flight = meter
        .i64_up_down_counter("pi_logger_demo_requests_in_flight")
        .with_description("指标上报测试:当前处理中请求数")
        .build();

    let attributes = vec![
        KeyValue::new("module", "metrics_demo"),
        KeyValue::new("protocol", "otlp"),
        KeyValue::new("status", "ok"),
    ];

    in_flight.add(1, &attributes);
    let started = Instant::now();
    thread::sleep(Duration::from_millis(15));
    request_counter.add(1, &attributes);
    request_duration.record(started.elapsed().as_secs_f64() * 1000.0, &attributes);
    in_flight.add(-1, &attributes);

    tracing::info!(
        target: "pi_logger_example::local_only",
        module = "metrics_demo",
        test_kind = "metrics_report_test",
        "指标上报测试:counter/histogram/up_down_counter 只通过 OTLP metrics 上传到采集器"
    );
}

#[tracing::instrument(
    name = "demo_request",
    target = "pi_logger_example::trace_test",
    level = "info",
    skip_all,
    fields(request_id = request_id, module = "trace_demo")
)]
fn demo_request_trace_test(request_id: u64) -> Result<()> {
    tracing::info!(
        target: "pi_logger_example::trace_test",
        request_id = request_id,
        "trace 跟踪测试:开始处理 demo_request 调用链"
    );

    decode_transaction_trace_test(request_id, b"trace payload")?;
    persist_transaction_trace_test(request_id)?;

    tracing::info!(
        target: "pi_logger_example::trace_test",
        request_id = request_id,
        "trace 跟踪测试:完成 demo_request 调用链"
    );

    Ok(())
}

#[tracing::instrument(
    name = "decode_transaction",
    target = "pi_logger_example::trace_test",
    level = "info",
    skip_all,
    fields(request_id = request_id, module = "decoder", protocol = "ton")
)]
fn decode_transaction_trace_test(request_id: u64, payload: &[u8]) -> Result<()> {
    tracing::info!(
        target: "pi_logger_example::trace_test",
        request_id = request_id,
        payload_len = payload.len(),
        "trace 跟踪测试:进入 decode_transaction 子调用"
    );

    validate_payload_trace_test(request_id, payload)?;
    parse_payload_trace_test(request_id, payload)?;

    Ok(())
}

#[tracing::instrument(
    name = "validate_payload",
    target = "pi_logger_example::trace_test",
    level = "info",
    skip_all,
    fields(request_id = request_id, module = "validator")
)]
fn validate_payload_trace_test(request_id: u64, payload: &[u8]) -> Result<()> {
    tracing::info!(
        target: "pi_logger_example::trace_test",
        request_id = request_id,
        payload_len = payload.len(),
        "trace 跟踪测试:校验 payload"
    );

    Ok(())
}

#[tracing::instrument(
    name = "parse_payload",
    target = "pi_logger_example::trace_test",
    level = "info",
    skip_all,
    fields(request_id = request_id, module = "parser")
)]
fn parse_payload_trace_test(request_id: u64, payload: &[u8]) -> Result<()> {
    tracing::info!(
        target: "pi_logger_example::trace_test",
        request_id = request_id,
        payload_len = payload.len(),
        "trace 跟踪测试:解析 payload"
    );

    Ok(())
}

#[tracing::instrument(
    name = "persist_transaction",
    target = "pi_logger_example::trace_test",
    level = "info",
    skip_all,
    fields(request_id = request_id, module = "storage")
)]
fn persist_transaction_trace_test(request_id: u64) -> Result<()> {
    tracing::info!(
        target: "pi_logger_example::trace_test",
        request_id = request_id,
        "trace 跟踪测试:持久化 transaction"
    );

    Ok(())
}

fn main() -> Result<()> {
    let config_path = std::env::var_os("PI_LOGGER_OBSERVABILITY_CONFIG").map(PathBuf::from);
    let (_reload, guards) = init_observability_from_optional_path(config_path.as_deref())?;

    tracing::info!(target: "pi_logger_example", "pi_logger observability example started");

    local_only_log_test();
    log_compatibility_test();
    remote_log_test();
    demo_request_trace_test(100)?;
    metrics_report_test();

    tracing::info!(target: "pi_logger_example", "pi_logger observability example finished");

    guards.shutdown();

    println!(
        "example finished. local log dir: {}",
        Path::new("logs")
            .canonicalize()
            .unwrap_or_else(|_| "logs".into())
            .display()
    );

    Ok(())
}