"""Post-plan goal verification messages (P0 block 9)."""

from __future__ import annotations

from typing import Any
from urllib.parse import urlparse


def _host_matches(url: str, required_host: str) -> bool:
    host = (urlparse(str(url or "")).hostname or "").lower().removeprefix("www.")
    required = str(required_host or "").strip().lower().removeprefix("www.")
    if not host or not required:
        return False
    return host == required or host.endswith(f".{required}")


def _step_evidence(step: Any) -> dict[str, Any]:
    return dict(getattr(step, "evidence", None) or {})


def _browser_openai_goal_verified(*, goal: str, completed_steps: list[Any]) -> str | None:
    lower_goal = goal.lower()
    if "openai" not in lower_goal and "официальн" not in lower_goal:
        return None
    saw_openai = False
    saw_google_only = False
    for step in completed_steps:
        evidence = _step_evidence(step)
        command_type = str(getattr(step, "command_type", "") or evidence.get("command_type") or "").strip().lower()
        if command_type == "browser_open_url":
            url = str(evidence.get("url") or "").strip()
            if _host_matches(url, "openai.com"):
                saw_openai = True
            elif "google." in (urlparse(url).hostname or "").lower():
                saw_google_only = True
        if command_type == "verify_screen_contains_text":
            required_host = str(evidence.get("required_url_host") or "").strip()
            verifier = dict(evidence.get("verifier_result") or {})
            if _host_matches(required_host or verifier.get("required_url_host") or "", "openai.com"):
                if evidence.get("pass") or verifier.get("url_domain_verified") or verifier.get("pass"):
                    saw_openai = True
    if saw_openai:
        return "✓ Официальный сайт openai.com открыт"
    if saw_google_only:
        return None
    return None


def _job_search_goal_verified(*, goal: str, completed_steps: list[Any]) -> str | None:
    if not any(token in goal for token in ("ваканс", "объявлен", "job", "driver", "водител")):
        return None
    for step in reversed(completed_steps):
        evidence = _step_evidence(step)
        if str(evidence.get("verify_mode") or "") != "web_research_extract":
            continue
        count = int(evidence.get("result_count") or len(evidence.get("results") or []))
        min_results = int(evidence.get("min_results") or 3)
        if count >= min_results:
            return f"✓ Найдено {count} объявлений (таблица ≥{min_results})"
        note = str(evidence.get("honest_note") or evidence.get("markdown") or "").strip()
        if note:
            return f"✓ {note}"
    return None


def _web_research_goal_verified(*, goal: str, completed_steps: list[Any]) -> str | None:
    if not any(token in goal for token in ("поиск", "search", "интернет", "internet", "web research")):
        return None
    for step in reversed(completed_steps):
        evidence = _step_evidence(step)
        command_type = str(getattr(step, "command_type", "") or evidence.get("command_type") or "").strip().lower()
        if command_type == "summarize_content" or str(evidence.get("verify_mode") or "") == "research_completed":
            summary = str(evidence.get("summary") or "").strip()
            summary_len = int(evidence.get("summary_length") or len(summary))
            if summary_len > 0:
                short = summary[:400] + ("…" if len(summary) > 400 else "")
                return f"✓ Результаты поиска:\n{short}"
        if str(evidence.get("verify_mode") or "") == "web_research_extract":
            markdown = str(evidence.get("markdown") or "").strip()
            if markdown:
                short = markdown[:400] + ("…" if len(markdown) > 400 else "")
                return f"✓ {short}"
            return "✓ Не удалось извлечь результаты поиска автоматически."
    return None


