#!/bin/sh
# ============================================================================
# setup_firefox_netflix.sh — Enable Netflix (Widevine DRM) on Firefox/FreeBSD
# ============================================================================
# This script patches the foreign-cdm port to support Firefox, rebuilds it,
# configures a Firefox profile with the necessary GMP/EME settings, and
# creates a launch script + desktop file.
#
# Requirements:
#   - FreeBSD amd64 with Linuxulator enabled
#   - Firefox installed (pkg install firefox)
#   - foreign-cdm port source extracted (/usr/ports/www/foreign-cdm)
#   - /etc/machine-id must exist
#   - Root access (will be prompted)
#
# Usage: sh setup_firefox_netflix.sh
# ============================================================================

set -e

# --- Colors ---
RED='\033[0;31m'
GREEN='\033[0;32m'
YELLOW='\033[1;33m'
NC='\033[0m'

info()  { printf "${GREEN}[+]${NC} %s\n" "$1"; }
warn()  { printf "${YELLOW}[!]${NC} %s\n" "$1"; }
error() { printf "${RED}[!]${NC} %s\n" "$1"; exit 1; }

# --- Configuration ---
PORT_DIR="/usr/ports/www/foreign-cdm"
WORK_SRC=""  # will be detected
FCDM_FBSD_SO="/usr/local/lib/foreign-cdm/fcdm-fbsd.so"
FCDM_WORKER="/usr/local/libexec/fcdm-worker"
CDM_SO="/usr/local/lib/WidevineCdm/_platform_specific/linux_x64/libwidevinecdm.so"
CDM_VERSION=""  # will be read from manifest
USER_HOME="$HOME"
LAUNCH_SCRIPT="$USER_HOME/launch_firefox_fcdm.sh"
DESKTOP_FILE="$USER_HOME/firefox-fcdm.desktop"

# ============================================================================
# 1. Preflight checks
# ============================================================================
info "Checking prerequisites..."

[ "$(uname -m)" = "amd64" ] || error "This script is for FreeBSD amd64 only."
[ -f /compat/linux/lib64/ld-linux-x86-64.so.2 ] || error "Linuxulator not enabled. Run: sudo sysrc linux_enable=YES && sudo service linux start"
command -v firefox >/dev/null 2>&1 || error "Firefox not installed. Run: sudo pkg install firefox"
[ -d "$PORT_DIR" ] || error "foreign-cdm port not found at $PORT_DIR. Run: sudo pkg install foreign-cdm (or portsnap fetch extract)"
[ -f /etc/machine-id ] || error "/etc/machine-id not found. Create one: sudo sh -c 'uuidgen | tr -d - > /etc/machine-id'"
[ -f "$CDM_SO" ] || error "Widevine CDM not found at $CDM_SO. Install the foreign-cdm package first."

# Detect port work directory
WORK_BASE="$PORT_DIR/work"
if [ ! -d "$WORK_BASE" ]; then
    info "Extracting port source..."
    sudo make -C "$PORT_DIR" extract
fi

WORK_SRC=$(find "$WORK_BASE" -maxdepth 1 -name "foreign-cdm-*" -type d | head -1)
[ -d "$WORK_SRC/src" ] || error "Port source not found in $WORK_BASE. Run: sudo make -C $PORT_DIR extract"

# Check that capnproto libs are built
if [ ! -f "$WORK_SRC/build/capnp-fbsd/c++/src/capnp/libcapnp.a" ] || \
   [ ! -f "$WORK_SRC/build/capnp-linux/c++/src/capnp/libcapnp.a" ]; then
    info "Building capnproto dependencies (this may take a while)..."
    sudo make -C "$WORK_SRC" build/capnp-fbsd build/capnp-linux MAKE_JOBS_NUMBER=$(sysctl -n hw.ncpu)
fi

# Read CDM version from manifest
if [ -f /usr/local/lib/WidevineCdm/manifest.json ]; then
    CDM_VERSION=$(sed -n 's/.*"version"[[:space:]]*:[[:space:]]*"\([^"]*\)".*/\1/p' /usr/local/lib/WidevineCdm/manifest.json)
