import asyncio
import json

from loguru import logger

from app.services.steam_auth import create_steam_session, close_steam, extract_session_cookies
from app.services.steam_wizard import AJAX_HEADERS, run_common_wizard


def _get_fresh_sessionid(steam) -> str:
    """Get sessionid from the live aiohttp cookie jar."""
    return steam._requests.cookies("help.steampowered.com").get("sessionid", "")


async def change_email(account: dict, params: dict, task_id: str = "") -> None:
    """Change account email via Steam recovery wizard + interactive prompts."""
    from app.core.task_manager import task_manager

    login = account["login"]
    new_email = params.get("new_email", "")
    await task_manager.set_step(task_id, 1, 5, "Авторизация", acc_id=account["id"])
    logger.info(f"[change_email] {login}: logging in to Steam...")
    steam = await create_steam_session(account)
    try:
        password = account["password"]
        await task_manager.set_step(task_id, 2, 5, "Wizard", acc_id=account["id"])
        logger.info(f"[change_email] {login}: auth ok, starting email change wizard...")

        wizard = await run_common_wizard(
            steam,
            entry_url="https://help.steampowered.com/wizard/HelpChangeEmail?redir=store/account/",
            login=login,
            password=password,
        )
        logger.info(f"[change_email] {login}: wizard done")

        if not new_email:
            new_email = await task_manager.prompt_user(task_id, f"Введите новый email для {login}", login=login)
        if not new_email:
            raise ValueError("new_email is required")

        await task_manager.set_step(task_id, 3, 5, "Запрос смены", acc_id=account["id"])
        logger.info(f"[change_email] {login}: requesting email change -> {new_email}...")

        for attempt in range(2):
            fresh_sid = _get_fresh_sessionid(steam)
            text = await steam.request(
                url="https://help.steampowered.com/en/wizard/AjaxAccountRecoveryChangeEmail/",
                method="POST",
                data={
                    "s": wizard.s,
                    "account": wizard.account,
                    "sessionid": fresh_sid,
                    "wizard_ajax": 1,
                    "gamepad": 0,
                    "email": new_email,
                },
                headers=AJAX_HEADERS,
            )
            data = json.loads(text) if isinstance(text, str) else text
            logger.debug(f"[change_email] {login}: change request attempt {attempt+1} response: {data}")
            if data.get("errorMsg"):
                error_code = data.get("success", 0)
                if error_code == 24:
                    raise PermissionError(f"Insufficient privileges for email change: {data['errorMsg']}")
                raise RuntimeError(f"Email change request failed: {data['errorMsg']}")

            if attempt == 0:
                await asyncio.sleep(3)

        await task_manager.set_step(task_id, 4, 5, "Код подтверждения", acc_id=account["id"])
        email_code = await task_manager.prompt_user(task_id, f"Введите код подтверждения с email ({new_email})", login=login)
        if not email_code:
            raise ValueError("email_code is required")
        email_code = email_code.strip()

        logger.info(f"[change_email] {login}: confirming email change...")
        fresh_sid = _get_fresh_sessionid(steam)
        confirm_text = await steam.request(
            url="https://help.steampowered.com/en/wizard/AjaxAccountRecoveryConfirmChangeEmail/",
            method="POST",
            data={
                "s": wizard.s,
                "account": wizard.account,
                "sessionid": fresh_sid,
                "wizard_ajax": 1,
                "gamepad": 0,
                "email": new_email,
                "email_change_code": email_code,
            },
            headers=AJAX_HEADERS,
        )
        confirm_data = json.loads(confirm_text) if isinstance(confirm_text, str) else confirm_text
        logger.debug(f"[change_email] {login}: confirm response: success={confirm_data.get('success')}")

        error_code = confirm_data.get("success", 0)
        if confirm_data.get("errorMsg") and error_code != 29:
            raise RuntimeError(f"Email confirmation failed: {confirm_data['errorMsg']}")

        await task_manager.set_step(task_id, 5, 5, "Сохранение", acc_id=account["id"])
        from app.database import get_db
        db = await get_db()
        await db.execute(
            "UPDATE accounts SET email = ?, updated_at = datetime('now') WHERE id = ?",
            (new_email, account["id"]),
        )
        await db.commit()

        logger.success(f"[change_email] {login}: email changed successfully -> {new_email}")
    finally:
        await close_steam(steam)


