import { get } from 'svelte/store';
import { ae_loc, ae_api, ae_sess, slct } from '$lib/stores/ae_stores';

/**
 * electron_relay.ts
 * TypeScript relay for Aether Native (Electron) Bridge.
 * Standardizes all IPC calls to snake_case.
 */

const native =
    typeof window !== 'undefined' ? (window as any).aetherNative : null;

export const is_native = !!native;

// 1. Core Config
export async function get_device_config() {
    if (!native) return null;
    return await native.get_device_config();
}

export async function get_device_info() {
    if (!native) return null;
    return await native.get_device_info();
}

// 2. File & Cache Management
export async function check_hash_file_cache({
    cache_root,
    hash,
    hash_prefix_length = 2,
    verify_hash = false
}: any) {
    if (!native) return false;
    return await native.check_cache({
        cache_root,
        hash,
        hash_prefix_length,
        verify_hash
    });
}

export async function download_to_cache({
    url,
    cache_root,
    hash,
    api_key,
    account_id,
    hash_prefix_length = 2
}: any) {
    if (!native)
        return { success: false, error: 'Native bridge not available' };
    return await native.download_to_cache({
        url,
        cache_root,
        hash,
        api_key,
        account_id,
        hash_prefix_length
    });
}

export async function launch_from_cache({
    cache_root,
    hash,
    temp_root,
    filename,
    hash_prefix_length = 2,
    native_template = null
}: {
    cache_root: string;
    hash: string;
    temp_root: string;
    filename: string;
    hash_prefix_length?: number;
    /**
     * Resolved native launch template. If provided, Electron executes this string
     * after the file is copied to temp.
     *
     * Two formats:
     *   - AppleScript: multi-line string with {{path}} placeholder (macOS only)
     *   - Shell command: prefix with "shell:" → e.g. "shell:open \"{{path}}\""
     *
        * Configure via per-profile launch_profiles overrides in event_device.data_json or $events_loc.launcher.
     * If null, Electron should treat that as a missing profile error.
     */
    native_template?: string | null;
}) {
    if (!native)
        return { success: false, error: 'Native bridge not available' };
    return await native.launch_from_cache({
        cache_root,
        hash,
        temp_root,
        filename,
        hash_prefix_length,
        native_template
    });
}

/**
 * Thin cache primitive — copies a cached file to the temp directory and returns
 * the resolved path. The caller decides what happens next.
 *
 * Preferred building block for composable launch flows on the Svelte side:
 *   1. copy_from_cache_to_temp(...)  → { path }
 *   2. run_osascript(template.replace('{{path}}', path))
 *      OR run_cmd(`open "${path}"`)
 *      OR whatever you need
 *
 * Use launch_from_cache when the built-in hardcoded logic is sufficient.
 * Use this when you want full control over what happens after the file lands in temp.
 */
export async function copy_from_cache_to_temp({
    cache_root,
    hash,
    temp_root,
    filename,
    hash_prefix_length = 2
}: {
    cache_root: string;
    hash: string;
    temp_root: string;
    filename: string;
    hash_prefix_length?: number;
}): Promise<{ success: boolean; path?: string; error?: string }> {
    if (!native)
        return { success: false, error: 'Native bridge not available' };
    return await native.copy_from_cache_to_temp({
        cache_root,
        hash,
        temp_root,
        filename,
        hash_prefix_length
    });
}

// 3. OS Shell Commands (Phase 3)
export async function open_folder(path: string) {
    if (!native)
        return { success: false, error: 'Native bridge not available' };
    return await native.open_folder(path);
}

export async function run_cmd({
    cmd,
    timeout = 30000,
    return_stdout = true
}: {
    cmd: string;
    timeout?: number;
    return_stdout?: boolean;
}) {
    if (!native)
        return { success: false, error: 'Native bridge not available' };
    return await native.run_cmd({ cmd, timeout, return_stdout });
}

export async function run_cmd_sync({
    cmd,
    return_stdout = true
}: {
    cmd: string;
    return_stdout?: boolean;
}) {
    if (!native)
        return { success: false, error: 'Native bridge not available' };
    return await native.run_cmd_sync({ cmd, return_stdout });
}

/**
 * Stale .tmp Cleanup
 * Deletes in-progress download artifacts (*.tmp) older than max_age_minutes from the cache root.
 * Called at launcher startup to prevent cache directory bloat from interrupted downloads.
 * Default: 1440 minutes = 24 hours.
 */
export async function cleanup_tmp_files({
    cache_root,
    max_age_minutes = 1440
}: {
    cache_root: string;
    max_age_minutes?: number;
}) {
    if (!native)
        return { success: false, error: 'Native bridge not available' };
    const cmd = `find "${cache_root}" -name "*.tmp" -mmin +${max_age_minutes} -type f -delete`;
    return await native.run_cmd({ cmd, timeout: 30000, return_stdout: false });
}