fi
[ -n "$CDM_VERSION" ] || CDM_VERSION="4.10.2934.0"
info "CDM version: $CDM_VERSION"

# ============================================================================
# 2. Patch worker.cpp
# ============================================================================
info "Patching worker.cpp..."

WORKER_SRC="$WORK_SRC/src/worker.cpp"
WORKER_TMP=$(mktemp /tmp/worker.cpp.XXXXXX)
cp "$WORKER_SRC" "$WORKER_TMP"

# Add #include <cstdio> and <cstring> if not present
if ! grep -q '#include <cstdio>' "$WORKER_TMP"; then
    sed -i '' '/#include <cerrno>/a\
#include <cstdio>\
#include <cstring>' "$WORKER_TMP"
fi

# Patch set_host_context / clear_host_context: remove asserts, add save/restore
cat > /tmp/patch_host_ctx.py << 'PYEOF'
import sys
content = open(sys.argv[1]).read()

old_ctx = '''static void set_host_context(kj::WaitScope* scope, XAlloc* arena) {
  KJ_ASSERT(host_ctx.scope == nullptr);
  KJ_ASSERT(host_ctx.arena == nullptr);
  host_ctx.scope = scope;
  host_ctx.arena = arena;
}

static void clear_host_context() {
  KJ_ASSERT(host_ctx.scope != nullptr);
  //~ KJ_ASSERT(host_ctx.arena != nullptr);
  host_ctx.scope = nullptr;
  host_ctx.arena = nullptr;
}'''

new_ctx = '''static void set_host_context(kj::WaitScope* scope, XAlloc* arena) {
  host_ctx.scope = scope;
  host_ctx.arena = arena;
}

static void clear_host_context() {
  host_ctx.scope = nullptr;
  host_ctx.arena = nullptr;
}'''

if old_ctx in content:
    content = content.replace(old_ctx, new_ctx)
    open(sys.argv[1], 'w').write(content)
    print("  - Patched set_host_context/clear_host_context")
else:
    print("  - set_host_context already patched or not found")
PYEOF
python3 /tmp/patch_host_ctx.py "$WORKER_TMP"

# Patch Initialize: force allow_distinctive_identifier=true
cat > /tmp/patch_init.py << 'PYEOF'
import sys
content = open(sys.argv[1]).read()

old_init = '''      auto allow_distinctive_identifier = context.getParams().getAllowDistinctiveIdentifier();
      auto allow_persistent_state       = context.getParams().getAllowPersistentState();
      auto use_hw_secure_codecs         = context.getParams().getUseHwSecureCodecs();
      m_cdm->Initialize(allow_distinctive_identifier, allow_persistent_state, use_hw_secure_codecs);'''

new_init = '''      auto allow_persistent_state       = context.getParams().getAllowPersistentState();
      auto use_hw_secure_codecs         = context.getParams().getUseHwSecureCodecs();
      // Force allow_distinctive_identifier=true (Firefox sends false, CDM needs true for Netflix)
      KJ_LOG(INFO, "Initialize: FORCING allow_distinctive_identifier = true");
      m_cdm->Initialize(true, allow_persistent_state, use_hw_secure_codecs);'''

if old_init in content:
    content = content.replace(old_init, new_init)
    open(sys.argv[1], 'w').write(content)
    print("  - Patched Initialize: force allow_distinctive_identifier=true")
else:
    print("  - Initialize already patched or not found")
PYEOF
python3 /tmp/patch_init.py "$WORKER_TMP"

# Patch SendPlatformChallenge: from KJ_UNIMPLEMENTED to log+ignore
cat > /tmp/patch_spc.py << 'PYEOF'
import sys
content = open(sys.argv[1]).read()

old = '''  void SendPlatformChallenge(const char* service_id, uint32_t service_id_size, const char* challenge, uint32_t challenge_size) override {
    KJ_UNIMPLEMENTED("SendPlatformChallenge");
  }'''

new = '''  void SendPlatformChallenge(const char* service_id, uint32_t service_id_size, const char* challenge, uint32_t challenge_size) override {
    // L3 CDM does not call this (L1/TEE only). Log and ignore.
    KJ_LOG(INFO, "SendPlatformChallenge: ignoring (L3 CDM)");
  }'''

