use crate::driver::base::uevent::kobject_uevent::kobject_uevent_env;
use core::fmt::Write;
/*
Struct
    kset_uevent_ops

Function

    get_ktype
    kobject_name
    kset_get
    kset_put
    to_kset
*/
use crate::driver::base::kobject::KObject;
use crate::driver::net::Iface;
use crate::filesystem::sysfs::{Attribute, SysFSOpsSupport, SYSFS_ATTR_MODE_RW};
use alloc::string::{String, ToString};
use alloc::sync::Arc;
use alloc::vec::Vec;
use intertrait::cast::CastArc;
use log::warn;
use system_error::SystemError;

use super::block::block_device::{BlockDevice, BlockDeviceOps};
use super::char::CharDevice;
use super::device::{Device, DeviceType};

pub mod kobject_uevent;

// https://code.dragonos.org.cn/xref/linux-6.1.9/lib/kobject_uevent.c?fi=kobject_uevent#457
#[derive(Debug)]
pub enum KobjectAction {
    KOBJADD,
    KOBJREMOVE, // Kobject（或上层数据结构）的添加/移除事件
    KOBJCHANGE, // Kobject（或上层数据结构）的状态或者内容发生改变; 如果设备驱动需要上报的事件不再上面事件的范围内，或者是自定义的事件，可以使用该event，并携带相应的参数。
    KOBJMOVE,   // Kobject（或上层数据结构）更改名称或者更改Parent（意味着在sysfs中更改了目录结构）
    KOBJONLINE,
    KOBJOFFLINE, // Kobject（或上层数据结构）的上线/下线事件，其实是是否使能
    KOBJBIND,
    KOBJUNBIND,
}

/// 解析一个字符串，以确定它代表的是哪个 kobject_action，并提取出随后的参数（如果有的话）
fn kobject_action_type(buf: &[u8]) -> Result<(KobjectAction, Vec<String>), SystemError> {
    let mut action = KobjectAction::KOBJCHANGE;
    let mut action_args: Vec<String> = Vec::new();
    let mut count = buf.len();
    if count != 0 && (buf[count - 1] == b'\n' || buf[count - 1] == b'\0') {
        count -= 1;
    }
    if count == 0 {
        return Err(SystemError::EINVAL);
    }

    let arg_start = buf.iter().position(|&c| c == b' ').unwrap_or(count);
    let count_first = arg_start;
    let args_start = arg_start + 1;

    // 匹配KobjectAction
    match &buf[..count_first] {
        b"add" => action = KobjectAction::KOBJADD,
        b"remove" => action = KobjectAction::KOBJREMOVE,
        b"change" => action = KobjectAction::KOBJCHANGE,
        b"move" => action = KobjectAction::KOBJMOVE,
        b"online" => action = KobjectAction::KOBJONLINE,
        b"offline" => action = KobjectAction::KOBJOFFLINE,
        b"bind" => action = KobjectAction::KOBJBIND,
        b"unbind" => action = KobjectAction::KOBJUNBIND,
        _ => return Err(SystemError::EINVAL),
    }

    // 如果有参数，提取参数
    if count - args_start > 0 {
        action_args = buf[args_start..]
            .split(|&c| c == b' ')
            .map(|s| String::from_utf8_lossy(s).to_string())
            .collect::<Vec<_>>();
    }

    Ok((action, action_args))
}

pub const UEVENT_NUM_ENVP: usize = 64;
pub const UEVENT_BUFFER_SIZE: usize = 2048;
pub const UEVENT_HELPER_PATH_LEN: usize = 256;

/// 表示处理内核对象 uevents 的环境
/// - envp，指针数组，用于保存每个环境变量的地址，最多可支持的环境变量数量为UEVENT_NUM_ENVP。
/// - envp_idx，用于访问环境变量指针数组的index。
/// - buf，保存环境变量的buffer，最大为UEVENT_BUFFER_SIZE。
/// - buflen，访问buf的变量。
// https://code.dragonos.org.cn/xref/linux-6.1.9/include/linux/kobject.h#31
#[derive(Debug)]
pub struct KobjUeventEnv {
    argv: Vec<String>,
    envp: Vec<String>,
    envp_idx: usize,
    buf: Vec<u8>,
    buflen: usize,
}

// kset_uevent_ops是为kset量身订做的一个数据结构，里面包含filter和uevent两个回调函数，用处如下：
/*
    filter，当任何Kobject需要上报uevent时，它所属的kset可以通过该接口过滤，阻止不希望上报的event，从而达到从整体上管理的目的。

    name，该接口可以返回kset的名称。如果一个kset没有合法的名称，则其下的所有Kobject将不允许上报uvent

    uevent，当任何Kobject需要上报uevent时，它所属的kset可以通过该接口统一为这些event添加环境变量。因为很多时候上报uevent时的环境变量都是相同的，因此可以由kset统一处理，就不需要让每个Kobject独自添加了。

*/

/// 设备文件夹下的`uevent`文件的属性
#[derive(Debug, Clone, Copy)]
pub struct UeventAttr;

