#====================================================================================================
# START - Testing Protocol - DO NOT EDIT OR REMOVE THIS SECTION
#====================================================================================================

# THIS SECTION CONTAINS CRITICAL TESTING INSTRUCTIONS FOR BOTH AGENTS
# BOTH MAIN_AGENT AND TESTING_AGENT MUST PRESERVE THIS ENTIRE BLOCK

# Communication Protocol:
# If the `testing_agent` is available, main agent should delegate all testing tasks to it.
#
# You have access to a file called `test_result.md`. This file contains the complete testing state
# and history, and is the primary means of communication between main and the testing agent.
#
# Main and testing agents must follow this exact format to maintain testing data. 
# The testing data must be entered in yaml format Below is the data structure:
# 
## user_problem_statement: {problem_statement}
## backend:
##   - task: "Task name"
##     implemented: true
##     working: true  # or false or "NA"
##     file: "file_path.py"
##     stuck_count: 0
##     priority: "high"  # or "medium" or "low"
##     needs_retesting: false
##     status_history:
##         -working: true  # or false or "NA"
##         -agent: "main"  # or "testing" or "user"
##         -comment: "Detailed comment about status"
##
## frontend:
##   - task: "Task name"
##     implemented: true
##     working: true  # or false or "NA"
##     file: "file_path.js"
##     stuck_count: 0
##     priority: "high"  # or "medium" or "low"
##     needs_retesting: false
##     status_history:
##         -working: true  # or false or "NA"
##         -agent: "main"  # or "testing" or "user"
##         -comment: "Detailed comment about status"
##
## metadata:
##   created_by: "main_agent"
##   version: "1.0"
##   test_sequence: 0
##   run_ui: false
##
## test_plan:
##   current_focus:
##     - "Task name 1"
##     - "Task name 2"
##   stuck_tasks:
##     - "Task name with persistent issues"
##   test_all: false
##   test_priority: "high_first"  # or "sequential" or "stuck_first"
##
## agent_communication:
##     -agent: "main"  # or "testing" or "user"
##     -message: "Communication message between agents"

# Protocol Guidelines for Main agent
#
# 1. Update Test Result File Before Testing:
#    - Main agent must always update the `test_result.md` file before calling the testing agent
#    - Add implementation details to the status_history
#    - Set `needs_retesting` to true for tasks that need testing
#    - Update the `test_plan` section to guide testing priorities
#    - Add a message to `agent_communication` explaining what you've done
#
# 2. Incorporate User Feedback:
#    - When a user provides feedback that something is or isn't working, add this information to the relevant task's status_history
#    - Update the working status based on user feedback
#    - If a user reports an issue with a task that was marked as working, increment the stuck_count
#    - Whenever user reports issue in the app, if we have testing agent and task_result.md file so find the appropriate task for that and append in status_history of that task to contain the user concern and problem as well 
#
# 3. Track Stuck Tasks:
#    - Monitor which tasks have high stuck_count values or where you are fixing same issue again and again, analyze that when you read task_result.md
#    - For persistent issues, use websearch tool to find solutions
#    - Pay special attention to tasks in the stuck_tasks list
#    - When you fix an issue with a stuck task, don't reset the stuck_count until the testing agent confirms it's working
#
# 4. Provide Context to Testing Agent:
#    - When calling the testing agent, provide clear instructions about:
#      - Which tasks need testing (reference the test_plan)
#      - Any authentication details or configuration needed
#      - Specific test scenarios to focus on
#      - Any known issues or edge cases to verify
#
# 5. Call the testing agent with specific instructions referring to test_result.md
#
# IMPORTANT: Main agent must ALWAYS update test_result.md BEFORE calling the testing agent, as it relies on this file to understand what to test next.

#====================================================================================================
# END - Testing Protocol - DO NOT EDIT OR REMOVE THIS SECTION
#====================================================================================================



#====================================================================================================
# Testing Data - Main Agent and testing sub agent both should log testing data below this section
#====================================================================================================

user_problem_statement: |
  Imported Nadiplayer-170credit GitHub repo into Emergent workspace. User wants:
  1. Update REACT_APP_BACKEND_URL → https://prmtly.com (production backend)
  2. Add Firebase google-services.json to Android project (Nadiplayer project, package om.nadi.player)
  3. AdMob: keep new App ID `ca-app-pub-6960839907465160~7767874649` and add a NEW
     "Rewarded" ad-unit field (`ca-app-pub-6960839907465160/7452490933`) end-to-end
     (backend settings, /api/public/ad-config, admin UI, frontend lib). Other slots
     (banner / interstitial / native) stay admin-editable, no APK rebuild needed.
  4. Fix silent crash on Asus ROG 8 Pro / Android 14-15 that happens when the
     "Allow notifications" dialog appears or right after tapping Allow.
     Must NOT break Warm Decoder / Fast-Zapping logic shipped in v2.0.