if old in content:
    content = content.replace(old, new)
    open(sys.argv[1], 'w').write(content)
    print("  - Patched SendPlatformChallenge")
else:
    print("  - SendPlatformChallenge already patched or not found")
PYEOF
python3 /tmp/patch_spc.py "$WORKER_TMP"

# Patch initializeVideoDecoder: add FCDM_REJECT_VIDEO_DECODER env var support
cat > /tmp/patch_ivd.py << 'PYEOF'
import sys
content = open(sys.argv[1]).read()

old = '''  kj::Promise<void> initializeVideoDecoder(InitializeVideoDecoderContext context) override {
    return kj::startFiber(FIBER_STACK_SIZE, [context, this](kj::WaitScope& scope) mutable {
      KJ_DLOG(INFO, "initializeVideoDecoder");
      set_host_context(&scope, &m_allocator);
      cdm::VideoDecoderConfig_2 video_decoder_config;'''

new = '''  kj::Promise<void> initializeVideoDecoder(InitializeVideoDecoderContext context) override {
    return kj::startFiber(FIBER_STACK_SIZE, [context, this](kj::WaitScope& scope) mutable {
      KJ_DLOG(INFO, "initializeVideoDecoder");

      // If FCDM_REJECT_VIDEO_DECODER=1, reject so Chromium falls back to decrypt-only + HW decode.
      // When not set (Firefox), accept CDM software decode.
      const char* reject_env = getenv("FCDM_REJECT_VIDEO_DECODER");
      if (reject_env != nullptr && strcmp(reject_env, "1") == 0) {
        KJ_LOG(INFO, "initializeVideoDecoder: REJECTING (FCDM_REJECT_VIDEO_DECODER=1)");
        context.getResults().setStatus(cdm::kInitializationError);
        return;
      }

      // Accept video decoder (don't call set_host_context to avoid fiber conflicts)
      cdm::VideoDecoderConfig_2 video_decoder_config;'''

if old in content:
    content = content.replace(old, new)
    # Also remove set_host_context/clear_host_context from initializeVideoDecoder
    # Replace the closing part
    old_end = '''      cdm::Status status = m_cdm->InitializeVideoDecoder(video_decoder_config);

      context.getResults().setStatus(status);
      clear_host_context();
      KJ_DLOG(INFO, "exiting initializeVideoDecoder");'''
    new_end = '''      cdm::Status status = m_cdm->InitializeVideoDecoder(video_decoder_config);
      KJ_LOG(INFO, "initializeVideoDecoder: CDM returned status", status);

      context.getResults().setStatus(status);
      KJ_DLOG(INFO, "exiting initializeVideoDecoder");'''
    content = content.replace(old_end, new_end)
    open(sys.argv[1], 'w').write(content)
    print("  - Patched initializeVideoDecoder")
else:
    print("  - initializeVideoDecoder already patched or not found")
PYEOF
python3 /tmp/patch_ivd.py "$WORKER_TMP"

# Patch HostWrapper: add CDM reference + local RequestStorageId interception
cat > /tmp/patch_host.py << 'PYEOF'
import sys
content = open(sys.argv[1]).read()

# Add m_cdm member and setCdm method to HostWrapper
old_hw = '''class HostWrapper: public cdm::Host_10 {

  HostProxy::Client m_host;

public:'''

new_hw = '''class HostWrapper: public cdm::Host_10 {

  HostProxy::Client m_host;
  cdm::ContentDecryptionModule_11* m_cdm = nullptr;

public:

  void setCdm(cdm::ContentDecryptionModule_11* cdm) { m_cdm = cdm; }'''

if old_hw in content:
    content = content.replace(old_hw, new_hw)
    print("  - Added CDM reference to HostWrapper")
else:
    print("  - HostWrapper CDM reference already present or not found")

