import os
import asyncio
import re
from playwright.async_api import Page
from app.automation.helpers import human_delay
from app.automation.tasks.login import run as login_run
from app.automation.tasks.popup import close_hudl_popups
from app.automation.selectors import (
    PRIMARY_NAVBAR,
    UPLOAD_NAV_LINK,
    UPLOAD_TEAM_COMBOBOX,
    UPLOAD_TEAM_DROPDOWN_BTN,
    UPLOAD_TEAMS_LIST,
    UPLOAD_SELECT_FILES_BTN,
    UNI_FORM_LABEL,
    UPLOADED_FILES_WRAPPER,
    UPLOADED_FILE_NAME,
    UPLOADED_FILE_DELETE_BTN,
    UPLOADED_FILE_NAME,
    UPLOADED_FILE_DELETE_BTN,
    TRIGGER_UPLOAD_BTN,
    SCHEDULE_EVENT_PLACEHOLDER,
    SCHEDULE_EVENT_MENU,
    SCHEDULE_EVENT_OPTIONS,
    VIDEO_TYPE_LABELS,
    VIDEO_TITLE_INPUT,
    VIDEO_CHECK_EVENT_LABEL,
    VIDEO_DETAILS_SAVE_BTN,
    CANCEL_UPLOAD_BTN,
    CONFIRM_CANCEL_UPLOAD_BTN
)


def _is_upload_page(url: str) -> bool:
    lower = url.lower()
    return "/upload" in lower


async def _resolve_upload_url(page: Page) -> str | None:
    """Resolve upload page URL from the global nav link."""
    if "hudl.com/home" not in page.url:
        await page.goto("https://www.hudl.com/home", wait_until="domcontentloaded")
        await human_delay(1.5, 2.5)
        await close_hudl_popups(page)

    try:
        await page.locator(PRIMARY_NAVBAR).first.wait_for(state="visible", timeout=15000)
    except Exception:
        pass

    upload_links = page.locator(UPLOAD_NAV_LINK)
    count = await upload_links.count()
    for i in range(count):
        link = upload_links.nth(i)
        try:
            href = await link.get_attribute("href")
            if href:
                if href.startswith("http"):
                    return href
                if href.startswith("/"):
                    return f"https://www.hudl.com{href}"
                return f"https://www.hudl.com/{href}"
        except Exception:
            continue

    selected_team = page.locator(
        '[data-qa-id="webnav-teamswitcher-menu"] > a.hui-primaryteamswitcher__item--selected'
    ).first
    qa_id = await selected_team.get_attribute("data-qa-id")
    if qa_id:
        match = re.search(r"webnav-teamswitcher-team-(\d+)", qa_id)
        if match:
            return f"https://www.hudl.com/upload/teams/{match.group(1)}"

    return "https://www.hudl.com/upload"


async def _navigate_to_upload(page: Page) -> None:
    """Open the Hudl upload page."""
    combobox = page.locator(UPLOAD_TEAM_COMBOBOX).first
    try:
        if _is_upload_page(page.url) and await combobox.count() > 0:
            return
    except Exception:
        pass

    upload_url = await _resolve_upload_url(page)
    upload_link = page.locator(UPLOAD_NAV_LINK).first
    try:
        if await upload_link.is_visible():
            print("Clicking upload navigation link...")
            await upload_link.click()
            await human_delay(2, 3)
            if _is_upload_page(page.url):
                return
    except Exception as click_err:
        print(f"Upload nav click failed: {click_err}")

    if upload_url:
        print(f"Navigating to upload at {upload_url}")
        await page.goto(upload_url, wait_until="domcontentloaded")
        await human_delay(2, 3)
        await close_hudl_popups(page)


async def open_upload(page: Page) -> dict:
    await login_run(page)
    await close_hudl_popups(page)
    await _navigate_to_upload(page)
    return {"status": "ok", "action": "open_upload", "url": page.url}

async def get_upload_team(page: Page) -> dict:
    combobox = page.locator(UPLOAD_TEAM_COMBOBOX).first
    team_name = ""
    if await combobox.count() > 0:
        team_name = await combobox.input_value()
    return {"status": "ok", "action": "get_upload_team", "team_name": team_name}

