"""Engagement verification — confirm actions actually landed on LinkedIn.

Provides both immediate (post-send) and batch verification for engagements.
Comments are verified via get_post_comments(), DMs via get_chat_messages().
Reactions are verified via get_post_reactions() (match our account in reactor list).
Follows are verified via check_follow_status() (Voyager followingStates endpoint).
Profile views and endorsements are marked as trust_api (no verification API).
"""

from __future__ import annotations

import asyncio
import logging
import time
from typing import Any

from ..constants import (
    ENGAGEMENT_VERIFY_DELAY_SECONDS,
    TRUST_API,
    UNVERIFIED,
    VERIFIED,
)
from ..db.async_bridge import run_db

logger = logging.getLogger(__name__)


async def verify_comment(
    client: Any,
    account_id: str,
    our_provider_id: str,
    engagement_id: str,
    post_id: str,
    comment_text: str,
) -> dict[str, Any]:
    """Verify a comment was posted by fetching post comments and matching.

    Matches by author_id == our_provider_id. Falls back to substring match
    on the first 80 chars of the comment text if author_id is missing.

    Returns:
        {"verified": bool, "comment_id": str, "error": str}
    """
    from ..db.queries import update_engagement_verification

    result: dict[str, Any] = {"verified": False, "comment_id": "", "error": ""}

    if not post_id or not engagement_id:
        result["error"] = "Missing post_id or engagement_id"
        return result

    try:
        # Brief delay to let LinkedIn propagate the comment
        await asyncio.sleep(ENGAGEMENT_VERIFY_DELAY_SECONDS)

        comments = await client.get_post_comments(account_id, post_id, limit=20)
        if not comments:
            await run_db(update_engagement_verification, engagement_id, UNVERIFIED)
            result["error"] = "No comments returned for post"
            return result

        # Primary match: by author_id
        snippet = comment_text[:80].strip() if comment_text else ""
        for c in comments:
            author_id = c.get("author_id", "")
            if author_id and str(author_id) == str(our_provider_id):
                result["verified"] = True
                result["comment_id"] = c.get("comment_id", "")
                await run_db(
                    update_engagement_verification,
                    engagement_id,
                    VERIFIED,
                    result["comment_id"],
                )
                return result

        # Fallback match: substring on text (if author_id wasn't returned)
        if snippet:
            for c in comments:
                c_text = (c.get("text") or "")[:80].strip()
                if c_text and snippet and snippet in c_text:
                    result["verified"] = True
                    result["comment_id"] = c.get("comment_id", "")
                    await run_db(
                        update_engagement_verification,
                        engagement_id,
                        VERIFIED,
                        result["comment_id"],
                    )
                    return result

        # Not found
        await run_db(update_engagement_verification, engagement_id, UNVERIFIED)
        result["error"] = "Comment not found in post comments"
    except Exception as e:
        logger.debug("verify_comment failed for engagement %s: %s", engagement_id[:8], e)
        result["error"] = str(e)

    return result


async def verify_dm(
    client: Any,
    account_id: str,
    chat_id: str,
    message_text: str,
    sent_at: int,
    outreach_id: str = "",
) -> dict[str, Any]:
    """Verify a DM was sent by fetching chat messages and matching.

    Matches by first 100 chars of text AND timestamp within 300 seconds.

    Returns:
        {"verified": bool, "error": str}
    """
    result: dict[str, Any] = {"verified": False, "error": ""}

    if not chat_id:
        result["error"] = "No chat_id to verify"
        return result

    try:
        await asyncio.sleep(ENGAGEMENT_VERIFY_DELAY_SECONDS)

        messages = await client.get_chat_messages(account_id, chat_id, limit=10)
        if not messages:
            result["error"] = "No messages returned for chat"
            return result

        snippet = message_text[:100].strip() if message_text else ""
        for msg in messages:
            msg_text = (msg.get("text") or "")[:100].strip()
            msg_ts = msg.get("timestamp", 0)
            # Match by text similarity and timestamp proximity (5 min window)
            if snippet and msg_text and snippet in msg_text:
                if not sent_at or not msg_ts or abs(msg_ts - sent_at) < 300:
                    result["verified"] = True
                    return result

        result["error"] = "Message not found in chat history"
    except Exception as e:
        logger.debug("verify_dm failed: %s", e)
        result["error"] = str(e)

    return result


async def mark_trust_api(engagement_id: str) -> None:
    """Mark an engagement as trust_api (no verification API available).

    Used for endorsements and profile views where no verification API exists.
    Reactions and follows now have real verification via verify_reaction/verify_follow.
    """
    if not engagement_id:
        return
    try:
        from ..db.queries import update_engagement_verification

        await run_db(update_engagement_verification, engagement_id, TRUST_API)
    except Exception as e:
        logger.debug("mark_trust_api failed for %s: %s", engagement_id[:8], e)


