"""Interactive Notion connection: secret → verify API → optional .env."""

from __future__ import annotations

import argparse
import os
import sys
from pathlib import Path

from folio_notion.envfile import load_dotenv, upsert_env
from folio_notion.integrations.notion_api import NotionAPIError
from folio_notion.integrations.notion_api import parse_page_id_from_user_input
from folio_notion.integrations.notion_api import verify_integration_token
from folio_notion.integrations.notion_api import verify_parent_location
from folio_notion.prompts import prompt_line, prompt_secret

_GUIDE_EVERY_N_FAILURES = 3
_QUIT_PARENT = frozenset({"quit", "exit", "q", ":q"})


def _env_path(args: argparse.Namespace) -> Path:
    root = Path(getattr(args, "project_root", ".") or ".").resolve()
    return root / ".env"


def _prompt_yes_no(prompt: str, default_yes: bool) -> bool:
    hint = "Y/n" if default_yes else "y/N"
    try:
        line = prompt_line(f"{prompt} [{hint}] ").strip().lower()
    except EOFError:
        return default_yes
    if not line:
        return default_yes
    return line in ("y", "yes")


def _short_parent_guide() -> None:
    print()
    print("Quick guide (parent page / database):")
    print("  • In Notion: open the page → Share → Copy link → paste it here (full URL is OK).")
    print(
        "  • The id is the 32-character block in the path, e.g. "
        "…notion.so/<this-part>?…"
    )
    print("  • **Page or database** both work; invite your integration to that location.")
    print('  • Or skip: press Enter, or type quit / exit / q to leave this step.')
    print("  • You can set NOTION_PARENT_PAGE_ID later in `.env`.")
    print()


def _title_from_page(page: dict) -> str:
    props = page.get("properties") if isinstance(page.get("properties"), dict) else {}
    if "title" in props:
        t = props["title"]
        if isinstance(t, dict) and t.get("title"):
            parts = t["title"]
            if isinstance(parts, list) and parts and isinstance(parts[0], dict):
                return str(parts[0].get("plain_text", ""))
    return ""


def _title_from_database(db: dict) -> str:
    raw = db.get("title")
    if isinstance(raw, list) and raw and isinstance(raw[0], dict):
        return str(raw[0].get("plain_text", ""))
    return ""


def _verify_parent_and_print_title(token: str, normalized_id: str) -> None:
    kind, obj = verify_parent_location(token, normalized_id)
    if kind == "page":
        title = _title_from_page(obj)
    else:
        title = _title_from_database(obj)
    label = "page" if kind == "page" else "database"
    print(f"Can access parent ({label}): {title or normalized_id}\n")


def _resolve_parent_interactive(token: str) -> str | None:
    """Return normalized page id, or None if user skipped or quit the parent step."""
    print(
        "Optional: parent page **or database** ID (where new pages will go).\n"
        "You can paste the full Share → Copy link.\n"
        "Enter alone = skip • quit / exit / q = leave this step (session continues)."
    )
    failures = 0
    while True:
        try:
            entered = prompt_line("Parent page ID [Enter to skip]: ")
        except EOFError:
            return None
        if not entered:
            return None
        if entered.lower() in _QUIT_PARENT:
            print(
                "Skipping parent for now — you'll get the save prompt next. "
                "Run `fn connect notion` again anytime.\n"
            )
            return None
        try:
            normalized = parse_page_id_from_user_input(entered)
        except ValueError as e:
            print(f"Couldn't use that as a page id: {e}")
            failures += 1
            if failures >= _GUIDE_EVERY_N_FAILURES:
                _short_parent_guide()
                failures = 0
            print(
                "Try again (or Enter to skip, quit to leave parent step).\n"
            )
            continue
        try:
            _verify_parent_and_print_title(token, normalized)
        except NotionAPIError as e:
            print(
                "Notion could not open that page/database. Is the id correct and the "
                f"integration invited? ({e})"
            )
            failures += 1
            if failures >= _GUIDE_EVERY_N_FAILURES:
                _short_parent_guide()
                failures = 0
            print(
                "Try again (or Enter to skip, quit to leave parent step).\n"
            )
            continue
        return normalized


def _resolve_parent_noninteractive(token: str, raw: str) -> str:
    try:
        normalized = parse_page_id_from_user_input(raw)
    except ValueError as e:
        print(f"Invalid page id: {e}", file=sys.stderr)
        _short_parent_guide()
        raise SystemExit(1) from e
    try:
        _verify_parent_and_print_title(token, normalized)
    except NotionAPIError as e:
        print(
            "Token works, but Notion could not open that page/database, or the id "
            f"is wrong: {e}",
            file=sys.stderr,
        )
        _short_parent_guide()
        raise SystemExit(1) from e
    return normalized


def connect_notion(args: argparse.Namespace) -> None:
    load_dotenv(_env_path(args))

    docs = "https://www.notion.so/my-integrations"
    print(
        "Notion uses an Internal Integration secret (not your Notion password).\n"
        f"Create or open an integration: {docs}\n"
        "Invite that integration to the page or database you want to use "
        "(Share → invite your integration).\n"
    )

    token = (getattr(args, "token", None) or "").strip() or os.environ.get(
        "NOTION_TOKEN", ""
    ).strip()
    tty = sys.stdin.isatty()

    if not token:
        if not tty:
            print(
                "No secret provided. Set NOTION_TOKEN or pass --token.",
                file=sys.stderr,
            )
            raise SystemExit(1)
        print("Paste your Internal Integration Secret (input is hidden; arrow keys work).")
        token = prompt_secret("Notion secret: ")

    if not token:
        print("No secret entered.", file=sys.stderr)
        raise SystemExit(1)

    try:
        me = verify_integration_token(token)
    except NotionAPIError as e:
        print(f"Could not reach Notion or token is invalid: {e}", file=sys.stderr)
        if e.status:
            print(f"(HTTP {e.status})", file=sys.stderr)
        raise SystemExit(1) from e

    name = me.get("name") or me.get("id", "integration")
    print(f"Connected to Notion as: {name}\n")

    arg_parent = (getattr(args, "parent", None) or "").strip()
    env_parent = os.environ.get("NOTION_PARENT_PAGE_ID", "").strip()
    parent_normalized: str | None = None

    interactive_parent = (
        not arg_parent
        and not env_parent
        and tty
        and not getattr(args, "non_interactive", False)
    )

    if interactive_parent:
        parent_normalized = _resolve_parent_interactive(token)
    elif arg_parent or env_parent:
        raw = arg_parent or env_parent
        parent_normalized = _resolve_parent_noninteractive(token, raw)

    env_updates: dict[str, str] = {"NOTION_TOKEN": token}
    if parent_normalized:
        env_updates["NOTION_PARENT_PAGE_ID"] = parent_normalized

    save = getattr(args, "save", False)
    no_save = getattr(args, "no_save", False)
    if save:
        should_save = True
    elif no_save:
        should_save = False
    elif tty and not getattr(args, "non_interactive", False):
        should_save = _prompt_yes_no(
            "Save NOTION_TOKEN (and parent id if any) to .env?",
            True,
        )
        print()
    else:
        should_save = False

    if should_save:
        path = _env_path(args)
        upsert_env(path, env_updates)
        print(f"Saved credentials to {path}")
    else:
        print("Not saving to .env. Set NOTION_TOKEN (and NOTION_PARENT_PAGE_ID) yourself.")
        if parent_normalized:
            print("Parent id was verified; remember to export NOTION_PARENT_PAGE_ID for runs.")

    print("Notion connect finished.")