async def open_team_dropdown(page: Page) -> dict:
    btn = page.locator(UPLOAD_TEAM_DROPDOWN_BTN).first
    try:
        await btn.wait_for(state="visible", timeout=10000)
    except Exception as e:
        print(f"open_team_dropdown timed out waiting for dropdown button: {e}. Attempting reload and retry...")
        try:
            # Reload page and wait
            await page.reload(wait_until="domcontentloaded")
            await human_delay(2, 3)
            # Re-run open_upload to trigger navigation to upload tab
            await open_upload(page)
        except Exception as reload_err:
            print(f"open_team_dropdown reload/re-navigation failed: {reload_err}")
        
        # Retry waiting for the button
        await btn.wait_for(state="visible", timeout=10000)

    await btn.click()
    await human_delay(1, 2)
    
    options = []
    list_loc = page.locator(UPLOAD_TEAMS_LIST)
    try:
        await list_loc.first.wait_for(state="attached", timeout=10000)
        count = await list_loc.count()
        for i in range(count):
            text = (await list_loc.nth(i).inner_text()).strip()
            options.append({"index": i, "text": text})
    except Exception:
        pass
        
    return {"status": "ok", "action": "open_team_dropdown", "teams": options}

async def get_upload_teams_list(page: Page) -> dict:
    options = []
    list_loc = page.locator(UPLOAD_TEAMS_LIST)
    
    try:
        await list_loc.first.wait_for(state="attached", timeout=10000)
        count = await list_loc.count()
        for i in range(count):
            text = (await list_loc.nth(i).inner_text()).strip()
            options.append({"index": i, "text": text})
    except Exception:
        pass
    
    return {"status": "ok", "action": "get_upload_teams_list", "teams": options}

async def wait_for_progress_bar_complete(bar_locator, timeout_seconds=600):
    """Wait for the progress bar to reach 100% (transform: translate3d(0%, 0px, 0px))"""
    print("wait_for_progress_bar_complete started checking progress bar...")
    for i in range(int(timeout_seconds * 2)):  # check every 0.5s
        try:
            divs = bar_locator.locator('div')
            if await divs.count() > 0:
                style = await divs.first.get_attribute("style") or ""
                # Normalize style string (remove spaces, semicolons)
                normalized = style.replace(" ", "").replace(";", "")
                
                # Print debug log every 3 seconds (6 iterations)
                if i % 6 == 0:
                    print(f"[Poll {i}] Inner progress div style: '{style}' (normalized: '{normalized}')")
                
                if "translate3d(0%," in normalized or "translate3d(0px," in normalized:
                    print(f"Success: Progress bar reached 100%! Style: {style}")
                    return True
            else:
                if i % 6 == 0:
                    print(f"[Poll {i}] No inner div found inside progress bar yet.")
        except Exception as poll_err:
            if i % 6 == 0:
                print(f"[Poll {i}] Exception while checking progress style: {poll_err}")
        await asyncio.sleep(0.5)
    print("Warning: wait_for_progress_bar_complete timed out waiting for 100% completion.")
    return False

async def select_files(page: Page, team_index: int = None, file_path: str = None) -> dict:
    from app.automation.tasks.popup import close_hudl_popups

    async def _execute():
        # 1. Select the team if index is provided
        if team_index is not None:
            print('here.')
            combobox = page.locator(UPLOAD_TEAM_COMBOBOX).first
            if await combobox.count() > 0:
                aria_expanded = await combobox.get_attribute("aria-expanded")
                if aria_expanded == "false":
                    # Dropdown not expanded, open it first
                    btn = page.locator(UPLOAD_TEAM_DROPDOWN_BTN).first
                    if await btn.count() > 0 and await btn.is_visible():
                        await btn.click()
                        await human_delay(1, 2)

            list_loc = page.locator(UPLOAD_TEAMS_LIST)
            count = await list_loc.count()
            if 0 <= team_index < count:
                item = list_loc.nth(team_index)
                await item.scroll_into_view_if_needed()
                await human_delay(0.5, 1)
                await item.click()
                await human_delay(1, 2)
        else:
            # If no team index is selected or provided, check if the dropdown is expanded.
            # Only click the label to collapse it if it is actually expanded (i.e., not false).
            combobox = page.locator(UPLOAD_TEAM_COMBOBOX).first
            is_expanded = False
            if await combobox.count() > 0:
                aria_expanded = await combobox.get_attribute("aria-expanded")
                is_expanded = (aria_expanded == "true")

            if is_expanded:
                print('Dropdown is expanded, closing it by clicking the label')
                label_loc = page.locator(UNI_FORM_LABEL)
                if await label_loc.count() > 0 and await label_loc.first.is_visible():
                    await label_loc.first.click()
                    await human_delay(0.5, 1)
            else:
                print('Dropdown is not expanded, skipping label click')

        # 2. Upload file through Playwright without opening OS File Dialog
        if file_path and os.path.exists(file_path):
            btn = page.locator(UPLOAD_SELECT_FILES_BTN).first
            await btn.wait_for(state="visible", timeout=15000)
            
            # Intercept the file chooser dialog
            async with page.expect_file_chooser() as fc_info:
                await btn.click()
            
            file_chooser = await fc_info.value
            await file_chooser.set_files(file_path)
            await human_delay(2, 3)
            
            # Check for any Hudl error notice
            error_notice = page.locator('xpath=//div[@class="uni-notice__content"]//h4')
            if await error_notice.count() > 0 and await error_notice.first.is_visible():
                err_text = (await error_notice.first.inner_text()).strip()
                return {"status": "error", "message": f"Hudl upload notice error: {err_text}"}

            # --- NO LONGER WAIT FOR UPLOAD TO COMPLETE IN THE BROWSER ---
            # We return immediately so the frontend can poll progress dynamically!
            # Just check that the progress bar container starts appearing.
            try:
                progress_bar_locator = page.locator('xpath=//div[@class="progress-bar"]')
                await progress_bar_locator.first.wait_for(state="visible", timeout=5000)
            except Exception as e:
                print(f"Warning: Progress bar did not appear in UI within 5 seconds: {e}")
                
            return {"status": "ok", "action": "select_files", "message": "File selected and uploaded successfully in browser."}
        else:
            return {"status": "error", "message": "File not provided or invalid."}

    try:
        return await _execute()
    except Exception as exc:
        print(f"select_files failed: {exc}. Attempting page reload and retry...")
        try:
            await page.reload(wait_until="domcontentloaded")
            await human_delay(3, 5)
            await close_hudl_popups(page)
            await open_upload(page)
        except Exception as recovery_err:
            print(f"select_files reload/recovery failed: {recovery_err}")
            
        # Retry the execution once more
        return await _execute()


