"""Compound intent: site research + local folder/document (0.2.2.57)."""

from __future__ import annotations

import re
from pathlib import Path
from typing import Any
from urllib.parse import urlparse

from .content_creation_intent import extract_content_topic, extract_landing_folder_name
from .website_resolver import extract_url_from_prompt, prompt_specifies_site
from iuve_connect_agents.shared.url_normalizer import extract_normalized_url_from_text, normalize_avatar_url

_CONSENT = {"user_consent_state": "consented_via_connect_flow"}

_LOCAL_FOLDER_CREATE_RE = re.compile(
    r"\b(?:создай|создать|create|make)\s+папк",
    re.IGNORECASE,
)
_LOCAL_DOCUMENT_RE = re.compile(
    r"\b(?:"
    r"новый\s+документ|новом\s+документе|"
    r"create\s+(?:a\s+)?(?:new\s+)?document|"
    r"в\s+документ|в\s+новом\s+документе|"
    r"открой\s+документ|open\s+document"
    r")\b",
    re.IGNORECASE,
)
_PLACE_IN_FOLDER_RE = re.compile(
    r"\b(?:помести|положи|сохрани|save|place)\b.{0,40}\b(?:папк|folder)\b",
    re.IGNORECASE,
)
_EXPLICIT_DESKTOP_RE = re.compile(
    r"\b(?:"
    r"рабоч\w*\s+стол\w*|"
    r"на\s+рабоч\w*\s+стол\w*|"
    r"desktop"
    r")\b",
    re.IGNORECASE,
)
_VISUAL_SITE_ANALYSIS_RE = re.compile(
    r"\b(?:"
    r"визуальн\w*\s+анализ|"
    r"анализ\w*\s+визуальн|"
    r"visual\s+(?:analysis|describe)|"
    r"describe.*(?:site|сайт)|"
    r"опиши.*(?:сайт|site|страниц)"
    r")\b",
    re.IGNORECASE,
)
_SITE_OPEN_RE = re.compile(
    r"\b(?:открой|open)\s+(?:сайт|site|url|https?://|www\.)",
    re.IGNORECASE,
)
_POST_IN_DOCUMENT_RE = re.compile(
    r"\b(?:напиш\w*|write)\b.{0,60}\b(?:пост|post)\b",
    re.IGNORECASE,
)
_FOLDER_NAME_ON_DESKTOP_RE = re.compile(
    r"\b(?:рабоч\w*\s+стол\w*|desktop)\s+([A-Za-zА-Яа-яЁё][A-Za-zА-Яа-яЁё0-9_-]*)",
    re.IGNORECASE,
)
_FOLDER_NAME_AFTER_CREATE_RE = re.compile(
    r"\b(?:создай|создать|create)\s+папк[уаеи]\s+(?:на\s+)?(?:рабоч\w*\s+стол\w*|desktop)?\s*([A-Za-zА-Яа-яЁё][A-Za-zА-Яа-яЁё0-9_-]*)",
    re.IGNORECASE,
)
_FOLDER_NAME_DESKTOP_THEN_CREATE_RE = re.compile(
    r"\b(?:создай|создать|create)\s+(?:на\s+)?(?:рабоч\w*\s+стол\w*|desktop)\s+папк[уаеи]\s+([A-Za-zА-Яа-яЁё][A-Za-zА-Яа-яЁё0-9_-]*)",
    re.IGNORECASE,
)
_FOLDER_STOPWORDS = frozenset(
    {
        "на",
        "в",
        "in",
        "the",
        "a",
        "an",
        "рабочем",
        "рабочий",
        "столе",
        "стол",
        "desktop",
        "папку",
        "папка",
        "папке",
        "folder",
        "create",
        "создай",
        "создать",
    }
)
_PLACE_IN_NAMED_FOLDER_RE = re.compile(
    r"\b(?:папк[уаеи]|folder)\s+([A-Za-zА-Яа-яЁё][A-Za-zА-Яа-яЁё0-9_-]*)",
    re.IGNORECASE,
)


def user_explicit_desktop_intent(text: str) -> bool:
    """True when user names Desktop/рабочий стол explicitly."""
    return bool(_EXPLICIT_DESKTOP_RE.search(str(text or "")))


def is_local_file_artifact_intent(text: str) -> bool:
    """Local folder/document artifact — not web composer or site post."""
    raw = str(text or "").strip()
    if not raw:
        return False
    lower = raw.lower()
    has_folder = bool(_LOCAL_FOLDER_CREATE_RE.search(raw)) or "папк" in lower
    has_local_doc = bool(_LOCAL_DOCUMENT_RE.search(raw))
    has_place = bool(_PLACE_IN_FOLDER_RE.search(raw))
    if has_local_doc and (has_folder or has_place):
        return True
    if has_folder and (has_place or "документ" in lower or "document" in lower):
        return True
    if has_folder and user_explicit_desktop_intent(raw):
        return True
    return False


