/*
 * Copyright (c) 2025, LJason. All Rights Reserved.
 */

//! # Bili Core - API Documentation
//!
//! 欢迎来到 Bili Core API 文档！
//!
//! 该库提供了对 Bilibili 网站 API 的访问功能，支持通过 feature 按需启用不同的 API 模块。

use std::{
    sync::{Arc, Mutex},
    time::Duration,
};

use reqwest::{Client, RequestBuilder};

use crate::extensions::LockOrPanic;

mod account;
mod api;
mod error;
mod extensions;
mod request;
mod response;

#[cfg(feature = "fav")]
pub use api::fav;

pub use account::Account;
pub use error::BiCoreError;
pub use request::BiliRequest;
pub use response::Response;

// 避免使用 musl 默认配置器
// https://nickb.dev/blog/default-musl-allocator-considered-harmful-to-performance/
#[cfg(target_env = "musl")]
#[global_allocator]
static GLOBAL: mimalloc::MiMalloc = mimalloc::MiMalloc;

#[derive(Default)]
pub struct BiliCore {
    client: Client,
    account: Arc<Mutex<Account>>,
}

impl BiliCore {
    /// 创建一个新的 `BiliCore` 实例
    ///
    /// # Panics
    ///
    /// 在构建 HTTP 客户端失败时会 panic。
    #[must_use]
    pub fn new() -> Self {
        #[allow(clippy::expect_used)]
        let client = Client::builder().timeout(Duration::from_secs(10)).gzip(true).build().expect("创建 HTTP 客户端失败");
        Self { client, account: Arc::new(Mutex::new(Account::default())) }
    }

    /// 设置登录所需的 SESSDATA
    pub fn set_sessdata(&self, sessdata: impl Into<String>) {
        let mut account = self.account.lock_or_panic();
        account.set_sessdata(sessdata);
    }

    /// 设置认证所需的 Jct
    pub fn set_bili_jct(&self, jct: impl Into<String>) {
        let mut account = self.account.lock_or_panic();
        account.set_bili_jct(jct);
    }
}

impl BiliCore {
    const BASE_URL: &str = "https://api.bilibili.com";

    fn get(&self, url: &str) -> RequestBuilder {
        self.client.get(format!("{}/{url}", Self::BASE_URL)).header("Cookie", self.account.lock_or_panic().to_cookie_str())
    }

    #[allow(dead_code)]
    fn post(&self, url: &str) -> RequestBuilder {
        self.client.post(format!("{}/{url}", Self::BASE_URL)).header("Cookie", self.account.lock_or_panic().to_cookie_str())
    }
}