impl Attribute for UeventAttr {
    fn name(&self) -> &str {
        "uevent"
    }

    fn mode(&self) -> crate::filesystem::vfs::syscall::ModeType {
        SYSFS_ATTR_MODE_RW
    }

    fn support(&self) -> crate::filesystem::sysfs::SysFSOpsSupport {
        SysFSOpsSupport::ATTR_SHOW | SysFSOpsSupport::ATTR_STORE
    }

    /// 用户空间读取 uevent 文件，返回 uevent 信息
    fn show(&self, _kobj: Arc<dyn KObject>, _buf: &mut [u8]) -> Result<usize, SystemError> {
        let device = _kobj.cast::<dyn Device>().map_err(|e: Arc<dyn KObject>| {
            warn!("device:{:?} is not a device!", e);
            SystemError::EINVAL
        })?;
        log::info!("show uevent");
        let device_type = device.dev_type();
        let mut uevent_content = String::new();
        log::info!("device_type: {:?}", device_type);
        match device_type {
            DeviceType::Block => {
                let major = device.id_table().device_number().major().data();
                let minor = device.id_table().device_number().minor();
                let device_name = device.id_table().name();
                writeln!(&mut uevent_content, "MAJOR={:?}", major).unwrap();
                writeln!(&mut uevent_content, "MINOR={:?}", minor).unwrap();
                writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
                writeln!(&mut uevent_content, "DEVTYPE=disk").unwrap();
            }
            DeviceType::Char => {
                let major = device.id_table().device_number().major().data();
                let minor = device.id_table().device_number().minor();
                let device_name = device.id_table().name();
                writeln!(&mut uevent_content, "MAJOR={}", major).unwrap();
                writeln!(&mut uevent_content, "MINOR={}", minor).unwrap();
                writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
                writeln!(&mut uevent_content, "DEVTYPE=char").unwrap();
            }
            DeviceType::Net => {
                let net_device = device.clone().cast::<dyn Iface>().map_err(|e: Arc<dyn Device>| {
                    warn!("device:{:?} is not a net device!", e);
                    SystemError::EINVAL
                })?;
                let iface_id = net_device.nic_id();
                let device_name = device.name();
                writeln!(&mut uevent_content, "INTERFACE={}", device_name).unwrap();
                writeln!(&mut uevent_content, "IFINDEX={}", iface_id).unwrap();
            }
            DeviceType::Bus => {
                // 处理总线设备类型
                let device_name = device.name();
                writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
                writeln!(&mut uevent_content, "DEVTYPE=bus").unwrap();
            }
            DeviceType::Rtc => {
                // 处理RTC设备类型
                let device_name = device.name();
                writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
                writeln!(&mut uevent_content, "DEVTYPE=rtc").unwrap();
            }
            DeviceType::Pci => {
                // 处理PCI设备类型
                let device_name = device.name();
                writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
                writeln!(&mut uevent_content, "DEVTYPE=pci").unwrap();
            }
            _ => {
                // 处理其他设备类型
                let device_name = device.name();
                writeln!(&mut uevent_content, "DEVNAME={}", device_name).unwrap();
                writeln!(&mut uevent_content, "DEVTYPE={:?}", device_type).unwrap();
            }
        }
        sysfs_emit_str(_buf, &uevent_content)
    }
    /// 捕获来自用户空间对 uevent 文件的写操作，触发uevent事件
    fn store(&self, _kobj: Arc<dyn KObject>, _buf: &[u8]) -> Result<usize, SystemError> {
        log::info!("store uevent");
        return kobject_synth_uevent(_buf, _kobj);
    }
}


/// 将设备的基本信息写入 uevent 文件
fn sysfs_emit_str(buf: &mut [u8], content: &str) -> Result<usize, SystemError> {
    log::info!("sysfs_emit_str");
    let bytes = content.as_bytes();
    if buf.len() < bytes.len() {
        return Err(SystemError::ENOMEM);
    }
    buf[..bytes.len()].copy_from_slice(bytes);
    Ok(bytes.len())
}

/// 解析用户空间写入的 uevent 信息，触发 uevent 事件
fn kobject_synth_uevent(buf: &[u8], kobj: Arc<dyn KObject>) -> Result<usize, SystemError> {
    let no_uuid_envp = vec!["SYNTH_UUID=0".to_string()];
    let (action, action_args) = kobject_action_type(buf)?;

    let result = if action_args.is_empty() {
        kobject_uevent_env(kobj.clone(), action, no_uuid_envp)
    } else {
        kobject_uevent_env(kobj.clone(), action, action_args)
    };

    if let Err(e) = result {
        let device = kobj.cast::<dyn Device>().map_err(|e: Arc<dyn KObject>| {
            warn!("device:{:?} is not a device!", e);
            SystemError::EINVAL
        })?;
        let devname = device.name();
        log::error!("synth uevent: {}: {:?}", devname, e);
        return Err(SystemError::EINVAL);
    }
    Ok(buf.len())
}