backend:
  - task: "Add ads_rewarded_id to settings model + default + backfill"
    implemented: true
    working: true
    file: "backend/routes/admin_users.py"
    stuck_count: 0
    priority: "high"
    needs_retesting: false
    status_history:
        - working: "NA"
          agent: "main"
          comment: "Added ads_rewarded_id to SettingsUpdate model, default settings doc (ca-app-pub-6960839907465160/7452490933), and backfill defaults. Persists via PUT /api/admin/settings."
        - working: true
          agent: "testing"
          comment: "✅ VERIFIED: ads_rewarded_id field successfully added to settings. GET /api/admin/settings returns ads_rewarded_id field with default value 'ca-app-pub-6960839907465160/7452490933'. PUT /api/admin/settings successfully updates and persists ads_rewarded_id. Backfill logic working correctly for legacy docs. All CRUD operations tested and working."

  - task: "Expose rewarded_id in public ad-config + universal TEST id when testing"
    implemented: true
    working: true
    file: "backend/routes/public.py"
    stuck_count: 0
    priority: "high"
    needs_retesting: false
    status_history:
        - working: "NA"
          agent: "main"
          comment: "GET /api/public/ad-config now returns rewarded_id. When testing_mode=true, returns Google's universal test rewarded unit ca-app-pub-3940256099942544/5224354917 to avoid touching the live account."
        - working: true
          agent: "testing"
          comment: "✅ VERIFIED: GET /api/public/ad-config correctly returns rewarded_id field. When ads_testing_mode=true, returns Google's test unit 'ca-app-pub-3940256099942544/5224354917'. When ads_testing_mode=false, returns real unit 'ca-app-pub-6960839907465160/7452490933'. All other test units (banner, interstitial, native) also correctly switch between test and real IDs based on testing mode. app_id correctly set to 'ca-app-pub-6960839907465160~7767874649'."


  - task: "Add push_enabled server kill-switch to settings + app-info"
    implemented: true
    working: true
    file: "backend/routes/admin_users.py, backend/routes/public.py"
    stuck_count: 0
    priority: "high"
    needs_retesting: false
    status_history:
        - working: "NA"
          agent: "main"
          comment: "Added push_enabled field to SettingsUpdate model (line 135), default settings (line 182), and backfill defaults (line 228). Exposed in /api/public/app-info under flags.push_enabled (line 100). Defaults to FALSE so APKs built before google-services.json was bundled won't crash."
        - working: true
          agent: "testing"
          comment: |
            ✅ VERIFIED: All 8 test scenarios PASSED
            1. ✅ GET /api/public/app-info returns flags.push_enabled field, defaults to false
            2. ✅ POST /api/auth/login with admin/admin123 works, returns JWT token
            3. ✅ GET /api/admin/settings returns push_enabled field with value false
            4. ✅ PUT /api/admin/settings with {"push_enabled": true} returns 200 and persists
            5. ✅ GET /api/public/app-info now shows flags.push_enabled=true (change reflected)
            6. ✅ PUT /api/admin/settings with {"push_enabled": false} returns 200 and persists
            7. ✅ GET /api/public/app-info now shows flags.push_enabled=false (system left safe)
            8. ✅ REGRESSION: GET /api/public/ad-config still returns rewarded_id field (no regression)
            
            Test file: /app/test_push_enabled.py
            All functionality working correctly. The kill-switch is properly implemented with safe defaults.