def is_site_visual_research_intent(text: str) -> bool:
    """Open a URL and visually analyze/describe it."""
    raw = str(text or "").strip()
    if not raw:
        return False
    has_site = bool(extract_url_from_prompt(raw)) or prompt_specifies_site(raw)
    if not has_site:
        return False
    return bool(_VISUAL_SITE_ANALYSIS_RE.search(raw))


def is_compound_site_local_intent(text: str) -> bool:
    """Site URL combined with local folder/document or visual-then-write goals."""
    raw = str(text or "").strip()
    if not raw:
        return False
    has_site = bool(extract_url_from_prompt(raw)) or prompt_specifies_site(raw)
    if not has_site:
        return False
    if is_local_file_artifact_intent(raw):
        return True
    lower = raw.lower()
    has_local_doc = bool(_LOCAL_DOCUMENT_RE.search(raw)) or "документ" in lower
    has_post = "пост" in lower or "post" in lower
    if has_local_doc and (has_post or is_site_visual_research_intent(raw)):
        return True
    if is_site_visual_research_intent(raw) and has_local_doc:
        return True
    return False


def should_defer_folder_analysis(text: str) -> bool:
    """Folder analysis must not win over compound site/local goals."""
    raw = str(text or "").strip()
    if not raw:
        return False
    if is_compound_site_local_intent(raw):
        return True
    has_site = bool(extract_url_from_prompt(raw)) or prompt_specifies_site(raw) or bool(_SITE_OPEN_RE.search(raw))
    if not has_site:
        return False
    lower = raw.lower()
    if is_site_visual_research_intent(raw):
        return True
    if any(token in lower for token in ("пост", "post", "открой сайт", "open site")):
        return True
    if "документ" in lower and any(token in lower for token in ("напиш", "write", "создай", "create")):
        return True
    return False


def should_defer_web_post_intent(text: str) -> bool:
    """Web composer post must not win when user wants a local document/folder."""
    raw = str(text or "").strip()
    if not raw:
        return False
    try:
        from .libreoffice_document_intent import (
            is_document_article_failure_follow_up,
            is_libreoffice_article_intent,
            should_block_meta_external_for_local_document,
        )

        if (
            is_libreoffice_article_intent(raw)
            or is_document_article_failure_follow_up(raw)
            or should_block_meta_external_for_local_document(raw)
        ):
            return True
    except ImportError:
        pass
    if is_local_file_artifact_intent(raw):
        return True
    if is_compound_site_local_intent(raw):
        if re.search(r"\b(?:опублик|publish|черновик\s+на\s+сайт|post\s+on)\b", raw, re.IGNORECASE):
            return False
        return True
    lower = raw.lower()
    if bool(_LOCAL_DOCUMENT_RE.search(raw)) and ("пост" in lower or "post" in lower):
        return True
    return False


def _resolve_site_url(text: str) -> str:
    url = extract_url_from_prompt(text) or extract_normalized_url_from_text(text)
    if url:
        return url
    match = re.search(
        r"\b(?:[a-zA-Z0-9](?:[a-zA-Z0-9-]{0,61}[a-zA-Z0-9])?\.)+[a-zA-Z]{2,63}\b",
        str(text or ""),
    )
    if match:
        return normalize_avatar_url(match.group(0))
    return ""


def _extract_target_folder_name(text: str) -> str:
    raw = str(text or "").strip()
    for pattern in (
        _FOLDER_NAME_DESKTOP_THEN_CREATE_RE,
        _FOLDER_NAME_ON_DESKTOP_RE,
        _FOLDER_NAME_AFTER_CREATE_RE,
        _PLACE_IN_NAMED_FOLDER_RE,
    ):
        match = pattern.search(raw)
        if match:
            name = str(match.group(1) or "").strip()
            if name and name.lower() not in _FOLDER_STOPWORDS:
                return name
    folder = extract_landing_folder_name(raw)
    if folder and folder.lower() not in {"сайт", "site", * _FOLDER_STOPWORDS}:
        return folder
    return "Research"


def _host_label(url: str) -> str:
    host = (urlparse(url).hostname or "").strip().lower().removeprefix("www.")
    return host or "site"


def _resolve_desktop_folder_path(text: str, folder_name: str) -> tuple[Path, str]:
    from iuve_connect_agents.shared.device_context_model import get_planning_dcm, resolve_path_from_dcm

    explicit = user_explicit_desktop_intent(text)
    dcm = get_planning_dcm()
    if dcm:
        desktop_str, hint, _remapped = resolve_path_from_dcm(
            "desktop",
            dcm=dcm,
            explicit_desktop=explicit,
            for_write=True,
        )
        if desktop_str:
            desktop = Path(desktop_str)
            target = desktop / folder_name
            return target, hint or f"Рабочий стол (DCM): {desktop}"

    from .capability_resolver import resolve_xdg_folder

    desktop = resolve_xdg_folder("desktop")
    if desktop is None:
        desktop = Path.home() / "Desktop"
    target = desktop.expanduser() / folder_name
    hint = f"Рабочий стол: {desktop}"
    return target, hint


