import subprocess
import time
import traceback
import requests
import os
from appium import webdriver
from appium.options.android import UiAutomator2Options
from selenium.webdriver.common.by import By
from appium.webdriver.common.appiumby import AppiumBy
from selenium.webdriver.support.ui import WebDriverWait
from selenium.webdriver.support import expected_conditions as EC

# ==========================================
# CONFIGURATION & PARAMETERS
# ==========================================
Password_Here = "G@Udn1w@#8N8"
key = 'dreYWZN6BkiImePegTZ5et'  # Replace with your IFTTT webhook key
event = 'tbn_event'             # Replace with your IFTTT event name

feed_caramelo = True
perform_plus_caramelo = False
perform_confirm_caramelo = False
REDROID_IP = "127.0.0.1:55555"  # Defined globally for easy changes

def send_ifttt_webhook(event, key, message):
    """Send a webhook message to IFTTT."""
    url = f'https://maker.ifttt.com/trigger/{event}/with/key/{key}'
    data = {'value1': message}
    try:
        requests.post(url, json=data, timeout=10)
        print(f"Webhook sent with message: {message}")
    except Exception as e:
        print(f"Failed to transmit webhook: {e}")
    return None

def pre_launch_wake_and_start():
    """Ensure the headless canvas is awake and force start the app."""
    print("Waking up virtual display canvas...")
    
    subprocess.run("killall scrcpy", shell=True, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
    
    print("Launching live visual feed via Scrcpy on RDP display :10...")
    subprocess.Popen(
        "export DISPLAY=:10 && scrcpy -s 127.0.0.1:55555 -f --bit-rate=2M --max-fps=30", 
        shell=True, 
        stdout=subprocess.DEVNULL, 
        stderr=subprocess.DEVNULL
    )
    time.sleep(2)
    
    try:
        # 1. Connect specifically to the Redroid Docker port
        subprocess.run(f"adb connect {REDROID_IP}", shell=True, timeout=5, stdout=subprocess.DEVNULL)
        
        # 2. Execute wakeup commands specifically on Redroid using the -s flag
        subprocess.run(f"adb -s {REDROID_IP} shell svc power stayon true", shell=True, timeout=10)
        subprocess.run(f"adb -s {REDROID_IP} shell wm dismiss-keyguard", shell=True, timeout=10)

        print("Launching Petlibro via Activity Manager...")
        subprocess.run(f"adb -s {REDROID_IP} shell am start -W -n com.designlibro.petlibro/.MainActivity --receiver-foreground -f 0x10000000", shell=True, timeout=15)
        time.sleep(2)
        
    except subprocess.TimeoutExpired:
        print("CRITICAL: ADB command timed out! The Android network bridge is frozen.")
    time.sleep(2)


def force_close_app():
    """Force stops the Android app and spins down the headless session."""
    print("Force-stopping application package execution layers cleanly...")
    subprocess.run(f"adb -s {REDROID_IP} shell am force-stop com.designlibro.petlibro", shell=True)
    subprocess.run("killall scrcpy", shell=True, stderr=subprocess.DEVNULL, stdout=subprocess.DEVNULL)
    print("System optimization cleanup complete. Session closed.")

def wait_for_appium(timeout=30):
    """Prevents crash if a cron schedule triggers during a server reboot."""
    print("Checking Appium Server health...")
    start_time = time.time()
    while time.time() - start_time < timeout:
        try:
            # Ping the Appium status endpoint
            response = requests.get('http://127.0.0.1:4723/status', timeout=2)
            if response.status_code == 200:
                return True
        except requests.ConnectionError:
            time.sleep(1)
    raise Exception("Appium server is offline or unreachable!")

def start_appium_session():
    """Initialize the cloud Appium options object matching Redroid architecture."""
    options = UiAutomator2Options()
    options.platform_name = "Android"
    options.automation_name = "UiAutomator2"
    options.device_name = REDROID_IP
    options.udid = REDROID_IP
    options.app_package = "com.designlibro.petlibro"
    options.app_activity = ".MainActivity"
    options.no_reset = True
    options.ensure_webviews_have_pages = True
    options.set_capability("androidHome", "/usr/lib/android-sdk")

    # This dynamically waits for Appium before trying to connect
    wait_for_appium() 
    driver = webdriver.Remote('http://127.0.0.1:4723', options=options)
    return driver

# Pre-wake display canvas and force app execution
pre_launch_wake_and_start()

# Start the Appium UI automation driver session
driver = start_appium_session()
print("Appium session established successfully.")


# ==========================================
# LOCATORS 
# ==========================================
# Core Feeding Interface
caramelo_locator = (By.XPATH, "//android.widget.Button[@content-desc='Kitchen\nCaramelo Bona\nNext feeding:\nNo Feeding Schedule ']")
feed_now_locator = (By.XPATH, "//android.widget.ImageView[@content-desc='Feed Now']")
plus_locator = (By.XPATH, "//android.view.View[@content-desc='10 g']/android.widget.ImageView[2]") 
confirm_locator = (AppiumBy.ACCESSIBILITY_ID, "Confirm")
back_locator = (By.XPATH, "//android.widget.FrameLayout[@resource-id='android:id/content']/android.widget.FrameLayout/android.widget.FrameLayout/android.view.View/android.view.View/android.view.View/android.view.View/android.widget.ImageView[1]")

# First-Time Initialization
agree_continue_locator = (By.XPATH, "//android.widget.Button[contains(@content-desc, 'Agree And Continue')]")

try:
    # ==========================================
    # GLOBAL PRE-FLIGHT INTERCEPT
    # ==========================================
    print("Checking for hanging OS notification prompts before scanning dashboard...")
    try:
        # Quick 4-second check. Uses XPath to catch either of the two IDs Android might use!
        deny_button = WebDriverWait(driver, 4).until(
            EC.presence_of_element_located((By.XPATH, "//*[@resource-id='com.android.permissioncontroller:id/permission_deny_button' or @resource-id='com.android.permissioncontroller:id/permission_deny_and_dont_ask_again_button']"))
        )
        deny_button.click()
        print("Cleared hanging notification shield!")
        time.sleep(1)
    except Exception:
        pass # No prompt blocking the screen

    # ==========================================
    # SMART STATE CHECK
    # ==========================================
    print("Checking if we are already logged in and on the dashboard...")
    needs_full_login = False
    
    try:
        # Give the cloud up to 12 seconds to load the dashboard natively
        WebDriverWait(driver, 12).until(
            EC.presence_of_element_located(caramelo_locator)
        )
        print("BINGO! Caramelo's profile found. Skipping login initialization entirely.")
    except Exception:
        print("Caramelo not found. The app is logged out or corrupted. Initiating full reset...")
        needs_full_login = True

    # ==========================================
    # FULL LOGIN GAUNTLET (Only runs if needed)
    # ==========================================
    if needs_full_login:
        # 1. Nuke the app memory and restart it while keeping the Appium bridge alive
        # print("Wiping app memory for a clean login slate...")
        # subprocess.run("adb -s 127.0.0.1:55555 shell pm clear com.designlibro.petlibro", shell=True)
        # time.sleep(1)
        # print("Relaunching clean app state...")
        # subprocess.run("adb -s 127.0.0.1:55555 shell am start -W -n com.designlibro.petlibro/.MainActivity --receiver-foreground -f 0x10000000", shell=True)
        # time.sleep(3)

        # 2. Terms and Conditions
        try:
            print("Checking for Terms and Conditions prompt...")
            agree_btn = driver.find_elements(*agree_continue_locator)
            if agree_btn:
                element = agree_btn[0]
                
                # Get the physical dimensions of the massive element
                rect = element.rect
                
                # Calculate the exact center horizontally
                target_x = rect['x'] + (rect['width'] // 2)
                
                # Calculate the bottom edge, then move up 75 pixels to hit the button squarely
                target_y = rect['y'] + rect['height'] - 75
                
                print(f"Phantom click bypassed. Firing precision tap at X:{target_x}, Y:{target_y}...")
                
                # Execute a native Android tap at our custom coordinates
                driver.execute_script("mobile: clickGesture", {
                    "x": target_x,
                    "y": target_y
                })
                
                print("Terms and Conditions prompt handled.")
                time.sleep(2) # Bumped to 2 seconds to let the screen transition
            else:
                print("No Terms and Conditions prompt detected. Moving on...")
        except Exception:
            pass

        # 3. Notification Bypass
        try:
            print("Checking for native notification prompt...")
            deny_button = WebDriverWait(driver, 15).until(
                EC.presence_of_element_located((By.XPATH, "//*[@resource-id='com.android.permissioncontroller:id/permission_deny_button' or @resource-id='com.android.permissioncontroller:id/permission_deny_and_dont_ask_again_button']"))
            )
            deny_button.click()
            print("Handled notification prompt successfully.")
        except Exception:
            print("No notification prompt detected. Moving on...")
        
        # 4. Flutter-Adaptive Login Entry
        try:
            # --- SPLASH SCREEN BYPASS ---
            print("Checking for pre-login splash screen...")
            try:
                # Look for the initial 'Log In' button to reach the form
                splash_login = WebDriverWait(driver, 15).until(
                    EC.element_to_be_clickable((By.XPATH, "//android.widget.Button[@content-desc='Log In']"))
                )
                splash_login.click()
                print("Bypassed splash screen! Entering credential form...")
                time.sleep(2)
            except Exception:
                print("No splash screen detected. Proceeding to credentials...")
            # ----------------------------

            print("Waiting for Flutter UI to stabilize...")

# ... existing Notification Bypass code ...
            
            # 3.5 Location Selection (Roller Box)
            print("Opening Location roller box...")
            try:
                # 1. Find and click the Location field to open the roller
                location_dropdown = WebDriverWait(driver, 10).until(
                    EC.element_to_be_clickable((By.XPATH, "//android.widget.ImageView[@content-desc='Location']"))
                )
                location_dropdown.click()
                time.sleep(2) # Wait for the roller animation to finish

                print("Searching for 'United States of America'...")
                try:
                    # 2A. Try to click it directly if it is already visible on the screen
                    usa_option = WebDriverWait(driver, 4).until(
                        EC.element_to_be_clickable((By.XPATH, "//*[@content-desc='United States of America' or @text='United States of America']"))
                    )
                    usa_option.click()
                except Exception:
                    # 2B. If it is hidden down the list, force Android to scroll until it finds it
                    print("Scrolling through the roller list...")
                    usa_option = driver.find_element(
                        AppiumBy.ANDROID_UIAUTOMATOR, 
                        'new UiScrollable(new UiSelector().scrollable(true)).scrollIntoView(new UiSelector().descriptionContains("United States of America"))'
                    )
                    usa_option.click()
                
                print("Location successfully set!")
                time.sleep(1) # Brief pause before moving to the Email field
                
            except Exception as loc_err:
                print(f"Warning: Failed to set location. Error: {loc_err}")

            # ... proceed to Email field ...

            # Email
            email_field = WebDriverWait(driver, 15).until(
                EC.element_to_be_clickable((By.XPATH, "//*[@class='android.view.View' and (@text='Email' or contains(@content-desc, 'Email'))] | //android.widget.EditText"))
            )
            email_field.click()
            email_field.send_keys("alexandre.bona@gmail.com")
            
            # Password
            password_field = driver.find_element(By.XPATH, "//*[@class='android.view.View' and (@text='Password' or contains(@content-desc, 'Password'))] | //android.widget.EditText[2]")
            password_field.click()
            password_field.send_keys(Password_Here)
            driver.press_keycode(66) # Enter
            time.sleep(0.5)

            # Checkbox
            checkbox = WebDriverWait(driver, 10).until(
                EC.element_to_be_clickable((By.XPATH, "//android.widget.ImageView[@index='5' and @clickable='true']"))
            )
            checkbox.click()

            # Login Button (Submit form)
            login_button = WebDriverWait(driver, 10).until(
                EC.element_to_be_clickable((By.XPATH, "//android.widget.Button[@index='7' and @content-desc='Log In' and @clickable='true']"))
            )
            login_button.click()
            print("Login payload transmitted!")

            # 5. Post-Login Intercept Gauntlet
            print("Waiting 8 seconds for Kalay cloud sync...")
            time.sleep(8) 
            
            print("Checking for Message Center hijack...")
            try:
                WebDriverWait(driver, 5).until(
                    EC.presence_of_element_located((AppiumBy.XPATH, "//android.view.View[@content-desc='MESSAGE CENTER']"))
                )
                print("Trapped in Message Center! Clicking back arrow...")
                back_arrow = driver.find_element(AppiumBy.XPATH, "//android.widget.ImageView[@index='0' and @clickable='true']")
                back_arrow.click()
                time.sleep(3) 
            except Exception:
                print("No Message Center intercepted.")

        except Exception as login_err:
            print(f"Login routine fault: {login_err}")


    # ==========================================
    # CORE PET FEEDING PIPELINE
    # ==========================================
    # This runs whether we just logged in, or if we were already logged in!
    if feed_caramelo:
        print("Locating Caramelo's machine entry profile...")
        driver.find_element(*caramelo_locator).click()
        
        print("Waiting 2 seconds for the device page to load...")
        time.sleep(2)

        # INTERCEPT: Device-Level "Done" Tooltip
        # We only check for this here because it only spawns inside the device menu!
        print("Checking for First-Time 'Done' tooltip on the device page...")
        try:
            target = WebDriverWait(driver, 5).until(
                EC.presence_of_element_located((AppiumBy.ACCESSIBILITY_ID, "Done"))
            )
            print("Tooltip detected! Firing native click...")
            target.click()
            time.sleep(2)
        except Exception:
            try:
                target = driver.find_element(AppiumBy.ANDROID_UIAUTOMATOR, 'new UiSelector().descriptionContains("Done")')
                driver.execute_script("mobile: clickGesture", {"elementId": target.id})
                time.sleep(2)
            except Exception:
                print("No 'Done' tooltip detected. Device screen is clear.")

        # Execute Feeding
        print("Triggering instant feed canvas overlay...")
        driver.find_element(*feed_now_locator).click()
        time.sleep(2)
        
        if perform_plus_caramelo:
            print("Incrementing weight portion size (+10g)...")
            driver.find_element(*plus_locator).click()
            time.sleep(2)

        if not perform_confirm_caramelo:
            print("Aborting feeding action loop: issuing back keycode.")
            driver.press_keycode(4)
            time.sleep(2)

        if perform_confirm_caramelo:
            print("Feeding validation confirmed. Delivering treats immediately.")
            driver.find_element(*confirm_locator).click()
            time.sleep(2)

        print("Returning interface map to root layer...")
        driver.find_element(*back_locator).click()
        time.sleep(2)

except Exception as e:
    print("\n=======================================================")
    print(f"❌ CRITICAL FAULT TRIPPED: {e}")
    print("=======================================================")
    
    traceback.print_exc() 
    send_ifttt_webhook(event, key, "Feed Failed!")

    try:
        print("\nSnapping emergency triage screenshots and layout XML...")
        driver.save_screenshot('/home/ubuntu/caramelo_fault.png')
        with open('/home/ubuntu/caramelo_layout.xml', 'w', encoding='utf-8') as f:
            f.write(driver.page_source)
        print("✅ Diagnostics saved to /home/ubuntu/caramelo_fault.png and /home/ubuntu/caramelo_layout.xml")
        
        print("\n🚨 EXECUTION PAUSED FOR DEBUGGING 🚨")
        print("The script has failed, but the Appium driver is still alive.")
        print("1. Look at your scrcpy window to see where the app is stuck.")
        print("2. Open /home/ubuntu/caramelo_layout.xml in VS Code to inspect the current UI tree.")
        input("\n👉 Press [ENTER] in this terminal when you are ready to kill the app and exit...")

    except Exception as diag_err:
        print(f"Failed to capture diagnostics: {diag_err}")

finally:
    print("Safely disconnecting client driver stream links...")
    try:
        driver.quit()
    except:
        pass
    force_close_app()