# Replace RequestStorageId with local interception
old_rsi = '''  void RequestStorageId(uint32_t version) override {
    KJ_DLOG(INFO, "RequestStorageId");
    auto request = m_host.requestStorageIdRequest();
    request.setVersion(version);
    auto response = request.send().wait(*host_ctx.scope);
    KJ_DLOG(INFO, "exiting RequestStorageId");
  }'''

new_rsi = '''  void RequestStorageId(uint32_t version) override {
    KJ_LOG(INFO, "RequestStorageId: intercepting locally", version);
    // Generate 32-byte storage ID from /etc/machine-id by XOR-folding,
    // then call CDM::OnStorageId directly (no RPC to browser).
    uint8_t storage_id[32] = {};
    FILE* f = fopen("/etc/machine-id", "r");
    if (f) {
      char line[256] = {};
      if (fgets(line, sizeof(line), f)) {
        size_t len = strlen(line);
        while (len > 0 && (line[len-1] == '\\n' || line[len-1] == '\\r')) line[--len] = 0;
        for (size_t i = 0; i < len; i++) {
          storage_id[i % 32] ^= (uint8_t)line[i];
        }
      }
      fclose(f);
    } else {
      KJ_LOG(WARNING, "Could not open /etc/machine-id, using zeros for storage ID");
    }
    KJ_ASSERT(m_cdm != nullptr);
    m_cdm->OnStorageId(version, storage_id, 32);
    KJ_LOG(INFO, "exiting RequestStorageId");
  }'''

if old_rsi in content:
    content = content.replace(old_rsi, new_rsi)
    print("  - Patched RequestStorageId: local interception")
else:
    print("  - RequestStorageId already patched or not found")

# Patch createCdmInstance to call setCdm after CDM creation
old_cci = '''      //TODO: somebody is supposed to dispose of the host object
      void* host = reinterpret_cast<void*>(new HostWrapper(kj::mv(host_proxy)));'''

new_cci = '''      //TODO: somebody is supposed to dispose of the host object
      auto* host_wrapper = new HostWrapper(kj::mv(host_proxy));
      void* host = reinterpret_cast<void*>(host_wrapper);'''

if old_cci in content:
    content = content.replace(old_cci, new_cci)
    print("  - Patched createCdmInstance: HostWrapper variable")
else:
    print("  - createCdmInstance HostWrapper already patched or not found")

old_post = '''      KJ_LOG(INFO, "create_cdm_inst_func returned", cdm);
      KJ_ASSERT(cdm != nullptr);

      context.getResults().setCdmProxy'''

new_post = '''      KJ_LOG(INFO, "create_cdm_inst_func returned", cdm);
      KJ_ASSERT(cdm != nullptr);

      // Give the host a reference to the CDM for local RequestStorageId interception
      host_wrapper->setCdm(reinterpret_cast<cdm::ContentDecryptionModule_11*>(cdm));

      context.getResults().setCdmProxy'''

if old_post in content:
    content = content.replace(old_post, new_post)
    print("  - Patched createCdmInstance: setCdm call")
else:
    print("  - createCdmInstance setCdm already patched or not found")

open(sys.argv[1], 'w').write(content)
PYEOF
python3 /tmp/patch_host.py "$WORKER_TMP"

# ============================================================================
# 3. Patch lib.cpp
# ============================================================================
info "Patching lib.cpp..."

LIB_SRC="$WORK_SRC/src/lib.cpp"
LIB_TMP=$(mktemp /tmp/lib.cpp.XXXXXX)
cp "$LIB_SRC" "$LIB_TMP"

cat > /tmp/patch_lib.py << 'PYEOF'
import sys
content = open(sys.argv[1]).read()

# Add WaitDepthGuard before class CdmWrapper
old_cw = 'class CdmWrapper: public cdm::ContentDecryptionModule_11 {'
new_cw = '''// Re-entrancy guard for nested wait() calls.
// FileIO callbacks may fire during another CDM operation. If we do wait()
// inside an already-waiting scope, it crashes. When nested, use detach().
static thread_local int g_wait_depth = 0;
struct WaitDepthGuard {
  WaitDepthGuard() { ++g_wait_depth; }
  ~WaitDepthGuard() { --g_wait_depth; }
};

class CdmWrapper: public cdm::ContentDecryptionModule_11 {'''