async def get_uploaded_files(page: Page) -> dict:
    files = []
    try:
        wrappers = page.locator(UPLOADED_FILES_WRAPPER)
        count = await wrappers.count()
        for i in range(count):
            name_loc = wrappers.nth(i).locator(UPLOADED_FILE_NAME)
            name = (await name_loc.inner_text()).strip() if await name_loc.count() > 0 else f"Unknown File {i}"
            files.append({"index": i, "name": name})
    except Exception as e:
        pass

    return {
        "status": "ok",
        "action": "get_uploaded_files",
        "files": files,
        "message": "Files retrieved successfully." if files else "No files uploaded."
    }


async def delete_uploaded_file(page: Page, file_index: int) -> dict:
    try:
        wrappers = page.locator(UPLOADED_FILES_WRAPPER)
        count = await wrappers.count()
        if 0 <= file_index < count:
            del_btn = wrappers.nth(file_index).locator(UPLOADED_FILE_DELETE_BTN)
            if await del_btn.count() > 0 and await del_btn.is_visible():
                await del_btn.click()
                await human_delay(1, 2)
                return {
                    "status": "ok", 
                    "action": "delete_uploaded_file", 
                    "message": f"Successfully deleted file at index {file_index}."
                }
            else:
                return {"status": "error", "message": f"Delete button not visible for index {file_index}."}
        else:
            return {"status": "error", "message": f"File index {file_index} is out of bounds (total {count})."}
    except Exception as e:
        return {"status": "error", "message": str(e)}


async def trigger_upload(page: Page) -> dict:
    try:
        btn = page.locator(TRIGGER_UPLOAD_BTN).first
        if await btn.count() > 0 and await btn.is_visible():
            await btn.click()
            await human_delay(1, 2)
            return {"status": "ok", "action": "trigger_upload", "message": "Triggered upload button."}
        else:
            return {"status": "error", "message": "Upload trigger button not found or not visible."}
    except Exception as e:
        return {"status": "error", "message": str(e)}


async def open_schedule_event(page: Page) -> dict:
    try:
        btn = page.locator(SCHEDULE_EVENT_PLACEHOLDER).first
        if await btn.count() > 0 and await btn.is_visible():
            await btn.click()
            await human_delay(1.5, 2.5)
            
            options = []
            locs = page.locator(SCHEDULE_EVENT_OPTIONS)
            count = await locs.count()
            for i in range(count):
                el = locs.nth(i)
                primary = el.locator('.select-text-primary')
                subtle = el.locator('.subtle')
                if await primary.count() > 0:
                    title = (await primary.inner_text()).strip()
                    date = (await subtle.inner_text()).strip() if await subtle.count() > 0 else ""
                    options.append({"index": i, "title": title, "date": date})
                else:
                    text = (await el.inner_text()).strip()
                    options.append({"index": i, "title": text, "date": ""})
                    
            return {"status": "ok", "action": "open_schedule_event", "events": options}
        else:
            return {"status": "error", "message": "Schedule event placeholder not found."}
    except Exception as e:
         return {"status": "error", "message": str(e)}