frontend:
  - task: "Fix native crash on back from Live/Movie/Series + back-from-deep-route exits app (v2.1.2)"
    implemented: true
    working: "NA"
    file: "frontend/android/app/src/main/java/com/nadi/player/nativeplayer/PlayerActivity.java"
    stuck_count: 0
    priority: "high"
    needs_retesting: false
    status_history:
        - working: "NA"
          agent: "main"
          comment: |
            TWO BUGS, ONE REPORT:

            ── A) NATIVE CRASH on back from PlayerActivity (Android 14/15)
            Root cause: the Media3 Player.Listener was an anonymous inner
            class registered inline on the MediaController, and NEVER
            removed on exit. After back press → finish(), the Media3
            session in PlaybackService kept firing
            onPlaybackStateChanged() / onPlayerError() callbacks into a
            destroyed Activity, which tried to touch dead views and
            blew up with NPE → native crash → Android system showed
            "Something went wrong with Nadiplayer / Clear cache?".

            Fix:
              • Player.Listener is now a stored field (`playerListener`).
              • New `releaseControllerSafely()` helper removes the
                listener, detaches the PlayerView, and nulls out the
                controller. Each step is its own try/catch so partial
                failure can never propagate.
              • Called from BOTH `exitPlayer()` AND `onDestroy()` —
                idempotent, safe.
              • Every callback method is wrapped in try/catch as a
                belt-and-braces guard for any callback that fires
                AFTER releaseControllerSafely() but BEFORE the future
                is fully released.

            CRITICAL: this fix does NOT touch the Warm Decoder or
            Fast-Zapping path. PlaybackService is killed by the same
            stopService() call that already existed — we only stop
            holding callbacks that target a dead Activity.

            ── B) BACK from Live/Movie/Series exits the app entirely
            (file: frontend/src/components/BackButtonHandler.tsx)
            Root cause: handleBack() exited the app whenever Capacitor
            reported canGoBack=false. On Android 14/15 this fires
            *frequently* when the WebView is restored from saved state
            after a process death, even though the user is clearly
            deep inside the app.

            Fix:
              • Removed `/admin` from the root-paths list — back from
                admin now returns to dashboard, not exits.
              • `handleBack` only exits when AT a root path. Anywhere
                else it pops history (if available) or navigates to
                `/` as a safe fallback — NEVER exits.

  - task: "PHP backend (cPanel): add ads_rewarded_id + push_enabled (admin save/load + public/ad-config + public/app-info)"
    implemented: true
    working: "NA"
    file: "cpanel_build_php/nadiplayer/api/routes/admin.php"
    stuck_count: 0
    priority: "high"
    needs_retesting: false
    status_history:
        - working: "NA"
          agent: "main"
          comment: |
            The user's prmtly.com runs the PHP backend, not the FastAPI one.
            Admin saves to it were silently dropping ads_rewarded_id
            (and push_enabled didn't exist), so the website admin panel
            never showed the field and the APK save reverted on reload.

            Patched cpanel_build_php/nadiplayer/api/routes/admin.php:
              • Defaults block: added ads_rewarded_id + push_enabled
              • Writable string list: added ads_rewarded_id
              • Bool toggle list: added push_enabled
            Patched cpanel_build_php/nadiplayer/api/routes/public.php:
              • /api/public/ad-config now returns rewarded_id
                (with Google's TEST id when testing_mode=true)
              • /api/public/app-info now returns flags.push_enabled
            Synced the same patches into release-bundle/nadiplayer/.

  - task: "GitHub Actions workflow that builds a ready-to-upload cPanel zip"
    implemented: true
    working: "NA"
    file: ".github/workflows/cpanel-deploy.yml"
    stuck_count: 0
    priority: "medium"
    needs_retesting: false
    status_history:
        - working: "NA"
          agent: "main"
          comment: |
            New workflow `cpanel-deploy.yml`. On every push to main /
            workflow_dispatch:
              1. Builds the React bundle with VITE_BACKEND_URL=prmtly.com
              2. Assembles cpanel_deploy/ = cpanel_build_php/ skeleton +
                 freshly-built React assets (overlaid)
              3. Strips firebase-service-account.json before packaging
              4. Zips → nadiplayer-cpanel-deploy.zip (retention 5 days)
              5. Uploads as artifact `nadiplayer-cpanel-deploy`
            Includes a DEPLOY_NOTES.txt inside the zip with install steps.

  - task: "Add server-side push_enabled kill-switch to stop the post-login crash on installed APKs"
    implemented: true
    working: "NA"
    file: "frontend/src/hooks/usePushNotifications.ts"
    stuck_count: 0
    priority: "high"
    needs_retesting: false
    status_history:
        - working: "NA"
          agent: "main"
          comment: |
            VIDEO ANALYSIS REVEALED THE ROOT CAUSE: silent crash ~2-3 s after
            successful login on Asus ROG 8 Pro / Android 14-15. That timing
            matches the OLD 3 s push deferral timer in the installed APK,
            and the APK was built BEFORE google-services.json was bundled,
            so `PushNotifications.register()` was crashing inside Firebase
            Messaging JNI init.

            FIX: added a server-side kill-switch flag (`push_enabled`,
            default **false**) read from /api/public/app-info. Before
            calling ANY native FCM API, the JS now fetches app-info and
            bails when push_enabled !== true. Fails CLOSED on network
            error so a stale APK can never be tricked into crashing.

            Combined with the previous changes (5 s + requestIdleCallback
            defer, listeners attached before register(), per-call
            try/catch wrappers, denied-state short-circuit), this is the
            full v2.1.0 hot-fix. Warm Decoder + Fast-Zapping untouched.

            DEPLOYMENT NOTE: the user must rebuild + reinstall the APK
            for THIS device fix to land (JS bundle lives inside the APK).
            After install, the kill-switch is OFF by default → no FCM,
            no crash. Admin flips it ON from the panel once everyone is
            on the new APK.

  - task: "Add Push Notifications admin toggle"
    implemented: true
    working: "NA"
    file: "frontend/src/pages/Admin.tsx"
    stuck_count: 0
    priority: "medium"
    needs_retesting: false
    status_history:
        - working: "NA"
          agent: "main"
          comment: "New amber-bordered toggle inside the Player Settings accordion (data-testid='toggle-push-enabled'). Saves via PUT /api/admin/settings → push_enabled. Default OFF with a warning copy explaining when to turn it on."

  - task: "Add ads_rewarded_id to Settings type for admin API"
    implemented: true
    working: "NA"
    file: "frontend/src/lib/nadiAuth.ts"
    stuck_count: 0
    priority: "medium"
    needs_retesting: false
    status_history:
        - working: "NA"
          agent: "main"
          comment: "Added adsRewardedId state, useEffect sync, save payload entry, and the visible <Input label='Rewarded Ad Unit ID' data-testid='set-ads-rewarded-id' />. Settings type in lib/nadiAuth.ts updated with ads_rewarded_id?: string."

  - task: "showRewarded() in admob lib + rewarded_id in AdConfig type"
    implemented: true
    working: "NA"
    file: "frontend/src/lib/admob.ts"
    stuck_count: 0
    priority: "medium"
    needs_retesting: false
    status_history:
        - working: "NA"
          agent: "main"
          comment: "Imported RewardAdOptions + AdMobRewardItem. Added rewarded_id to AdConfig. Added showRewarded(apiBase?) that prepares + shows the rewarded video and falls back to the interstitial unit when the rewarded slot is empty so admin can configure just one id."

  - task: "Fix silent crash on Android 14/15 when 'Allow notifications' dialog appears"
    implemented: true
    working: "NA"
    file: "frontend/src/hooks/usePushNotifications.ts"
    stuck_count: 0
    priority: "high"
    needs_retesting: false
    status_history:
        - working: "NA"
          agent: "main"
          comment: |
            Rewrote the deferral logic:
              • Wait for document.readyState === 'complete' AND a 5 s timer AND requestIdleCallback (with hard 8 s ceiling).
              • Attach ALL listeners (registration, registrationError, pushNotificationReceived, pushNotificationActionPerformed) BEFORE calling register() — fixes JNI-callback-into-null on Android 15.
              • Bail early when permission state is 'denied' so we never re-prompt and never race the player.
              • Every JNI call wrapped in its own try/catch; the whole hook can never bubble an exception into React.
            Untouched: ExoPlayer, channel preview decoder, AdMob init paths — Warm Decoder / Fast-Zapping intact.

  - task: "Update REACT_APP_BACKEND_URL to production https://prmtly.com"
    implemented: true
    working: "NA"
    file: "frontend/.env"
    stuck_count: 0
    priority: "high"
    needs_retesting: false
    status_history:
        - working: "NA"
          agent: "main"
          comment: "Webview now points at production backend https://prmtly.com. Note: this means localhost preview can't authenticate against the local FastAPI; production must deploy the backend changes (ads_rewarded_id) for full parity."

  - task: "Drop google-services.json into Android project for FCM"
    implemented: true
    working: "NA"
    file: "frontend/android/app/google-services.json"
    stuck_count: 0
    priority: "high"
    needs_retesting: false
    status_history:
        - working: "NA"
          agent: "main"
          comment: "Placed firebase config (project_id=nadiplayer, package=om.nadi.player) in frontend/android/app/. Gradle already wires com.google.gms.google-services + firebase-messaging — APK rebuild will pick it up."

metadata:
  created_by: "main_agent"
  version: "2.2.0"
  test_sequence: 2
  run_ui: false

test_plan:
  current_focus:
    - "Add push_enabled server kill-switch to settings + app-info"
  stuck_tasks: []
  test_all: false
  test_priority: "high_first"

agent_communication:
    - agent: "main"
      message: |
        Backend changes (ads_rewarded_id + /api/public/ad-config exposing rewarded_id) need verification:
          1. GET /api/public/ad-config must return a `rewarded_id` field
             - When testing_mode=true → "ca-app-pub-3940256099942544/5224354917"
             - When testing_mode=false → admin-saved value (or empty string)
          2. PUT /api/admin/settings with `ads_rewarded_id: "ca-app-pub-6960839907465160/7452490933"` must persist
          3. GET /api/admin/settings must echo back the saved ads_rewarded_id
          4. Admin auth via POST /api/login with admin/admin123 (from test_credentials.md)
          5. Make sure no regression on /api/public/ad-config when settings doc is fresh (backfill should inject the new field).
    - agent: "testing"
      message: |
        ✅ ALL BACKEND TESTS PASSED (7/7)
        
        Tested all scenarios from review request:
        1. ✅ GET /api/public/ad-config (public, no auth) - Returns all required keys including rewarded_id
        2. ✅ Testing mode verification - When ads_testing_mode=true, rewarded_id returns Google's test unit (ca-app-pub-3940256099942544/5224354917)
        3. ✅ app_id verification - Correctly set to ca-app-pub-6960839907465160~7767874649
        4. ✅ Admin login - POST /api/auth/login with admin/admin123 works, returns JWT token
        5. ✅ GET /api/admin/settings - Returns ads_rewarded_id field with correct default value
        6. ✅ PUT /api/admin/settings - Successfully updates ads_rewarded_id and ads_testing_mode, changes persist
        7. ✅ Real ID verification - After disabling testing mode, ad-config returns real rewarded_id (ca-app-pub-6960839907465160/7452490933)
        8. ✅ Reset to testing mode - Successfully reset ads_testing_mode to true
        9. ✅ Regression checks - GET /api/public/app-info and GET /api/public/playback-mode both return 200 with expected structure
        
        Minor fix applied: Added missing JWT_SECRET to backend/.env (was causing login failures). This is a configuration fix, not a code change.
        
        All rewarded ad backend functionality is working correctly. Ready for production deployment.
    - agent: "main"
      message: |
        New push_enabled server kill-switch needs verification. Admin creds in /app/memory/test_credentials.md (admin / admin123).
        Test scenarios:
          1. GET /api/public/app-info (public, no auth) — confirm response shape contains flags.push_enabled and defaults to false
          2. POST /api/auth/login with admin/admin123 → capture JWT
          3. GET /api/admin/settings (bearer) — confirm response contains push_enabled field, value should be false
          4. PUT /api/admin/settings with body {"push_enabled": true} → must return 200 and persist
          5. Re-GET /api/public/app-info → flags.push_enabled MUST now be true
          6. PUT /api/admin/settings with body {"push_enabled": false} → confirm it goes back to false
          7. Re-GET /api/public/app-info → flags.push_enabled MUST be false again
          8. Regression: confirm GET /api/public/ad-config still returns rewarded_id field
    - agent: "testing"
      message: |
        ✅ ALL PUSH_ENABLED TESTS PASSED (8/8)
        
        Comprehensive testing completed for push_enabled server kill-switch:
        
        Test Results:
        1. ✅ GET /api/public/app-info - flags.push_enabled field present and defaults to false
        2. ✅ POST /api/auth/login - Admin authentication successful with JWT token
        3. ✅ GET /api/admin/settings - push_enabled field present with value false
        4. ✅ PUT /api/admin/settings {"push_enabled": true} - Successfully updated and persisted
        5. ✅ GET /api/public/app-info - flags.push_enabled correctly reflects true
        6. ✅ PUT /api/admin/settings {"push_enabled": false} - Successfully reset to false
        7. ✅ GET /api/public/app-info - flags.push_enabled correctly reflects false (system left safe)
        8. ✅ REGRESSION CHECK - GET /api/public/ad-config still returns rewarded_id field
        
        Implementation verified:
        - push_enabled field correctly added to SettingsUpdate model (admin_users.py line 135)
        - Default value set to false in settings defaults (admin_users.py line 182)
        - Backfill logic includes push_enabled (admin_users.py line 228)
        - Exposed in /api/public/app-info under flags.push_enabled (public.py line 100)
        - Admin can toggle via PUT /api/admin/settings
        - Changes persist correctly in MongoDB
        - Public endpoint reflects changes immediately
        - No regression on existing ad-config functionality
        
        Test file: /app/test_push_enabled.py
        
        The push_enabled kill-switch is fully functional and ready for production. Safe default (false) ensures APKs built before google-services.json was added won't crash on Firebase init.