async def verify_comment_immediate(
    client: Any,
    account_id: str,
    engagement_id: str,
    post_id: str,
    comment_text: str,
) -> None:
    """Convenience wrapper for immediate comment verification after send.

    Resolves our_provider_id from settings and calls verify_comment().
    Silently swallows all errors — never blocks the engagement flow.
    """
    try:
        from ..db.queries import get_setting

        profile = await run_db(get_setting, "profile", {})
        our_provider_id = profile.get("provider_id", "")
        if not our_provider_id:
            logger.debug("verify_comment_immediate: no provider_id in profile")
            return
        await verify_comment(
            client, account_id, our_provider_id,
            engagement_id, post_id, comment_text,
        )
    except Exception as e:
        logger.debug("verify_comment_immediate failed: %s", e)


async def verify_reaction(
    client: Any,
    account_id: str,
    our_provider_id: str,
    engagement_id: str,
    post_id: str,
) -> dict[str, Any]:
    """Verify a reaction was posted by fetching post reactions and matching.

    Matches by author_id == our_provider_id in the reactions list.

    Returns:
        {"verified": bool, "error": str}
    """
    from ..db.queries import update_engagement_verification

    result: dict[str, Any] = {"verified": False, "error": ""}

    if not post_id or not engagement_id:
        result["error"] = "Missing post_id or engagement_id"
        return result

    try:
        # Brief delay to let LinkedIn propagate the reaction
        await asyncio.sleep(ENGAGEMENT_VERIFY_DELAY_SECONDS)

        reactions = await client.get_post_reactions(account_id, post_id, limit=100)
        if not reactions:
            await run_db(update_engagement_verification, engagement_id, UNVERIFIED)
            result["error"] = "No reactions returned for post"
            return result

        # Match by author_id / provider_id
        for r in reactions:
            reactor_id = str(
                r.get("author_id") or r.get("provider_id") or ""
            )
            if reactor_id and reactor_id == str(our_provider_id):
                result["verified"] = True
                await run_db(
                    update_engagement_verification,
                    engagement_id,
                    VERIFIED,
                )
                return result

        # Not found in reactions list
        await run_db(update_engagement_verification, engagement_id, UNVERIFIED)
        result["error"] = "Our account not found in post reactions"
    except Exception as e:
        logger.debug("verify_reaction failed for engagement %s: %s", engagement_id[:8], e)
        result["error"] = str(e)

    return result


async def verify_reaction_immediate(
    client: Any,
    account_id: str,
    engagement_id: str,
    post_id: str,
) -> None:
    """Convenience wrapper for immediate reaction verification after send.

    Resolves our_provider_id from settings and calls verify_reaction().
    Silently swallows all errors — never blocks the engagement flow.
    """
    try:
        from ..db.queries import get_setting

        profile = await run_db(get_setting, "profile", {})
        our_provider_id = profile.get("provider_id", "")
        if not our_provider_id:
            logger.debug("verify_reaction_immediate: no provider_id in profile")
            return
        await verify_reaction(
            client, account_id, our_provider_id,
            engagement_id, post_id,
        )
    except Exception as e:
        logger.debug("verify_reaction_immediate failed: %s", e)


async def verify_follow(
    client: Any,
    account_id: str,
    provider_id: str,
    engagement_id: str,
) -> dict[str, Any]:
    """Verify a follow action by checking the follow status via Voyager.

    Calls check_follow_status() to query LinkedIn's followingStates endpoint.

    Returns:
        {"verified": bool, "error": str}
    """
    from ..db.queries import update_engagement_verification

    result: dict[str, Any] = {"verified": False, "error": ""}

    if not provider_id or not engagement_id:
        result["error"] = "Missing provider_id or engagement_id"
        return result

    try:
        # Brief delay to let LinkedIn propagate the follow
        await asyncio.sleep(ENGAGEMENT_VERIFY_DELAY_SECONDS)

        follow_result = await client.check_follow_status(account_id, provider_id)
        if follow_result.get("following"):
            result["verified"] = True
            await run_db(
                update_engagement_verification,
                engagement_id,
                VERIFIED,
            )
        elif follow_result.get("error"):
            # API error — fall back to trust_api
            await run_db(update_engagement_verification, engagement_id, TRUST_API)
            result["error"] = follow_result["error"]
        else:
            await run_db(update_engagement_verification, engagement_id, UNVERIFIED)
            result["error"] = "Follow not confirmed by LinkedIn"
    except Exception as e:
        logger.debug("verify_follow failed for engagement %s: %s", engagement_id[:8], e)
        result["error"] = str(e)

    return result


async def verify_follow_immediate(
    client: Any,
    account_id: str,
    provider_id: str,
    engagement_id: str,
) -> None:
    """Convenience wrapper for immediate follow verification after send.

    Silently swallows all errors — never blocks the engagement flow.
    """
    try:
        await verify_follow(
            client, account_id, provider_id, engagement_id,
        )
    except Exception as e:
        logger.debug("verify_follow_immediate failed: %s", e)