/**
 * Executes an AppleScript string. macOS only.
 *
 * HARDENED (2026-05-11): The Electron handler now writes the script to a temp .scpt
 * file and runs `osascript "/path/to/file.scpt"` rather than passing it inline via
 * the -e flag. This means:
 *   - Multi-line scripts work correctly
 *   - Paths with spaces or special characters work correctly
 *   - No shell escaping required in the script string you pass here
 *
 * The .scpt file is deleted immediately after execution.
 */
export async function run_osascript(script: string) {
    if (!native)
        return { success: false, error: 'Native bridge not available' };
    return await native.run_osascript(script);
}

export async function kill_processes({
    process_name_li = []
}: {
    process_name_li: string[];
}) {
    if (!native)
        return { success: false, error: 'Native bridge not available' };
    return await native.kill_processes({ process_name_li });
}

export async function open_local_file_v2(path: string) {
    if (!native)
        return { success: false, error: 'Native bridge not available' };
    return await native.open_local_file_v2(path);
}

/**
 * Specialized Presentation Launcher (Phase 5)
 * Handles platform-specific application selection (LibreOffice on Linux,
 * PowerPoint/Keynote on macOS).
 */
export async function launch_presentation({
    path,
    app = 'default',
    os = 'auto',
    log_lvl = 0
}: {
    path: string;
    app?: 'default' | 'powerpoint' | 'keynote' | 'libreoffice';
    os?: 'auto' | 'linux' | 'darwin' | 'win32';
    log_lvl?: number;
}) {
    if (!native)
        return { success: false, error: 'Native bridge not available' };

    // 1. Detect OS if set to auto
    let platform = os;
    if (platform === 'auto') {
        const info = await get_device_info();
        platform = info?.platform || 'linux';
    }

    // 2. Prefer the Native Bridge implementation (Atomic Copy-and-Launch)
    // This delegates to the hardened logic in electron_native.js
    if (native.launch_presentation) {
        if (log_lvl) console.log('Relay: Using native.launch_presentation');
        return await native.launch_presentation({
            path,
            app,
            os_platform: platform
        });
    }

    // 3. Relay-side Fallback (Mock/Legacy)
    // Manually resolve placeholders using all available context
    const info = await get_device_info();
    const loc = get(ae_loc);

    // Attempt to find home/tmp from bridge info OR local hydrated store
    const home =
        info?.home_directory ||
        loc.home_directory ||
        loc.native_device?.home_directory ||
        '';
    const tmp =
        info?.tmp_directory ||
        loc.tmp_directory ||
        loc.native_device?.tmp_directory ||
        '';

    if (log_lvl) console.log('Relay Debug:', { home, tmp, raw_path: path });

    // CRITICAL: Resolve all instances of placeholders using global regex
    let cleaned_path = path;
    if (home) cleaned_path = cleaned_path.replace(/\[home\]/g, home);
    if (tmp) cleaned_path = cleaned_path.replace(/\[tmp\]/g, tmp);

    if (log_lvl)
        console.log(`Relay Fallback: Resolving ${path} -> ${cleaned_path}`);

    // If path still contains [home] or [tmp], it means we failed to resolve it.
    if (cleaned_path.includes('[home]') || cleaned_path.includes('[tmp]')) {
        console.error(
            'Relay Error: Could not resolve path placeholders. Home or Tmp directory unknown.',
            { home, tmp }
        );
        return { success: false, error: 'Could not resolve path placeholders' };
    }

    if (platform === 'linux') {
        if (log_lvl)
            console.log(
                `Relay: Launching LibreOffice on Linux for path: ${cleaned_path}`
            );
        return await run_cmd({
            cmd: `libreoffice --impress "${cleaned_path}"`
        });
    }

    if (platform === 'darwin') {
        if (app === 'keynote') {
            return await run_osascript(
                `tell application "Keynote" to open POSIX file "${cleaned_path}"`
            );
        }
        return await open_local_file_v2(cleaned_path);
    }

    return await open_local_file_v2(cleaned_path);
}

/**
 * Control Presentation (Phase 5)
 * Sends navigation commands to the active presentation (Next, Prev, Stop).
 */
export async function control_presentation({
    app,
    action
}: {
    app: 'powerpoint' | 'keynote';
    action: 'next' | 'prev' | 'start' | 'stop';
}) {
    if (!native)
        return { success: false, error: 'Native bridge not available' };

    // Check if the native bridge has the direct implementation
    if (native.control_presentation) {
        return await native.control_presentation({ app, action });
    }

    // Fallback to generic osascript if direct handler is missing
    let script = '';
    if (app === 'powerpoint') {
        switch (action) {
            case 'next':
                script =
                    'tell application "Microsoft PowerPoint" to next slide of slide show view of active presentation';
                break;
            case 'prev':
                script =
                    'tell application "Microsoft PowerPoint" to previous slide of slide show view of active presentation';
                break;
            case 'start':
                script =
                    'tell application "Microsoft PowerPoint" to run slide show of active presentation';
                break;
            case 'stop':
                script =
                    'tell application "Microsoft PowerPoint" to stop slide show of active presentation';
                break;
        }
    } else if (app === 'keynote') {
        switch (action) {
            case 'next':
                script = 'tell application "Keynote" to show next';
                break;
            case 'prev':
                script = 'tell application "Keynote" to show previous';
                break;
            case 'start':
                script = 'tell application "Keynote" to start (front document)';
                break;
            case 'stop':
                script = 'tell application "Keynote" to stop';
                break;
        }
    }

    if (script) {
        return await run_osascript(script);
    }

    return {
        success: false,
        error: `Unsupported app or action: ${app}/${action}`
    };
}