if 'g_wait_depth' not in content:
    content = content.replace(old_cw, new_cw)
    print("  - Added WaitDepthGuard")
else:
    print("  - WaitDepthGuard already present")

# Add WaitDepthGuard to CdmWrapper methods that do wait()
methods_to_guard = [
    'void Initialize(bool allow_distinctive_identifier',
    'void GetStatusForPolicy(uint32_t promise_id',
    'void SetServerCertificate(uint32_t promise_id',
    'void UpdateSession(uint32_t promise_id',
    'void CloseSession(uint32_t promise_id',
    'void TimerExpired(void* context)',
    'cdm::Status Decrypt(const cdm::InputBuffer_2&',
    'cdm::Status InitializeVideoDecoder(const cdm::VideoDecoderConfig_2&',
    'cdm::Status DecryptAndDecodeFrame(const cdm::InputBuffer_2&',
]

for method_sig in methods_to_guard:
    # Find the method and add WaitDepthGuard after the opening line
    idx = content.find(method_sig)
    if idx == -1:
        continue
    # Find the next KJ_DLOG or KJ_ASSERT after this method
    search_start = content.find('{', idx)
    if search_start == -1:
        continue
    next_line_start = content.find('\n', search_start) + 1
    # Check if WaitDepthGuard is already there
    next_chunk = content[next_line_start:next_line_start+100]
    if 'WaitDepthGuard' not in next_chunk:
        content = content[:next_line_start] + '    WaitDepthGuard guard;\n' + content[next_line_start:]

# Also add guard to CreateSessionAndGenerateRequest
idx = content.find('CreateSessionAndGenerateRequest(')
if idx != -1:
    # Find the line with KJ_DLOG after it
    dlog_pos = content.find('KJ_DLOG(INFO, "CreateSessionAndGenerateRequest"', idx)
    if dlog_pos != -1:
        line_start = content.rfind('\n', 0, dlog_pos) + 1
        chunk = content[line_start:line_start+100]
        if 'WaitDepthGuard' not in chunk:
            content = content[:line_start] + '    WaitDepthGuard guard;\n' + content[line_start:]

# Make OnOpenComplete/OnReadComplete/OnWriteComplete conditional
for cb_name in ['OnOpenComplete', 'OnReadComplete', 'OnWriteComplete']:
    old_wait = f'request.send().wait(io.waitScope);\n    KJ_DLOG(INFO, "exiting {cb_name}");'
    new_wait = f'''if (g_wait_depth > 0) {{
      request.send().detach([](kj::Exception&&){{}});
    }} else {{
      request.send().wait(io.waitScope);
    }}
    KJ_DLOG(INFO, "exiting {cb_name}");'''
    if old_wait in content:
        content = content.replace(old_wait, new_wait)

# Make OnStorageId always use detach (called from event loop)
old_osi_wait = '''request.send().wait(m_io.waitScope);
    KJ_DLOG(INFO, "exiting OnStorageId");'''
new_osi_wait = '''// Always detach: called as synchronous callback from event loop
    request.send().detach([](kj::Exception&&){});
    KJ_DLOG(INFO, "exiting OnStorageId");'''
if old_osi_wait in content:
    content = content.replace(old_osi_wait, new_osi_wait)
    print("  - Patched OnStorageId: always detach")

# Make OnQueryOutputProtectionStatus conditional
old_oqop = '''request.send().wait(m_io.waitScope);
    KJ_DLOG(INFO, "exiting OnQueryOutputProtectionStatus");'''
new_oqop = '''if (g_wait_depth > 0) {
      request.send().detach([](kj::Exception&&){});
    } else {
      request.send().wait(m_io.waitScope);
    }
    KJ_DLOG(INFO, "exiting OnQueryOutputProtectionStatus");'''
if old_oqop in content:
    content = content.replace(old_oqop, new_oqop)

open(sys.argv[1], 'w').write(content)
print("  - Patched FileIO callbacks and CdmWrapper methods")
PYEOF
python3 /tmp/patch_lib.py "$LIB_TMP"