async def get_schedule_events(page: Page) -> dict:
    try:
        options = []
        locs = page.locator(SCHEDULE_EVENT_OPTIONS)
        count = await locs.count()
        for i in range(count):
            el = locs.nth(i)
            # Check for primary text and subtle text
            primary = el.locator('.select-text-primary')
            subtle = el.locator('.subtle')
            
            if await primary.count() > 0:
                title = (await primary.inner_text()).strip()
                date = (await subtle.inner_text()).strip() if await subtle.count() > 0 else ""
                options.append({"index": i, "title": title, "date": date})
            else:
                text = (await el.inner_text()).strip()
                options.append({"index": i, "title": text, "date": ""})
                
        return {
            "status": "ok", 
            "action": "get_schedule_events", 
            "events": options
        }
    except Exception as e:
         return {"status": "error", "message": str(e)}


async def fill_video_details(page: Page, schedule_event_index: int = None, video_type: str = "Game", title: str = None, check_event: bool = False) -> dict:
    try:
        # 1. Select schedule event if provided
        if schedule_event_index is not None:
            opts = page.locator(SCHEDULE_EVENT_OPTIONS)
            if await opts.count() > schedule_event_index:
                await opts.nth(schedule_event_index).scroll_into_view_if_needed()
                await human_delay(0.2, 0.5)
                await opts.nth(schedule_event_index).click()
                await human_delay(0.5, 1)

        # 2. Select video type (Game, Practice, Scout)
        type_labels = page.locator(VIDEO_TYPE_LABELS)
        count = await type_labels.count()
        for i in range(count):
            text = await type_labels.nth(i).inner_text()
            if video_type.lower() in text.lower():
                await type_labels.nth(i).click()
                await human_delay(0.5, 1)
                break

        # 3. Fill title
        if title is not None:
            title_input = page.locator(VIDEO_TITLE_INPUT).first
            if await title_input.count() > 0 and await title_input.is_visible():
                await title_input.fill("")
                await human_delay(0.2, 0.5)
                await title_input.fill(title)
                await human_delay(0.5, 1)

        # 4. Check event checkbox
        if check_event:
            chk = page.locator(VIDEO_CHECK_EVENT_LABEL).first
            if await chk.count() > 0 and await chk.is_visible():
                await chk.click()
                await human_delay(0.5, 1)

        # 5. Non-blocking safety check: verify at least progress bar is present if uploading
        print("Non-blocking check: video details save triggered.")

        # 6. Save button
        save_btn = page.locator(VIDEO_DETAILS_SAVE_BTN).first
        if await save_btn.count() > 0 and await save_btn.is_visible():
            await save_btn.click()
            await human_delay(3, 5)

        # 6. Tab cleanup: close newly opened tabs and focus original page
        try:
            pages = page.context.pages
            if len(pages) > 1:
                print(f"Detected {len(pages)} open tabs. Closing new tabs...")
                for p in pages:
                    if p != page:
                        try:
                            await p.close()
                        except Exception:
                            pass
                await page.bring_to_front()
                await human_delay(1, 2)
        except Exception as tab_err:
            print("Error cleaning up tabs:", tab_err)

        return {"status": "ok", "action": "fill_video_details", "message": "Video details saved successfully."}
    except Exception as e:
        return {"status": "error", "message": str(e)}


async def cancel_upload(page: Page) -> dict:
    try:
        # 1. Click initial cancel button
        cancel_btn = page.locator(CANCEL_UPLOAD_BTN).first
        if await cancel_btn.count() > 0 and await cancel_btn.is_visible():
            await cancel_btn.click()
            await human_delay(1, 2)
            
            # 2. Click confirm cancel button in the modal
            confirm_btn = page.locator(CONFIRM_CANCEL_UPLOAD_BTN).first
            if await confirm_btn.count() > 0 and await confirm_btn.is_visible():
                await confirm_btn.click()
                await human_delay(1, 2)
                return {"status": "ok", "action": "cancel_upload", "message": "Upload cancelled successfully."}
            else:
                return {"status": "error", "message": "Confirm cancel button not found in modal."}
        else:
            return {"status": "error", "message": "Cancel upload button not found or not visible."}
    except Exception as e:
        return {"status": "error", "message": str(e)}


async def get_upload_progress(page: Page) -> dict:
    try:
        progress_bars = page.locator('xpath=//div[@class="progress-bar"]')
        total = await progress_bars.count()
        completed = 0
        for i in range(total):
            bar = progress_bars.nth(i)
            divs = bar.locator('div')
            if await divs.count() > 0:
                style = await divs.first.get_attribute("style") or ""
                # Normalize style string
                normalized = style.replace(" ", "").replace(";", "")
                if "translate3d(0%," in normalized or "translate3d(0px," in normalized:
                    completed += 1
        return {
            "status": "ok",
            "action": "get_upload_progress",
            "total": total,
            "completed": completed
        }
    except Exception as e:
        return {"status": "error", "message": str(e)}
