pub(crate) mod format;
pub mod time;

use crate::time::FormatTime;
use format::{write_span_mode, Buffers, ColorLevel, Config, FmtEvent, SpanMode};

use nu_ansi_term::{Color, Style};
use std::{
    fmt::{self, Write},
    io::{self, IsTerminal},
    iter::Fuse,
    mem,
    sync::{
        atomic::{AtomicBool, Ordering},
        Mutex,
    },
    thread::LocalKey,
    time::Instant,
};
use tracing_core::{
    field::{Field, Visit},
    span::{Attributes, Id},
    Event, Subscriber,
};
#[cfg(feature = "tracing-log")]
use tracing_log::NormalizeEvent;
use tracing_subscriber::{
    fmt::MakeWriter,
    layer::{Context, Layer},
    registry::{LookupSpan, ScopeFromRoot, SpanRef},
};

// Span extension data
pub(crate) struct Data {
    start: Instant,
    kvs: Vec<(&'static str, String)>,
    written: bool,
}

impl Data {
    pub fn new(attrs: &Attributes<'_>, written: bool) -> Self {
        let mut span = Self {
            start: Instant::now(),
            kvs: Vec::new(),
            written,
        };
        attrs.record(&mut span);
        span
    }
}

impl Visit for Data {
    fn record_debug(&mut self, field: &Field, value: &dyn fmt::Debug) {
        self.kvs.push((field.name(), format!("{:?}", value)))
    }
}

#[derive(Debug)]
pub struct HierarchicalLayer<W = fn() -> io::Stderr, FT = ()>
where
    W: for<'writer> MakeWriter<'writer> + 'static,
    FT: FormatTime,
{
    make_writer: W,
    bufs: Mutex<Buffers>,
    config: Config,
    timer: FT,
}

impl Default for HierarchicalLayer {
    fn default() -> Self {
        Self::new(2)
    }
}

impl HierarchicalLayer<fn() -> io::Stderr> {
    pub fn new(indent_amount: usize) -> Self {
        let ansi = io::stderr().is_terminal();
        let config = Config {
            ansi,
            indent_amount,
            ..Default::default()
        };
        Self {
            make_writer: io::stderr,
            bufs: Mutex::new(Buffers::new()),
            config,
            timer: (),
        }
    }
}

impl<W, FT> HierarchicalLayer<W, FT>
where
    W: for<'writer> MakeWriter<'writer> + 'static,
    FT: FormatTime,
{
    /// Enables terminal colors, boldness and italics.
    pub fn with_ansi(self, ansi: bool) -> Self {
        Self {
            config: self.config.with_ansi(ansi),
            ..self
        }
    }

    pub fn with_writer<W2>(self, make_writer: W2) -> HierarchicalLayer<W2, FT>
    where
        W2: for<'writer> MakeWriter<'writer>,
    {
        HierarchicalLayer {
            make_writer,
            config: self.config,
            bufs: self.bufs,
            timer: self.timer,
        }
    }

    pub fn with_indent_amount(self, indent_amount: usize) -> Self {
        let config = Config {
            indent_amount,
            ..self.config
        };
        Self { config, ..self }
    }

    /// Renders an ascii art tree instead of just using whitespace indentation.
    pub fn with_indent_lines(self, indent_lines: bool) -> Self {
        Self {
            config: self.config.with_indent_lines(indent_lines),
            ..self
        }
    }

    /// Specifies how to measure and format time at which event has occurred.
    pub fn with_timer<FT2: FormatTime>(self, timer: FT2) -> HierarchicalLayer<W, FT2> {
        HierarchicalLayer {
            make_writer: self.make_writer,
            config: self.config,
            bufs: self.bufs,
            timer,
        }
    }

    /// Whether to render the event and span targets. Usually targets are the module path to the
    /// event/span macro invocation.
    pub fn with_targets(self, targets: bool) -> Self {
        Self {
            config: self.config.with_targets(targets),
            ..self
        }
    }

    /// Whether to render the thread id in the beginning of every line. This is helpful to
    /// untangle the tracing statements emitted by each thread.
    pub fn with_thread_ids(self, thread_ids: bool) -> Self {
        Self {
            config: self.config.with_thread_ids(thread_ids),
            ..self
        }
    }

    /// Whether to render the thread name in the beginning of every line. Not all threads have
    /// names, but if they do, this may be more helpful than the generic thread ids.
    pub fn with_thread_names(self, thread_names: bool) -> Self {
        Self {
            config: self.config.with_thread_names(thread_names),
            ..self
        }
    }

    /// Resets the indentation to zero after `wraparound` indentation levels.
    /// This is helpful if you expect very deeply nested spans as otherwise the indentation
    /// just runs out of your screen.
    pub fn with_wraparound(self, wraparound: usize) -> Self {
        Self {
            config: self.config.with_wraparound(wraparound),
            ..self
        }
    }

    /// Whether to print the currently active span's message again before entering a new span.
    /// This helps if the entry to the current span was quite a while back (and with scrolling
    /// upwards in logs).
    pub fn with_verbose_entry(self, verbose_entry: bool) -> Self {
        Self {
            config: self.config.with_verbose_entry(verbose_entry),
            ..self
        }
    }

    /// Whether to print the currently active span's message again before dropping it.
    /// This helps if the entry to the current span was quite a while back (and with scrolling
    /// upwards in logs).
    pub fn with_verbose_exit(self, verbose_exit: bool) -> Self {
        Self {
            config: self.config.with_verbose_exit(verbose_exit),
            ..self
        }
    }

    /// Whether to print the currently active span's message again if another span was entered in
    /// the meantime
    /// This helps during concurrent or multi-threaded events where threads are entered, but not
    /// necessarily *exited* before other *divergent* spans are entered and generating events.
    pub fn with_span_retrace(self, enabled: bool) -> Self {
        Self {
            config: self.config.with_span_retrace(enabled),
            ..self
        }
    }

    /// Defers printing span opening until an event is generated within the span.
    ///
    /// Avoids printing empty spans with no generated events.
    pub fn with_deferred_spans(self, enabled: bool) -> Self {
        Self {
            config: self.config.with_deferred_spans(enabled),
            ..self
        }
    }

    /// Prefixes each branch with the event mode, such as `open`, or `close`
    pub fn with_span_modes(self, enabled: bool) -> Self {
        Self {
            config: self.config.with_span_modes(enabled),
            ..self
        }
    }

    /// Whether to print `{}` around the fields when printing a span.
    /// This can help visually distinguish fields from the rest of the message.
    pub fn with_bracketed_fields(self, bracketed_fields: bool) -> Self {
        Self {
            config: self.config.with_bracketed_fields(bracketed_fields),
            ..self
        }
    }

    /// Whether to print the time with higher precision.
    pub fn with_higher_precision(self, higher_precision: bool) -> Self {
        Self {
            config: self.config.with_higher_precision(higher_precision),
            ..self
        }
    }

    fn styled(&self, style: Style, text: impl AsRef<str>) -> String {
        if self.config.ansi {
            style.paint(text.as_ref()).to_string()
        } else {
            text.as_ref().to_string()
        }
    }

    fn print_kvs<'a, I, V>(&self, buf: &mut impl fmt::Write, kvs: I) -> fmt::Result
    where
        I: IntoIterator<Item = (&'a str, V)>,
        V: fmt::Display + 'a,
    {
        let mut kvs = kvs.into_iter();
        if let Some((k, v)) = kvs.next() {
            if k == "message" {
                write!(buf, "{}", v)?;
            } else {
                write!(buf, "{}={}", k, v)?;
            }
        }
        for (k, v) in kvs {
            write!(buf, ", {}={}", k, v)?;
        }
        Ok(())
    }

    /// Ensures that `new_span` and all its ancestors are properly printed before an event
    fn write_retrace_span<'a, S>(
        &self,
        new_span: &SpanRef<'a, S>,
        bufs: &mut Buffers,
        ctx: &'a Context<S>,
        pre_open: bool,
    ) where
        S: Subscriber + for<'new_span> LookupSpan<'new_span>,
    {
        // Also handle deferred spans along with retrace since deferred spans may need to print
        // multiple spans at once as a whole tree can be deferred
        //
        // If a another event occurs right after a previous event in the same span, this will
        // simply print nothing since the path to the common lowest ancestor is empty
        // if self.config.span_retrace || self.config.deferred_spans {
        let old_span_id = bufs.current_span.replace((new_span.id()).clone());
        let old_span_id = old_span_id.as_ref();
        let new_span_id = new_span.id();

        if Some(&new_span_id) != old_span_id {
            let old_span = old_span_id.as_ref().and_then(|v| ctx.span(v));
            let old_path = old_span.as_ref().map(scope_path).into_iter().flatten();

            let new_path = scope_path(new_span);

            // Print the path from the common base of the two spans
            let new_path = DifferenceIter::new(old_path, new_path, |v| v.id());

            for (i, span) in new_path.enumerate() {
                // Mark traversed spans as *written*
                let was_written = if let Some(data) = span.extensions_mut().get_mut::<Data>() {
                    mem::replace(&mut data.written, true)
                } else {
                    // `on_new_span` was not called, before
                    // Consider if this should panic instead, which is *technically* correct but is
                    // bad behavior for a logging layer in production.
                    false
                };

                // Print the parent of the first span
                let mut verbose = false;
                if i == 0 && pre_open {
                    if let Some(span) = span.parent() {
                        verbose = true;
                        self.write_span_info(&span, bufs, SpanMode::PreOpen);
                    }
                }

                self.write_span_info(
                    &span,
                    bufs,
                    if was_written {
                        SpanMode::Retrace { verbose }
                    } else {
                        SpanMode::Open { verbose }
                    },
                )
            }
        }
    }

    fn write_span_info<S>(&self, span: &SpanRef<S>, bufs: &mut Buffers, style: SpanMode)
    where
        S: Subscriber + for<'span> LookupSpan<'span>,
    {
        let ext = span.extensions();
        let data = ext.get::<Data>().expect("span does not have data");

        let mut current_buf = &mut bufs.current_buf;

        if self.config.span_modes {
            write_span_mode(current_buf, style)
        }

        let indent = scope_path(span).skip(1).count();

        let should_write = match style {
            SpanMode::Open { .. } | SpanMode::Event => true,
            // Print the parent of a new span again before entering the child
            SpanMode::PreOpen { .. } if self.config.verbose_entry => true,
            SpanMode::Close { verbose } => verbose,
            // Generated if `span_retrace` is enabled
            SpanMode::Retrace { .. } => true,
            // Generated if `verbose_exit` is enabled
            SpanMode::PostClose => true,
            _ => false,
        };

        if should_write {
            if self.config.targets {
                let target = span.metadata().target();
                write!(
                    &mut current_buf,
                    "{}::",
                    self.styled(Style::new().dimmed(), target,),
                )
                .expect("Unable to write to buffer");
            }

            write!(
                current_buf,
                "{name}",
                name = self.styled(Style::new().fg(Color::Green).bold(), span.metadata().name())
            )
            .unwrap();
            if self.config.bracketed_fields {
                write!(
                    current_buf,
                    "{}",
                    self.styled(Style::new().fg(Color::Green).bold(), "{") // Style::new().fg(Color::Green).dimmed().paint("{")
                )
                .unwrap();
            } else {
                write!(current_buf, " ").unwrap();
            }
            self.print_kvs(&mut current_buf, data.kvs.iter().map(|(k, v)| (*k, v)))
                .unwrap();
            if self.config.bracketed_fields {
                write!(
                    current_buf,
                    "{}",
                    self.styled(Style::new().fg(Color::Green).bold(), "}") // Style::new().dimmed().paint("}")
                )
                .unwrap();
            }
        }

        bufs.indent_current(indent, &self.config, style);
        let writer = self.make_writer.make_writer();
        bufs.flush_current_buf(writer)
    }

    fn get_timestamp<S>(&self, span: SpanRef<S>) -> Option<String>
    where
        S: Subscriber + for<'span> LookupSpan<'span>,
    {
        let ext = span.extensions();
        let data = ext
            .get::<Data>()
            .expect("Data cannot be found in extensions");

        if self.config.higher_precision {
            Some(self.format_timestamp_with_decimals(data.start))
        } else {
            Some(self.format_timestamp(data.start))
        }
    }

    fn format_timestamp(&self, start: std::time::Instant) -> String {
        let elapsed = start.elapsed();
        let millis = elapsed.as_millis();
        let secs = elapsed.as_secs();

        // Convert elapsed time to appropriate units: ms, s, or m.
        // - Less than 1s : use ms
        // - Less than 1m : use s
        // - 1m and above : use m
        let (n, unit) = if millis < 1000 {
            (millis as _, "ms")
        } else if secs < 60 {
            (secs, "s ")
        } else {
            (secs / 60, "m ")
        };

        let timestamp = format!("{n:>3}");
        self.style_timestamp(timestamp, unit)
    }

    fn format_timestamp_with_decimals(&self, start: std::time::Instant) -> String {
        let secs = start.elapsed().as_secs_f64();

        // Convert elapsed time to appropriate units: μs, ms, or s.
        // - Less than 1ms: use μs
        // - Less than 1s : use ms
        // - 1s and above : use s
        let (n, unit) = if secs < 0.001 {
            (secs * 1_000_000.0, "μs")
        } else if secs < 1.0 {
            (secs * 1_000.0, "ms")
        } else {
            (secs, "s ")
        };

        let timestamp = format!(" {n:.2}");
        self.style_timestamp(timestamp, unit)
    }

    fn style_timestamp(&self, timestamp: String, unit: &str) -> String {
        format!(
            "{timestamp}{unit} ",
            timestamp = self.styled(Style::new().dimmed(), timestamp),
            unit = self.styled(Style::new().dimmed(), unit),
        )
    }

    fn is_recursive() -> Option<RecursiveGuard> {
        thread_local! {
            pub static IS_EMPTY: AtomicBool = const { AtomicBool::new(true) };
        }

        IS_EMPTY.with(|is_empty| {
            is_empty
                .compare_exchange(true, false, Ordering::Relaxed, Ordering::Relaxed)
                .ok()
                .map(|_| RecursiveGuard(&IS_EMPTY))
        })
    }
}

struct RecursiveGuard(&'static LocalKey<AtomicBool>);

impl Drop for RecursiveGuard {
    fn drop(&mut self) {
        self.0
            .with(|is_empty| is_empty.store(true, Ordering::Relaxed));
    }
}

impl<S, W, FT> Layer<S> for HierarchicalLayer<W, FT>
where
    S: Subscriber + for<'span> LookupSpan<'span>,
    W: for<'writer> MakeWriter<'writer> + 'static,
    FT: FormatTime + 'static,
{
    fn on_new_span(&self, attrs: &Attributes, id: &Id, ctx: Context<S>) {
        let Some(_guard) = Self::is_recursive() else {
            return;
        };

        let span = ctx.span(id).expect("in new_span but span does not exist");

        if span.extensions().get::<Data>().is_none() {
            let data = Data::new(attrs, !self.config.deferred_spans);
            span.extensions_mut().insert(data);
        }

        // Entry will be printed in on_event along with retrace
        if self.config.deferred_spans {
            return;
        }

        let bufs = &mut *self.bufs.lock().unwrap();

        if self.config.span_retrace {
            self.write_retrace_span(&span, bufs, &ctx, self.config.verbose_entry);
        } else {
            if self.config.verbose_entry {
                if let Some(span) = span.parent() {
                    self.write_span_info(&span, bufs, SpanMode::PreOpen);
                }
            }
            // Store the most recently entered span
            bufs.current_span = Some(span.id());
            self.write_span_info(
                &span,
                bufs,
                SpanMode::Open {
                    verbose: self.config.verbose_entry,
                },
            );
        }
    }

    fn on_event(&self, event: &Event<'_>, ctx: Context<S>) {
        let Some(_guard) = Self::is_recursive() else {
            return;
        };

        let span = ctx.current_span();
        let span_id = span.id();
        let span = span_id.and_then(|id| ctx.span(id));

        let mut guard = self.bufs.lock().unwrap();
        let bufs = &mut *guard;

        if let Some(new_span) = &span {
            if self.config.span_retrace || self.config.deferred_spans {
                self.write_retrace_span(new_span, bufs, &ctx, self.config.verbose_entry);
            }
        }

        let mut event_buf = &mut bufs.current_buf;

        // Time.

        {
            let prev_buffer_len = event_buf.len();

            self.timer
                .format_time(&mut event_buf)
                .expect("Unable to write time to buffer");

            // Something was written to the buffer, pad it with a space.
            if prev_buffer_len < event_buf.len() {
                write!(event_buf, " ").expect("Unable to write to buffer");
            }
        }

        let deindent = if self.config.indent_lines { 0 } else { 1 };
        // printing the indentation
        let indent = ctx
            .event_scope(event)
            .map(|scope| scope.count() - deindent)
            .unwrap_or(0);

        // check if this event occurred in the context of a span.
        // if it has, get the start time of this span.
        if let Some(span) = span {
            if let Some(timestamp) = self.get_timestamp(span) {
                write!(&mut event_buf, "{}", timestamp).expect("Unable to write to buffer");
            }
        }

        #[cfg(feature = "tracing-log")]
        let normalized_meta = event.normalized_metadata();
        #[cfg(feature = "tracing-log")]
        let metadata = normalized_meta.as_ref().unwrap_or_else(|| event.metadata());
        #[cfg(not(feature = "tracing-log"))]
        let metadata = event.metadata();

        let level = metadata.level();
        let level = if self.config.ansi {
            ColorLevel(level).to_string()
        } else {
            level.to_string()
        };

        write!(&mut event_buf, "{level}", level = level).expect("Unable to write to buffer");

        if self.config.targets {
            let target = metadata.target();
            write!(
                &mut event_buf,
                " {}",
                self.styled(Style::new().dimmed(), target,),
            )
            .expect("Unable to write to buffer");
        }

        let mut visitor = FmtEvent { comma: false, bufs };
        event.record(&mut visitor);
        visitor
            .bufs
            .indent_current(indent, &self.config, SpanMode::Event);
        let writer = self.make_writer.make_writer();
        bufs.flush_current_buf(writer)
    }

    fn on_close(&self, id: Id, ctx: Context<S>) {
        let Some(_guard) = Self::is_recursive() else {
            return;
        };

        let bufs = &mut *self.bufs.lock().unwrap();

        let span = ctx.span(&id).expect("invalid span in on_close");

        // Span was not printed, so don't print an exit
        if self.config.deferred_spans
            && span.extensions().get::<Data>().map(|v| v.written) != Some(true)
        {
            return;
        }

        // self.write_retrace_span(&span, bufs, &ctx);

        self.write_span_info(
            &span,
            bufs,
            SpanMode::Close {
                verbose: self.config.verbose_exit,
            },
        );

        if let Some(parent_span) = span.parent() {
            bufs.current_span = Some(parent_span.id());
            if self.config.verbose_exit {
                // Consider parent as entered

                self.write_span_info(&parent_span, bufs, SpanMode::PostClose);
            }
        }
    }
}

fn scope_path<'a, R: LookupSpan<'a>>(span: &SpanRef<'a, R>) -> ScopeFromRoot<'a, R> {
    span.scope().from_root()
}

/// Runs `A` and `B` side by side and only yields items present in `B`
struct DifferenceIter<L, R, F> {
    left: Fuse<L>,
    right: R,
    compare: F,
}

impl<L: Iterator<Item = T>, R: Iterator<Item = T>, T, U: PartialEq, F: Fn(&T) -> U>
    DifferenceIter<L, R, F>
{
    fn new(left: L, right: R, compare: F) -> Self {
        Self {
            left: left.fuse(),
            right,
            compare,
        }
    }
}

impl<L: Iterator<Item = T>, R: Iterator<Item = T>, T, U: PartialEq, F: Fn(&T) -> U> Iterator
    for DifferenceIter<L, R, F>
{
    type Item = T;

    fn next(&mut self) -> Option<Self::Item> {
        loop {
            let left = self.left.next();
            let right = self.right.next()?;

            if left.as_ref().map(&self.compare) != Some((self.compare)(&right)) {
                return Some(right);
            }
        }
    }
}