// 4. System Management (Phase 5+)

export async function set_wallpaper({
    path,
    url,
    url_external,
    display = 'all',
    api_key,
    account_id
}: {
    /** Local file path (existing behavior). */
    path?: string;
    /** HTTPS URL — downloaded to ~/Library/Caches/OSIT/wallpaper/ before applying. */
    url?: string;
    /** Optional separate URL for the external/projector display only. */
    url_external?: string;
    /** Which display(s) to target. Defaults to 'all'. */
    display?: 'all' | 'primary' | 'external';
    /** Aether API key passed as x-aether-api-key header on the download request. */
    api_key?: string;
    /** Aether account ID passed as x-account-id header on the download request. */
    account_id?: string;
}) {
    if (!native || !native.set_wallpaper)
        return {
            success: false,
            error: 'Native handler set_wallpaper not available'
        };
    return await native.set_wallpaper({ path, url, url_external, display, api_key, account_id });
}

/**
 * Restores the macOS default wallpaper on all displays.
 * Scans /System/Library/Desktop Pictures/ for the first .heic file — works across
 * all recent macOS versions without needing to know the version name.
 * No-op on non-macOS (Linux/Windows return success:false from run_osascript).
 */
export async function restore_macos_default_wallpaper(
    display: 'all' | 'primary' | 'external' = 'all'
): Promise<{ success: boolean; error?: string }> {
    const display_target =
        display === 'primary'
            ? 'tell desktop 1'
            : display === 'external'
              ? 'tell desktop 2'
              : 'tell every desktop';

    const script = `
set pic_path to do shell script "ls '/System/Library/Desktop Pictures/'*.heic 2>/dev/null | head -1"
if pic_path is "" then
    error "No default macOS wallpaper (.heic) found in /System/Library/Desktop Pictures/"
end if
tell application "System Events"
    ${display_target}
        set picture to pic_path
    end tell
end tell
`.trim();

    const result = await run_osascript(script);
    return result ?? { success: false, error: 'Native bridge not available' };
}

export async function update_app(args: {
    source: 'url' | 'file';
    url?: string;
    path?: string;
}) {
    if (!native || !native.update_app)
        return {
            success: false,
            error: 'Native handler update_app not available'
        };
    return await native.update_app(args);
}

export async function window_control({
    action,
    value
}: {
    action: string;
    value?: any;
}) {
    if (!native || !native.window_control)
        return {
            success: false,
            error: 'Native handler window_control not available'
        };
    return await native.window_control({ action, value });
}

export async function manage_recording({
    action,
    options
}: {
    action: 'start' | 'stop' | 'status';
    options?: any;
}) {
    if (!native || !native.manage_recording)
        return {
            success: false,
            error: 'Native handler manage_recording not available'
        };
    return await native.manage_recording({ action, options });
}

export async function set_display_layout({
    mode,
    configStr
}: {
    mode: 'mirror' | 'extend';
    configStr?: string;
}) {
    if (!native || !native.set_display_layout)
        return {
            success: false,
            error: 'Native handler set_display_layout not available'
        };
    return await native.set_display_layout({ mode, configStr });
}

export async function list_display_modes() {
    if (!native || !native.list_display_modes)
        return { success: false, error: 'Native handler list_display_modes not available' };
    return await native.list_display_modes();
}

export async function set_display_mode({
    display_index,
    width,
    height,
    refresh_rate,
    hidpi
}: {
    display_index: number;
    width: number;
    height: number;
    refresh_rate?: number;
    hidpi?: boolean | null;
}) {
    if (!native || !native.set_display_mode)
        return { success: false, error: 'Native handler set_display_mode not available' };
    return await native.set_display_mode({ display_index, width, height, refresh_rate, hidpi });
}

export async function power_control({
    action
}: {
    action: 'shutdown' | 'reboot' | 'sleep';
}) {
    if (!native || !native.power_control)
        return {
            success: false,
            error: 'Native handler power_control not available'
        };
    return await native.power_control({ action });
}

export async function open_external({
    url,
    app
}: {
    url: string;
    app?: 'chrome' | 'firefox' | 'default';
}) {
    if (!native || !native.open_external)
        return {
            success: false,
            error: 'Native handler open_external not available'
        };
    return await native.open_external({ url, app });
}

/**
 * List Tools (Self-Documentation)
 * Returns a JSON manifest of all available native bridge functions.
 */
export async function list_tools() {
    if (!native || !native.list_tools) return [];
    return await native.list_tools();
}