async def validate_account(account: dict, params: dict, task_id: str = "") -> None:
    """Validate account credentials by attempting login. Fetches profile and ban status on success."""
    from app.database import get_db
    from app.services.steam_auth import close_steam
    from app.services.steam_profile import fetch_profile
    from app.services.steam_ban import check_ban
    from app.core.task_manager import task_manager
    from app.config import read_validation_settings

    steam = None
    error_msg = None
    ban_status = ""
    vac_status = ""
    limit_status = ""
    vac_games: list[str] = []
    balance = ""
    country = ""

    val_settings = read_validation_settings()

    login = account["login"]
    profile = None
    try:
        await task_manager.set_step(task_id, 1, 6, "Авторизация", acc_id=account["id"])
        logger.info(f"[validate] {login}: logging in to Steam...")
        steam = await create_steam_session(account)
        status = "valid"
        logger.info(f"[validate] {login}: auth ok")

        if status == "valid" and steam is not None:
            if val_settings.get("check_ban"):
                await task_manager.set_step(task_id, 2, 6, "Проверка бана", acc_id=account["id"])
                logger.info(f"[validate] {login}: checking ban status...")
                ban_status = await check_ban(steam)
                logger.info(f"[validate] {login}: ban = {ban_status or 'none'}")
                await task_manager.set_step(task_id, 3, 6, "Проверка VAC", acc_id=account["id"])
                from app.services.steam_vac_checker import check_vac_and_limit
                vac_status, limit_status, vac_games = await check_vac_and_limit(steam)
                logger.info(f"[validate] {login}: vac={vac_status or 'none'}, limit={limit_status or 'none'}, games={vac_games}")
            await task_manager.set_step(task_id, 4, 6, "Баланс / Страна", acc_id=account["id"])
            from app.services.steam_store_checker import fetch_balance_and_country
            balance, country = await fetch_balance_and_country(steam)
            logger.info(f"[validate] {login}: balance={balance or 'none'}, country={country or 'none'}")
            if account.get("steam_id") and val_settings.get("fetch_profile"):
                await task_manager.set_step(task_id, 5, 6, "Профиль", acc_id=account["id"])
                logger.info(f"[validate] {login}: fetching profile (id={account['steam_id']})...")
                profile = await fetch_profile(account["steam_id"], steam=steam)
                if profile:
                    logger.info(f"[validate] {login}: profile fetched — {profile.get('nickname')}, lvl={profile.get('steam_level')}")
                else:
                    logger.warning(f"[validate] {login}: failed to fetch profile")

        await task_manager.set_step(task_id, 6, 6, "Сохранение", acc_id=account["id"])
        if steam is not None and status == "valid":
            try:
                session_cookies = extract_session_cookies(steam)
                if session_cookies:
                    _db = await get_db()
                    await _db.execute(
                        "UPDATE accounts SET session_cookies = ?, updated_at = datetime('now') WHERE id = ?",
                        (session_cookies, account["id"]),
                    )
                    await _db.commit()
                    logger.debug(f"[validate] {login}: saved session cookies")
            except Exception as cookie_err:
                logger.warning(f"[validate] {login}: failed to save cookies — {cookie_err}")

            from app.services.steam_auth import update_mafile_tokens
            if update_mafile_tokens(steam, account):
                logger.info(f"[validate] {login}: updated mafile tokens")

    except Exception as exc:
        status = "invalid"
        error_msg = str(exc)
        logger.warning(f"[validate] {login}: error — {error_msg}")
    finally:
        if steam is not None:
            await close_steam(steam)

    import json as _json
    db = await get_db()
    await db.execute(
        "UPDATE accounts SET status = ?, ban_status = ?, vac_status = ?, limit_status = ?, vac_games = ?, balance = ?, country = ?, updated_at = datetime('now') WHERE id = ?",
        (status, ban_status or None, vac_status or None, limit_status or None,
         _json.dumps(vac_games) if vac_games else None,
         balance or None, country or None, account["id"]),
    )
    await db.commit()

    if profile:
        sets = []
        vals = []
        for col, key in [("nickname", "nickname"), ("avatar_url", "avatar_url"), ("steam_level", "steam_level"), ("last_online", "last_online")]:
            if profile.get(key) is not None:
                sets.append(f"{col} = ?")
                vals.append(profile[key])
        if sets:
            sets.append("updated_at = datetime('now')")
            vals.append(account["id"])
            await db.execute(f"UPDATE accounts SET {', '.join(sets)} WHERE id = ?", vals)
            await db.commit()
        logger.info(f"[validate] {login}: profile saved — {profile.get('nickname')}")

    if error_msg:
        raise Exception(f"{error_msg}")
    else:
        ban_info = f" | ban={ban_status}" if ban_status else ""
        logger.info(f"[validate] {login}: result — {status}{ban_info}")
