// Copyright (C) 2025 Huawei Device Co., Ltd.
// Licensed under the Apache License, Version 2.0 (the "License");
// you may not use this file except in compliance with the License.
// You may obtain a copy of the License at
//
//     http://www.apache.org/licenses/LICENSE-2.0
//
// Unless required by applicable law or agreed to in writing, software
// distributed under the License is distributed on an "AS IS" BASIS,
// WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, either express or implied.
// See the License for the specific language governing permissions and
// limitations under the License.

//! Module for tracking and reporting task completion statistics.
//!
//! This module provides utilities to count completed and failed tasks, and
//! report these statistics when tasks are unloaded. It uses a thread-safe
//! singleton pattern to maintain the count state across the application.

use std::sync::{Arc, Mutex, Once};

/// Internal struct for tracking request task statistics.
///
/// This struct maintains counts of completed and failed tasks, along with a
/// state flag indicating whether any tasks have been recorded since the last
/// report.
struct RequestTaskCount {
    /// Number of successfully completed tasks.
    completed_task_count: i32,
    /// Number of failed tasks.
    failed_task_count: i32,
    /// Flag indicating whether task counts have been updated since last report.
    load_state: bool,
}

impl RequestTaskCount {
    /// Gets a thread-safe singleton instance of `RequestTaskCount`.
    ///
    /// This method implements the singleton pattern with thread safety,
    /// ensuring that only one instance of `RequestTaskCount` exists
    /// throughout the application lifecycle.
    ///
    /// # Safety
    ///
    /// This method uses `unsafe` code to access and initialize the static
    /// instance. The `Once` mechanism guarantees that initialization happens
    /// exactly once, and subsequent accesses are safe.
    ///
    /// # Returns
    ///
    /// Returns a reference-counted pointer to a mutex-wrapped
    /// `RequestTaskCount` instance.
    fn get_instance() -> Arc<Mutex<RequestTaskCount>> {
        // Static storage for the singleton instance
        static mut TASK_COUNT: Option<Arc<Mutex<RequestTaskCount>>> = None;
        // Ensures the initialization happens exactly once
        static ONCE: Once = Once::new();

        ONCE.call_once(|| {
            // Initialize the singleton instance with default values
            unsafe {
                TASK_COUNT = Some(Arc::new(Mutex::new(RequestTaskCount {
                    completed_task_count: 0,
                    failed_task_count: 0,
                    load_state: false,
                })))
            };
        });

        // Return a clone of the Arc to increment the reference count
        unsafe { TASK_COUNT.as_ref().unwrap().clone() }
    }
}

/// Increments the count of successfully completed tasks.
///
/// This function safely increments the completed task counter and sets the
/// load state flag to indicate that statistics have been updated.
///
/// # Examples
///
/// ```rust
/// // Call when a task successfully completes
/// task_complete_add();
/// ```
pub(crate) fn task_complete_add() {
    let instance = RequestTaskCount::get_instance();
    // Lock the mutex to ensure thread safety while updating the count
    let mut task_count = instance.lock().unwrap();
    task_count.completed_task_count += 1;
    // Mark that we have new data to report
    task_count.load_state = true;
}

/// Increments the count of failed tasks.
///
/// This function safely increments the failed task counter and sets the
/// load state flag to indicate that statistics have been updated.
///
/// # Examples
///
/// ```rust
/// // Call when a task fails to complete
/// task_fail_add();
/// ```
pub(crate) fn task_fail_add() {
    let instance = RequestTaskCount::get_instance();
    // Lock the mutex to ensure thread safety while updating the count
    let mut task_count = instance.lock().unwrap();
    task_count.failed_task_count += 1;
    // Mark that we have new data to report
    task_count.load_state = true;
}

/// Reports task statistics and resets counters.
///
/// This function checks if there are new statistics to report (using the
/// load_state flag). If so, it logs the completed and failed task counts
/// using the sys_event macro, then resets all counters and the state flag.
///
/// # Notes
///
/// Statistics are only reported if the load_state flag is true, indicating
/// that task counts have been updated since the last report.
///
/// # Examples
///
/// ```rust
/// // Call when unloading tasks to report collected statistics
/// task_unload();
/// ```
pub(crate) fn task_unload() {
    let instance = RequestTaskCount::get_instance();
    // Lock the mutex to ensure thread safety while reading and resetting
    let mut task_count = instance.lock().unwrap();

    // Only report and reset if we have new data
    if task_count.load_state {
        // Capture current counts for reporting
        let completed = task_count.completed_task_count;
        let failed = task_count.failed_task_count;

        // Report statistics via system event
        sys_event!(
            ExecError,
            DfxCode::TASK_STATISTICS,
            &format!("Task Completed {}, failed {}", completed, failed)
        );

        // Reset counters and state flag
        task_count.completed_task_count = 0;
        task_count.failed_task_count = 0;
        task_count.load_state = false;
    }
}