pub mod network;
pub mod syscall;
pub mod system;

use std::fs;

use crate::engine::feedback::OperationResult;
use crate::engine::real_ops::disk;
use crate::operations::Operation;

/// Execute an operation using initrd-compatible tools (no systemd dbus).
pub fn execute(op: &Operation) -> OperationResult {
    match op {
        // Network — ip link
        Operation::EnableInterface { interface } => network::enable_interface(interface),
        Operation::DisableInterface { interface } => network::disable_interface(interface),

        // Network — wifi (iw + wpa_supplicant CLI, no dbus)
        Operation::ScanWifiNetworks { interface } => network::scan_wifi_networks(interface),
        Operation::ReceiveWifiScanResults { interface } => {
            network::receive_wifi_scan_results(interface)
        }
        Operation::AuthenticateWifi {
            interface,
            ssid,
            password,
        } => network::authenticate_wifi(interface, ssid, password),
        Operation::ConfigureWifiSsidAuth {
            interface,
            ssid,
            password,
        } => network::configure_wifi_ssid_auth(interface, ssid, password),
        Operation::ConfigureWifiQrCode {
            interface,
            qr_data,
        } => network::configure_wifi_qr_code(interface, qr_data),

        // Network — DHCP via dhcpcd
        Operation::ConfigureDhcp { interface } => network::configure_dhcp(interface),
        Operation::SelectPrimaryInterface { interface } => {
            network::select_primary_interface(interface)
        }
        Operation::ShutdownInterface { interface } => network::shutdown_interface(interface),

        // Network — checks (sysfs/ip/ping/getent, no dbus)
        Operation::CheckLinkAvailability { interface } => {
            network::check_link_availability(interface)
        }
        Operation::CheckIpAddress { interface } => network::check_ip_address(interface),
        Operation::CheckUpstreamRouter { interface } => {
            network::check_upstream_router(interface)
        }
        Operation::CheckInternetRoutability { interface } => {
            network::check_internet_routability(interface)
        }
        Operation::CheckDnsResolution {
            interface,
            hostname,
        } => network::check_dns_resolution(interface, hostname),

        // WPS push-button
        Operation::WpsPbcStart { interface } => network::wps_pbc_start(interface),
        Operation::WpsPbcStatus { interface } => network::wps_pbc_status(interface),

        // Network — state records (no system action)
        Operation::WifiConnectionTimeout { .. } => OperationResult::WifiTimeout,
        Operation::WifiAuthError { .. } => OperationResult::WifiAuthFailed("auth error".into()),

        // Disk — reuse real_ops (same tools: parted, mkfs.btrfs, mount)
        Operation::PartitionDisk { device } => disk::partition_disk(device),
        Operation::MkfsBtrfs { devices } => disk::mkfs_btrfs(devices),
        Operation::CreateBtrfsSubvolume { mount_point, name } => {
            disk::create_btrfs_subvolume(mount_point, name)
        }
        Operation::BtrfsRaidSetup {
            devices,
            raid_level,
        } => disk::btrfs_raid_setup(devices, raid_level),
        Operation::MountFilesystem {
            device,
            mount_point,
            fs_type,
            ref options,
        } => mount_filesystem_syscall(device, mount_point, fs_type, options.as_deref()),

        // Generate fstab
        Operation::GenerateFstab {
            mount_point,
            device,
            fs_type,
        } => disk::generate_fstab(mount_point, device, fs_type),

        // Persist network config to installed system
        Operation::PersistNetworkConfig {
            mount_point,
            interface,
            mac_address,
        } => network::persist_network_config(mount_point, interface, mac_address),

        // SSH keys
        Operation::ImportSshKeys {
            mount_point,
            system_user,
            github_username,
        } => crate::ssh::execute_import_ssh_keys(mount_point, system_user, github_username),

        // System
        Operation::InstallBaseSystem { target } => system::install_base_system(target),
        Operation::Reboot => system::reboot(),
        Operation::Exit => OperationResult::Success,
        Operation::Abort { .. } => OperationResult::Success,

        // Cleanup
        Operation::CleanupNetworkConfig { interface } => {
            network::cleanup_network_config(interface)
        }
        Operation::CleanupWpaSupplicant { interface } => {
            network::cleanup_wpa_supplicant(interface)
        }
        Operation::CleanupUnmount { mount_point } => unmount_syscall(mount_point),

        // Getty operations
        Operation::PowerOff => system::power_off(),
        Operation::StopAllContainers => system::stop_all_containers(),
        Operation::WipeDisk { device } => system::wipe_disk(device),
    }
}

/// Mount a filesystem using the mount(2) syscall.
/// For btrfs, runs `btrfs device scan` first so RAID members are discovered.
fn mount_filesystem_syscall(device: &str, mount_point: &str, fs_type: &str, options: Option<&str>) -> OperationResult {
    if let Err(e) = fs::create_dir_all(mount_point) {
        return OperationResult::Error(format!(
            "failed to create mount point {}: {}",
            mount_point, e
        ));
    }

    // For btrfs RAID arrays, scan for member devices before mounting
    if fs_type == "btrfs" {
        if let Err(e) = crate::engine::real_ops::run_cmd("btrfs", &["device", "scan"]) {
            crate::engine::real_ops::cmd_log_append(format!("  btrfs device scan warning: {}", e));
        }
    }

    match nix::mount::mount(
        Some(device),
        mount_point,
        Some(fs_type),
        nix::mount::MsFlags::empty(),
        options,
    ) {
        Ok(_) => OperationResult::Success,
        Err(e) => OperationResult::Error(format!(
            "mount({}, {}, {}) failed: {}",
            device, mount_point, fs_type, e
        )),
    }
}

/// Unmount a filesystem using the umount2(2) syscall. Best-effort.
fn unmount_syscall(mount_point: &str) -> OperationResult {
    if let Err(e) = nix::mount::umount2(mount_point, nix::mount::MntFlags::MNT_DETACH) {
        crate::engine::real_ops::cmd_log_append(format!(
            "  umount2 warning (best-effort): {}",
            e
        ));
    }
    OperationResult::Success
}