# ============================================================================
# 4. Build and install
# ============================================================================
info "Copying patched sources..."
sudo cp "$WORKER_TMP" "$WORKER_SRC"
sudo cp "$LIB_TMP" "$LIB_SRC"

info "Building fcdm-fbsd.so and fcdm-worker..."
NCPU=$(sysctl -n hw.ncpu)
sudo sh -c "cd '$WORK_SRC' && rm -f build/fcdm-fbsd.so build/fcdm-worker && make fcdm MAKE_JOBS_NUMBER=$NCPU 2>&1"

info "Installing patched binaries..."
sudo cp "$WORK_SRC/build/fcdm-fbsd.so" "$FCDM_FBSD_SO"
sudo cp "$WORK_SRC/build/fcdm-worker" "$FCDM_WORKER"
sudo chmod a+x "$FCDM_WORKER"

# Clean up temp files
rm -f "$WORKER_TMP" "$LIB_TMP" /tmp/patch_*.py

# ============================================================================
# 5. Find Firefox profile
# ============================================================================
info "Detecting active Firefox profile..."

PROFILES_INI="$USER_HOME/.mozilla/firefox/profiles.ini"
[ -f "$PROFILES_INI" ] || error "Firefox profiles.ini not found. Launch Firefox at least once first."

# Find the default-release profile path
PROFILE_PATH=""
current_section=""
while IFS= read -r line; do
    case "$line" in
        \[Profile*\]) current_section="$line" ;;
        Path=*) path_val="${line#Path=}" ;;
        Name=default-release*) PROFILE_PATH="$path_val" ;;
    esac
done < "$PROFILES_INI"

if [ -z "$PROFILE_PATH" ]; then
    # Fallback: find profile with Install section Default
    PROFILE_PATH=$(awk -F= '/^\[Install/{inst=1} inst && /^Default=/{print $2; exit}' "$PROFILES_INI")
fi

[ -n "$PROFILE_PATH" ] || error "Could not detect Firefox profile. Set PROFILE_PATH manually."

PROFILE_DIR="$USER_HOME/.mozilla/firefox/$PROFILE_PATH"
[ -d "$PROFILE_DIR" ] || error "Profile directory not found: $PROFILE_DIR"
info "Using profile: $PROFILE_PATH"

# ============================================================================
# 6. Configure Firefox GMP CDM
# ============================================================================
info "Setting up Widevine CDM in Firefox profile..."

GMP_DIR="$PROFILE_DIR/gmp-widevinecdm/openwv"
mkdir -p "$GMP_DIR"

# Symlink the shim as CDM library
ln -sf "$FCDM_FBSD_SO" "$GMP_DIR/libwidevinecdm.so"

# Create manifest.json
cat > "$GMP_DIR/manifest.json" << MANIFEST
{
  "manifest_version": 2,
  "name": "WidevineCdm",
  "version": "$CDM_VERSION",
  "x-cdm-module-versions": "4",
  "x-cdm-interface-versions": "10",
  "x-cdm-host-versions": "10",
  "x-cdm-codecs": "vp8,vp9.0,avc1,av01",
  "x-cdm-persistent-license-support": true,
  "x-cdm-supported-encryption-schemes": ["cenc", "cbcs"]
}
MANIFEST

info "Created GMP manifest ($CDM_VERSION)"

# ============================================================================
# 7. Create user.js
# ============================================================================
info "Creating user.js with EME/codec preferences..."

# Back up existing user.js
[ -f "$PROFILE_DIR/user.js" ] && cp "$PROFILE_DIR/user.js" "$PROFILE_DIR/user.js.bak.$(date +%s)"

cat > "$PROFILE_DIR/user.js" << 'USERJS'
// === EME / Widevine DRM ===
user_pref("media.eme.enabled", true);
user_pref("media.gmp-widevinecdm.enabled", true);
user_pref("media.gmp-widevinecdm.visible", true);
user_pref("media.gmp-widevinecdm.autoupdate", false);
user_pref("media.gmp-widevinecdm.version", "openwv");
user_pref("media.gmp.decoder.enabled", true);