def format_goal_verification_message(
    *,
    goal_summary: str,
    completed_steps: list[Any],
) -> str | None:
    """Return a specific outcome line (✓ …) when the plan goal can be verified from evidence."""
    goal = str(goal_summary or "").strip().lower()
    if not completed_steps:
        return None

    openai_line = _browser_openai_goal_verified(goal=goal, completed_steps=completed_steps)
    if openai_line:
        return openai_line
    openai_navigation_goal = "openai" in goal or "официальн" in goal

    job_line = _job_search_goal_verified(goal=goal, completed_steps=completed_steps)
    if job_line:
        return job_line

    research_line = _web_research_goal_verified(goal=goal, completed_steps=completed_steps)
    if research_line:
        return research_line

    web_research_goal = any(token in goal for token in ("поиск", "search", "интернет", "internet"))

    for step in reversed(completed_steps):
        evidence = dict(getattr(step, "evidence", None) or {})
        handler = str(evidence.get("handler") or "").strip().lower()
        command_type = str(getattr(step, "command_type", "") or evidence.get("command_type") or "").strip().lower()

        if handler == "list_files_in_folder" or command_type == "list_files_in_folder":
            count = int(evidence.get("match_count") or len(evidence.get("files") or []))
            pattern = str(evidence.get("pattern") or "файл").strip()
            extension = str(evidence.get("extension") or "").strip().lower()
            action = str(evidence.get("action") or "").strip().lower()
            if action == "folder_analysis" or evidence.get("folder_analysis_report"):
                report = str(evidence.get("folder_analysis_report") or evidence.get("file_list_text") or "").strip()
                if report:
                    first_line = report.splitlines()[0] if report.splitlines() else report
                    return f"✓ {first_line.lstrip('#').strip()}"
                return f"✓ Проанализировано файлов: {count}"
            if count == 0:
                empty = str(evidence.get("empty_message") or "").strip()
                if empty:
                    return f"✓ {empty}"
                return "✓ Файлы не найдены"
            if extension == "pdf" or "pdf" in pattern.lower() or "pdf" in goal:
                return f"✓ Найдено {count} PDF"
            return f"✓ Найдено {count} файлов"

        if handler == "browser_open_url" or command_type == "browser_open_url":
            url = str(evidence.get("url") or "").strip()
            if openai_navigation_goal or web_research_goal:
                continue
            mvp = str(evidence.get("mvp_limitation") or "").strip()
            if mvp and ("поиск" in goal or "search" in goal or "интернет" in goal):
                continue
            if url and ("загруз" in goal or "load" in goal or "сайт" in goal):
                host = urlparse(url).hostname or url
                return f"✓ Страница {host} открыта в браузере"

        if handler in {"verify_screen_contains_text", "describe_active_window"} or command_type in {
            "verify_screen_contains_text",
            "describe_active_window",
        }:
            findings = str(evidence.get("findings") or evidence.get("description") or "").strip()
            if findings:
                if "активн" in goal or "окн" in goal or "window" in goal:
                    short = findings[:240] + ("…" if len(findings) > 240 else "")
                    return f"✓ Активное окно: {short}"
                if "загруз" in goal or "load" in goal:
                    if evidence.get("pass") or evidence.get("page_loaded"):
                        return "✓ Страница загрузилась"
                    return "✗ Страница не подтверждена по скриншоту"

        if handler == "get_diagnostics" or command_type == "get_diagnostics":
            if "таблиц" in goal or "cpu" in goal or "диск" in goal or "процессор" in goal:
                return "✓ Метрики устройства собраны (см. таблицу выше)"

        if handler == "application_launch" or command_type == "application_launch":
            app = str(evidence.get("application") or "").strip()
            if app and ("монитор" in goal or "monitor" in goal or "stacer" in goal):
                return f"✓ Приложение {app} запущено"

        if handler == "verify_workspace_file" or command_type == "verify_workspace_file":
            path = str(evidence.get("path") or "").strip()
            if path and ("лендинг" in goal or "landing" in goal or "html" in goal):
                if evidence.get("pass"):
                    return f"✓ Файл создан: {path}"
                return f"✗ Проверка HTML не пройдена: {path}"

        if handler == "generate_content" or command_type == "generate_content":
            ctype = str(evidence.get("content_type") or "").strip()
            if ctype == "html_landing" and ("лендинг" in goal or "html" in goal):
                return f"✓ HTML-контент сгенерирован ({evidence.get('content_length', 0)} символов)"
            if ctype == "social_post" and ("пост" in goal or "post" in goal or "черновик" in goal):
                return "✓ Текст поста сгенерирован"

        if handler == "verify_web_draft" or command_type == "verify_web_draft":
            draft_state = str(evidence.get("draft_state") or evidence.get("web_post_status") or "").strip()
            if draft_state in {"draft_verified", "draft_created"} and evidence.get("pass"):
                return "✓ Черновик подтверждён в composer (vision)"
            if draft_state == "draft_content_mismatch":
                return "✗ Текст в composer не совпадает с ожидаемым"
            if draft_state == "composer_not_found":
                return "✗ Composer не найден — черновик не создан"
            if draft_state == "composer_found":
                return "✓ Composer найден"
            if draft_state == "typed_wrong_control":
                return "✗ Текст введён не в composer (неверный фокус)"
            if draft_state == "draft_not_created":
                return "✗ Черновик не подтверждён по скриншоту"
            if draft_state == "typing_failed":
                return "✗ Не удалось ввести текст в composer"

        if handler == "browser_click_publish" or command_type == "browser_click_publish":
            if evidence.get("publish_confirmation_required"):
                return "Черновик готов. Для публикации требуется подтверждение."
            if evidence.get("publish_clicked") or evidence.get("published"):
                return "✓ Публикация отправлена (кнопка нажата)"
            if evidence.get("publish_failed") or evidence.get("detail") == "publish_button_not_found":
                return "✗ Кнопка публикации не найдена"

        if handler == "verify_published" or command_type == "verify_published":
            if evidence.get("publish_verified"):
                return "✓ Публикация подтверждена по скриншоту"
            if evidence.get("publish_failed"):
                return "✗ Публикация не подтверждена"

        if handler == "insert_exact_text" or command_type == "insert_exact_text":
            exact = str(evidence.get("exact_text") or evidence.get("content") or "").strip()
            if exact:
                return f"✓ Точный текст подготовлен: {exact[:80]}"

        if handler == "keyboard_type_text" or command_type == "keyboard_type_text":
            draft_state = str(evidence.get("draft_state") or evidence.get("web_post_status") or "").strip()
            if draft_state == "pending_verification":
                return None
            if draft_state == "draft_inserted" and evidence.get("composer_mode"):
                return "✓ Текст вставлен в composer (ожидает проверки)"
            if ("пост" in goal or "черновик" in goal or "draft" in goal) and evidence.get("draft_verified"):
                return "✓ Черновик введён в composer (без публикации)"
            if ("пост" in goal or "черновик" in goal) and evidence.get("typed") and not evidence.get("draft_verified"):
                return None

        if handler == "open_folder" or command_type == "open_folder":
            path = str(evidence.get("path") or "").strip()
            if path and ("загрузк" in goal or "downloads" in goal):
                return f"✓ Открыта папка {path}"

        if handler == "capture_screenshot" or command_type == "capture_screenshot":
            path = str(
                evidence.get("saved_path")
                or evidence.get("artifact_path")
                or evidence.get("path")
                or evidence.get("screenshot_path")
                or ""
            ).strip()
            if path:
                return f"✓ Скриншот сохранён: {path}"
            if evidence.get("present_to_chat"):
                return "✓ Скриншот сделан, но путь к файлу не получен"

    if "план" in goal and ("копир" in goal or "backup" in goal or "резерв" in goal):
        return "✓ План действий подготовлен (без выполнения)"

    if "plan_only" in goal or "без выполн" in goal:
        return "✓ plan_generated"

    return None
