use core::{
    hint::spin_loop,
    sync::atomic::{compiler_fence, Ordering},
};

use log::{debug, warn};
use system_error::SystemError;
use x86::dtables::DescriptorTablePointer;

use crate::{
    arch::{fpu::FpState, interrupt::trap::arch_trap_init, process::table::TSSManager},
    driver::clocksource::{acpi_pm::init_acpi_pm_clocksource, kvm_clock},
    init::init::start_kernel,
    mm::{MemoryManagementArch, PhysAddr},
};

use self::boot::early_boot_init;

use super::{
    driver::{
        hpet::{hpet_init, hpet_instance},
        tsc::TSCManager,
    },
    MMArch,
};

mod boot;
mod multiboot2;
mod pvh;
mod rsdp;

mod boot_params;

pub use self::boot_params::ArchBootParams;

extern "C" {
    static mut GDT_Table: [usize; 0usize];
    static mut IDT_Table: [usize; 0usize];
    fn head_stack_start();

}

#[no_mangle]
#[allow(static_mut_refs)]
unsafe extern "C" fn kernel_main(
    mb2_info: u64,
    mb2_magic: u64,
    bsp_gdt_size: u64,
    bsp_idt_size: u64,
    boot_entry_type: u64,
) -> ! {
    let mut gdtp = DescriptorTablePointer::<usize>::default();
    let gdt_vaddr =
        MMArch::phys_2_virt(PhysAddr::new(&GDT_Table as *const usize as usize)).unwrap();
    let idt_vaddr =
        MMArch::phys_2_virt(PhysAddr::new(&IDT_Table as *const usize as usize)).unwrap();
    gdtp.base = gdt_vaddr.data() as *const usize;
    gdtp.limit = bsp_gdt_size as u16 - 1;

    let idtp = DescriptorTablePointer::<usize> {
        base: idt_vaddr.data() as *const usize,
        limit: bsp_idt_size as u16 - 1,
    };

    x86::dtables::lgdt(&gdtp);
    x86::dtables::lidt(&idtp);

    compiler_fence(Ordering::SeqCst);
    if early_boot_init(boot_entry_type, mb2_magic, mb2_info).is_err() {
        loop {
            spin_loop();
        }
    }
    compiler_fence(Ordering::SeqCst);

    start_kernel();
}

/// 在内存管理初始化之前的架构相关的早期初始化
#[inline(never)]
#[allow(static_mut_refs)]
pub fn early_setup_arch() -> Result<(), SystemError> {
    // 初始化 XSAVE 支持（必须在任何 FPU 状态保存/恢复之前）
    FpState::init_xsave_support();

    let stack_start = unsafe { *(head_stack_start as *const u64) } as usize;
    debug!("head_stack_start={:#x}\n", stack_start);
    unsafe {
        let gdt_vaddr =
            MMArch::phys_2_virt(PhysAddr::new(&GDT_Table as *const usize as usize)).unwrap();
        let idt_vaddr =
            MMArch::phys_2_virt(PhysAddr::new(&IDT_Table as *const usize as usize)).unwrap();

        debug!("GDT_Table={:?}, IDT_Table={:?}\n", gdt_vaddr, idt_vaddr);
    }

    set_current_core_tss(stack_start, 0);
    unsafe { TSSManager::load_tr() };
    arch_trap_init().expect("arch_trap_init failed");

    return Ok(());
}

/// 架构相关的初始化
#[inline(never)]
pub fn setup_arch() -> Result<(), SystemError> {
    return Ok(());
}

/// 架构相关的初始化（在IDLE的最后一个阶段）
#[inline(never)]
pub fn setup_arch_post() -> Result<(), SystemError> {
    // ============= 初始化时钟源硬件 =============
    // 1.先尝试初始化 kvm-clock（如果在 KVM 虚拟机中运行且 kvm-clock 可用的话）
    // 2.再尝试初始化 HPET（如果硬件支持的话）
    // 3.如果 kvm-clock 和 HPET 都不可用，则回退到 ACPI PM Timer
    // 4.最后初始化 TSC 管理器 （既可以通过 kvm-clock 提供的 pvclock 确定 TSC 频率，也可以通过其他方法确定 TSC 频率）
    let kvmclock_ok = kvm_clock::kvmclock_init();
    let hpet_ok = match hpet_init() {
        Ok(()) => match hpet_instance().hpet_enable() {
            Ok(_) => true,
            Err(error) => {
                warn!(
                    "HPET enable failed, retaining fallback clocksource: {:?}",
                    error
                );
                false
            }
        },
        Err(error) => {
            warn!(
                "HPET init failed, retaining fallback clocksource: {:?}",
                error
            );
            false
        }
    };
    if !kvmclock_ok && !hpet_ok {
        if let Err(error) = init_acpi_pm_clocksource() {
            // jiffies is already registered and installed by timekeeping_init.
            warn!(
                "ACPI PM timer unavailable, continuing with jiffies: {:?}",
                error
            );
        }
    }
    if let Err(error) = TSCManager::init() {
        if TSCManager::cpu_khz() == 0 {
            // The scheduler clock and APIC timer still require CPU_KHZ even
            // when POSIX timekeeping can remain on jiffies.
            return Err(error);
        }
        warn!(
            "TSC clocksource unavailable, continuing with registered clocksource: {:?}",
            error
        );
    }

    return Ok(());
}

fn set_current_core_tss(stack_start: usize, ist0: usize) {
    let current_tss = unsafe { TSSManager::current_tss() };
    debug!(
        "set_current_core_tss: stack_start={:#x}, ist0={:#x}\n",
        stack_start, ist0
    );
    current_tss.set_rsp(x86::Ring::Ring0, stack_start as u64);
    current_tss.set_ist(0, ist0 as u64);
}
