//! Linux permission backend.
//!
//! Most traditional Linux systems have no TCC-like consent model for the
//! domains this enum covers. Permission typically falls out of:
//!
//! - file / device permissions (e.g. reading `/dev/video0` for camera)
//! - desktop-portal prompts for sandboxed apps (Flatpak / Snap)
//! - polkit for privileged actions
//!
//! For a pragmatic v1 we:
//!
//! - probe the relevant device/path for Camera, Microphone, ScreenCapture
//! - check Chrome/Chromium availability for Browser
//! - return `NotApplicable` for Contacts, Calendar, Mail, Accessibility,
//!   Automation — there is no OS-level permission registry to query

use super::{Context, Domain, PermissionError, PermissionStatus};

pub fn status_with(domain: Domain, _ctx: &Context) -> Result<PermissionStatus, PermissionError> {
    Ok(match domain {
        Domain::Browser => browser_status(),
        Domain::Camera => device_status("/dev/video0"),
        Domain::Microphone => device_status("/dev/snd"),
        Domain::ScreenCapture => screen_status(),
        Domain::Contacts
        | Domain::Calendar
        | Domain::Mail
        | Domain::Accessibility
        | Domain::Automation
        | Domain::HealthRead => PermissionStatus::NotApplicable,
        _ => PermissionStatus::NotApplicable,
    })
}

pub fn request_with(domain: Domain, ctx: &Context) -> Result<PermissionStatus, PermissionError> {
    // No portal-based prompt is reliable without caller context (xdg-desktop-
    // portal needs an app-id or parent window). v1 returns the current
    // status; callers that want portal prompts can call into them directly
    // from their own code.
    status_with(domain, ctx)
}

pub fn describe(domain: Domain, status: PermissionStatus) -> (String, Option<String>) {
    match (domain, status) {
        (_, PermissionStatus::Granted) => ("Granted.".to_string(), None),
        (_, PermissionStatus::NotApplicable) => (
            "Not applicable on Linux — no OS-level permission registry for \
             this domain. Access is governed by file perms, DE settings, or \
             app-specific config."
                .to_string(),
            None,
        ),
        (Domain::Browser, _) => (
            "No Chrome/Chromium binary found.".to_string(),
            Some(
                "Install google-chrome, chromium, or chromium-browser via \
                 your package manager."
                    .to_string(),
            ),
        ),
        (Domain::Camera, _) => (
            "Camera device /dev/video0 is not readable by the current user.".to_string(),
            Some(
                "Add your user to the 'video' group and re-login, or ensure \
                 a camera is connected."
                    .to_string(),
            ),
        ),
        (Domain::Microphone, _) => (
            "Audio device /dev/snd is not accessible.".to_string(),
            Some(
                "Add your user to the 'audio' group and re-login, and check \
                 that PulseAudio/PipeWire is running."
                    .to_string(),
            ),
        ),
        (Domain::ScreenCapture, _) => (
            "Screen capture requires a graphical session.".to_string(),
            Some("Run under X11 or Wayland with xdg-desktop-portal available.".to_string()),
        ),
        (
            Domain::Contacts
            | Domain::Calendar
            | Domain::Mail
            | Domain::Accessibility
            | Domain::Automation,
            _,
        ) => (
            "Not applicable on Linux — no OS-level permission registry for \
             this domain."
                .to_string(),
            None,
        ),
        (_, _) => ("Domain not modeled on Linux yet.".to_string(), None),
    }
}

fn browser_status() -> PermissionStatus {
    // Direct PATH scan — don't rely on `command`, which is a shell
    // builtin and isn't always present as an executable.
    let names = [
        "google-chrome",
        "chromium",
        "chromium-browser",
        "microsoft-edge",
    ];
    if let Ok(path) = std::env::var("PATH") {
        for dir in path.split(':') {
            for name in names {
                let p = std::path::Path::new(dir).join(name);
                if p.exists() {
                    return PermissionStatus::Granted;
                }
            }
        }
    }
    PermissionStatus::Denied
}

fn device_status(path: &str) -> PermissionStatus {
    let p = std::path::Path::new(path);
    if !p.exists() {
        return PermissionStatus::Denied;
    }
    // Best-effort readability probe — opening for read without doing
    // anything is cheap and doesn't produce side effects.
    match std::fs::File::open(p) {
        Ok(_) => PermissionStatus::Granted,
        Err(_) => PermissionStatus::Denied,
    }
}

fn screen_status() -> PermissionStatus {
    // X11 or Wayland session available?
    if std::env::var("WAYLAND_DISPLAY").is_ok() || std::env::var("DISPLAY").is_ok() {
        PermissionStatus::Granted
    } else {
        PermissionStatus::Denied
    }
}