def build_compound_site_local_plan(text: str) -> dict[str, Any] | None:
    """Site open → visual research → local folder/document artifact."""
    if not is_compound_site_local_intent(text):
        return None

    url = _resolve_site_url(text)
    if not url:
        return None

    host = _host_label(url)
    topic = extract_content_topic(text, default=host)
    wants_folder = bool(_LOCAL_FOLDER_CREATE_RE.search(text)) or bool(
        re.search(r"\bпапк", str(text or ""), re.IGNORECASE)
    )
    wants_local_doc = bool(_LOCAL_DOCUMENT_RE.search(text)) or "документ" in str(text or "").lower()
    wants_post = bool(_POST_IN_DOCUMENT_RE.search(text)) or (
        "пост" in str(text or "").lower() and wants_local_doc
    )
    folder_name = _extract_target_folder_name(text)

    steps: list[dict[str, Any]] = [
        {
            "step_id": "s1",
            "command_type": "browser_open_url",
            "payload": {"url": url, "new_window": True, "browser": "default", **_CONSENT},
        },
        {
            "step_id": "s2",
            "command_type": "describe_active_window",
            "depends_on": ["s1"],
            "payload": {
                "prompt": f"Кратко опиши визуально содержимое сайта {host} для дальнейшего документа.",
                "delay_sec": 4.0,
                "active_site": url,
                "depends_on_step": "s1",
                **_CONSENT,
            },
        },
    ]
    last_dep = "s2"

    if wants_folder:
        target_path, policy_hint = _resolve_desktop_folder_path(text, folder_name)
        folder_step_id = "s3_folder"
        steps.append(
            {
                "step_id": folder_step_id,
                "command_type": "open_folder",
                "depends_on": [last_dep],
                "payload": {
                    "absolute_path": str(target_path),
                    "folder_name": folder_name,
                    "policy_hint": policy_hint,
                    "explicit_desktop": user_explicit_desktop_intent(text),
                    **_CONSENT,
                },
            }
        )
        last_dep = folder_step_id

    content_type = "social_post" if wants_post else "document"
    generate_id = "s_gen"
    steps.append(
        {
            "step_id": generate_id,
            "command_type": "generate_content",
            "depends_on": [last_dep],
            "payload": {
                "content_type": content_type,
                "topic": topic or host,
                "research_context_from_step": "s2",
                "content_from_step": "s2",
                "goal_summary": f"{'Post' if wants_post else 'Document'} about {host}",
                **_CONSENT,
            },
        }
    )

    if wants_folder or (wants_local_doc and not wants_post):
        filename = f"{folder_name}-site-summary.md" if wants_folder else f"{host.replace('.', '-')}-summary.md"
        write_id = "s_write"
        if wants_folder:
            target_path, _ = _resolve_desktop_folder_path(text, folder_name)
            abs_path = str(target_path / filename)
            rel_path = f"{folder_name}/{filename}"
        else:
            abs_path = f"IuVeWorkspace/{filename}"
            rel_path = f"IuVeWorkspace/{filename}"
        steps.extend(
            [
                {
                    "step_id": write_id,
                    "command_type": "write_file_in_workspace",
                    "depends_on": [generate_id],
                    "payload": {
                        "relative_path": rel_path,
                        "absolute_path": abs_path,
                        "content_from_step": generate_id,
                        "artifact_topic": topic or host,
                        **_CONSENT,
                    },
                },
                {
                    "step_id": "s_verify",
                    "command_type": "verify_workspace_file",
                    "depends_on": [write_id],
                    "payload": {
                        "relative_path": rel_path,
                        "absolute_path": abs_path,
                        "topic": topic or host,
                        "verify_mode": "exists",
                        **_CONSENT,
                    },
                },
            ]
        )
        goal = f"Изучить {host}, создать папку {folder_name} на рабочем столе и записать документ"
        if not wants_folder:
            goal = f"Изучить {host} и записать документ"
        return {
            "goal_summary": goal,
            "verifier": "document_generated",
            "compound_intent": "SITE_RESEARCH_LOCAL_ARTIFACT",
            "steps": steps,
        }

    doc_step_id = "s_doc"
    doc_path = f"IuVeWorkspace/{host.replace('.', '-')}-post.odt"
    steps.extend(
        [
            {
                "step_id": doc_step_id,
                "command_type": "open_document_edit",
                "depends_on": [generate_id],
                "payload": {
                    "content_from_step": generate_id,
                    "relative_path": doc_path,
                    "editor": "libreoffice",
                    "mode": "edit",
                    **_CONSENT,
                },
            },
            {
                "step_id": "s_type",
                "command_type": "keyboard_type_text",
                "depends_on": [doc_step_id],
                "payload": {
                    "content_from_step": generate_id,
                    "text_from_step": generate_id,
                    "target_app": "libreoffice",
                    "window_name": "LibreOffice",
                    "delay_sec": 5.0,
                    **_CONSENT,
                },
            },
        ]
    )
    return {
        "goal_summary": f"Визуально изучить {host} и написать пост в документе",
        "verifier": "document_generated",
        "compound_intent": "SITE_VISUAL_THEN_DOCUMENT_POST",
        "steps": steps,
    }