// === Codec / Decoder ===
user_pref("media.rdd-process.enabled", true);
user_pref("media.ffmpeg.enabled", true);
user_pref("media.ffmpeg.vaapi.enabled", true);
user_pref("media.mp4.enabled", true);
// KEY FIX: Load FFmpeg in content process so MP4Decoder::IsSupportedType
// returns true for "video/mp4; codecs=avc1.640028" during EME capability check
user_pref("media.allow_audio_non_utility", true);

// === EME video decode ===
user_pref("media.eme.chromium-api.video-enabled", true);

// === Sandbox (relax for CDM) ===
user_pref("security.sandbox.content.level", 0);
USERJS

# ============================================================================
# 8. Create launch script
# ============================================================================
info "Creating launch script..."

PROFILE_NAME=$(awk -F= "/Path=$PROFILE_PATH/{found=1} found && /^Name=/{print substr(\$0,6); exit}" "$PROFILES_INI")
[ -z "$PROFILE_NAME" ] && PROFILE_NAME="default-release"

cat > "$LAUNCH_SCRIPT" << LAUNCH
#!/bin/sh
# Launch Firefox with foreign-cdm Widevine support for Netflix

# foreign-cdm environment
export FCDM_BINDIR_PATH=/usr/local/libexec
export FCDM_CDM_SO_PATH=$CDM_SO

# Verbose fcdm logging (comment out to reduce noise)
# export FCDM_LOG_INFO=1

# Firefox EME/GMP debug logging (uncomment for troubleshooting)
# export MOZ_LOG="GMP:5,EME:5,CDMProxy:5,MediaDRM:5,Widevine:5"

# Log file
LOG="/tmp/firefox-fcdm-\$(date +%Y%m%d-%H%M%S).log"

firefox -P "$PROFILE_NAME" "\$@" >"\${LOG}" 2>&1
LAUNCH

chmod +x "$LAUNCH_SCRIPT"

# ============================================================================
# 9. Create desktop file
# ============================================================================
info "Creating desktop file..."

cat > "$DESKTOP_FILE" << DESKTOP
[Desktop Entry]
Version=1.0
Name=Firefox (Widevine DRM)
Name[it]=Firefox (Widevine DRM)
Comment=Firefox with Widevine DRM support for Netflix
Comment[it]=Firefox con supporto Widevine DRM per Netflix
GenericName=Web Browser
Exec=$LAUNCH_SCRIPT %U
Terminal=false
Type=Application
Icon=firefox
Categories=GNOME;GTK;Network;WebBrowser;
MimeType=text/html;text/xml;application/xhtml+xml;application/xml;application/rss+xml;application/rdf+xml;image/gif;image/jpeg;image/png;x-scheme-handler/http;x-scheme-handler/https;
StartupNotify=true
Actions=NewWindow;NewPrivateWindow;

[Desktop Action NewWindow]
Name=Open a New Window
Exec=$LAUNCH_SCRIPT -new-window

[Desktop Action NewPrivateWindow]
Name=Open a New Private Window
Exec=$LAUNCH_SCRIPT -private-window
DESKTOP

# Install desktop file
mkdir -p "$USER_HOME/.local/share/applications"
cp "$DESKTOP_FILE" "$USER_HOME/.local/share/applications/firefox-fcdm.desktop"

# ============================================================================
# Done!
# ============================================================================
echo ""
info "============================================"
info "  Netflix on Firefox is ready!"
info "============================================"
echo ""
echo "  Launch script:  $LAUNCH_SCRIPT"
echo "  Desktop file:   $DESKTOP_FILE"
echo "  Firefox profile: $PROFILE_PATH"
echo "  CDM version:    $CDM_VERSION"
echo ""
echo "  To test: close Firefox, then run:"
echo "    $LAUNCH_SCRIPT"
echo "  and open https://www.netflix.com"
echo ""
warn "Note: if Chrome also uses foreign-cdm and you want it to use"
warn "HW decode (VAAPI), set FCDM_REJECT_VIDEO_DECODER=1 in its"
warn "launch script. Firefox uses CDM software decode by default."
echo ""
