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 (Alphabet Jump & Roller)
            print("Opening Location list...")
            try:
                # 1. Find and click the Location field to open the roller/list
                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 menu animation to finish

                # 1.5. JUMP TO 'U'
                print("Clicking the 'U' index to jump down the list...")
                try:
                    # Look for the 'U' on the alphabet index sidebar
                    u_index = WebDriverWait(driver, 3).until(
                        EC.element_to_be_clickable((By.XPATH, "//*[@content-desc='U' or @text='U']"))
                    )
                    u_index.click()
                    time.sleep(1.5) # Give Flutter a moment to snap the list down to the 'U' section
                except Exception:
                    print("Warning: Could not find the 'U' index link. Falling back to full manual scrolling...")

                print("Searching for 'United States of America'...")
                try:
                    # 2A. Try to click it directly if the 'U' jump put it perfectly on the screen!
                    usa_option = WebDriverWait(driver, 3).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 still slightly hidden, perform a short loop to nudge the list
                    print("Nudging the list to find the United States...")
                    
                    window = driver.get_window_size()
                    center_x = window['width'] // 2
                    
                    # Swipe UP (finger starts low and drags high) to reveal items just below the 'U' jump
                    start_y = int(window['height'] * 0.7)  
                    end_y = int(window['height'] * 0.4)    
                    
                    usa_found = False
                    for _ in range(5):  # We only need 5 max swipes now since we already jumped to U!
                        try:
                            usa_option = WebDriverWait(driver, 1).until(
                                EC.element_to_be_clickable((By.XPATH, "//*[@content-desc='United States of America' or @text='United States of America']"))
                            )
                            usa_option.click()
                            usa_found = True
                            break # Found it!
                        except Exception:
                            # Nudge the list
                            driver.swipe(center_x, start_y, center_x, end_y, 800)
                            time.sleep(0.5) 
                            
                    if not usa_found:
                        raise Exception("Jumped to U, but couldn't find the United States!")
                
                print("Location successfully set!")
                time.sleep(1)
                
            except Exception as loc_err:
                print(f"Warning: Failed to set location. Error: {loc_err}")
                
            # 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()
