from __future__ import annotations

from dataclasses import dataclass
from datetime import datetime, timezone

import eightmem.services.memory_service as memory_service
import eightmem.services.telegram_service as telegram_service
from eightmem.core.governance import create_approval_request, get_approval_request
from eightmem.services.telegram_service import build_telegram_reply_keyboard, process_telegram_message


@dataclass
class _FakeResult:
    model: str = "qwen2.5:14b"
    text: str = "Founder update: Shipping memory improvements this week with concise progress updates."
    text_source: str = "response"
    done: bool = True
    done_reason: str | None = "stop"
    eval_count: int = 12
    eval_duration: int = 123456
    raw: dict | None = None


def test_telegram_remember_updates_user_preferences(fake_home):
    reply = process_telegram_message(user_id="tg-user-1", text="Remember: keep answers short and practical")

    assert reply.action == "save_preference"
    assert reply.memory_updated is True
    exported = memory_service.export_context_text("tg-user-1").lower()
    assert "keep answers short and practical" in exported
    assert "prefers keep answers short and practical" not in exported


def test_telegram_correct_updates_user_corrections(fake_home):
    reply = process_telegram_message(user_id="tg-user-2", text="Correct: don't use emojis")

    assert reply.action == "save_correction"
    assert reply.memory_updated is True
    assert "Updated. I'll use this going forward:" in reply.message
    exported = memory_service.export_context_text("tg-user-2").lower()
    assert "do not use emojis" in exported


def test_telegram_recall_summarizes_saved_memory(fake_home):
    process_telegram_message(user_id="tg-user-3", text="Remember: keep answers concise")
    process_telegram_message(user_id="tg-user-3", text="Correct: don't use long paragraphs")

    reply = process_telegram_message(user_id="tg-user-3", text="What do you know about me")

    assert reply.action == "recall_summary"
    assert "Here's what I know about you:" in reply.message
    assert "Preference: Keep answers concise." in reply.message
    assert "Correction:" in reply.message
    assert reply.reply_keyboard == [["/passport", "/compare"]]


def test_telegram_recall_handles_common_typo_variant(fake_home):
    process_telegram_message(user_id="tg-user-recall-typo", text="Remember: keep answers concise")

    reply = process_telegram_message(user_id="tg-user-recall-typo", text="WHT DO YOU KNOW ABOUT ME")

    assert reply.action == "recall_summary"
    assert "Preference: Keep answers concise." in reply.message


def test_telegram_recall_handles_u_shorthand(fake_home):
    process_telegram_message(user_id="tg-user-recall-u", text="Remember: keep answers concise")

    reply = process_telegram_message(user_id="tg-user-recall-u", text="what do u know about me")

    assert reply.action == "recall_summary"
    assert "Preference: Keep answers concise." in reply.message


def test_telegram_recall_handles_natural_remember_variant(fake_home):
    process_telegram_message(user_id="tg-user-recall-natural", text="Remember: keep answers concise")

    reply = process_telegram_message(user_id="tg-user-recall-natural", text="what do you remember about me")

    assert reply.action == "recall_summary"
    assert "Preference: Keep answers concise." in reply.message


def test_telegram_passport_handles_currently_using_right_now_variant(fake_home):
    process_telegram_message(user_id="tg-user-passport-now", text="Remember: keep answers concise")

    reply = process_telegram_message(user_id="tg-user-passport-now", text="what are you using right now")

    assert reply.action == "memory_passport"
    assert "Here's the memory I'm using for you:" in reply.message


def test_telegram_recent_changes_summary_handles_natural_variant(fake_home):
    process_telegram_message(user_id="tg-user-changes", text="Remember: keep answers concise")
    process_telegram_message(user_id="tg-user-changes", text="Correct: do not use emojis")

    reply = process_telegram_message(user_id="tg-user-changes", text="what changed about me")

    assert reply.action == "recent_changes_summary"
    assert "What changed in your memory:" in reply.message
    assert "Added preference:" in reply.message or "Added communication style:" in reply.message


def test_telegram_corrections_shows_auditable_timeline(fake_home):
    process_telegram_message(user_id="tg-user-corrections-log", text="Remember: use emojis")
    process_telegram_message(user_id="tg-user-corrections-log", text="Correct: do not use emojis")

    reply = process_telegram_message(user_id="tg-user-corrections-log", text="/corrections")

    assert reply.action == "corrections_summary"
    assert "Corrections" in reply.message
    assert 'communication style: "Use emojis." -> "do not use emojis"' in reply.message


def test_telegram_forget_requires_confirmation_and_records_deletion(fake_home):
    process_telegram_message(user_id="tg-user-forget", text="Remember: keep answers concise")

    prompt = process_telegram_message(user_id="tg-user-forget", text="/forget concise")

    assert prompt.action == "forget_memory_confirm"
    assert "Keep answers concise." in prompt.message
    assert prompt.reply_keyboard == [["forget yes", "forget no"]]

    deleted = process_telegram_message(user_id="tg-user-forget", text="forget yes")

    assert deleted.action == "forget_memory_confirmed"
    assert deleted.memory_updated is True
    assert "Keep answers concise." in deleted.message

    recall = process_telegram_message(user_id="tg-user-forget", text="What do you know about me")
    assert "Keep answers concise." not in recall.message

    corrections = process_telegram_message(user_id="tg-user-forget", text="/corrections")
    assert 'deleted "Keep answers concise."' in corrections.message


def test_telegram_correction_trigger_updates_memory_and_asks_for_clarification(fake_home):
    clarification = process_telegram_message(user_id="tg-user-correction-trigger", text="That's wrong")
    assert clarification.action == "correction_clarification"
    assert "What should I replace it with?" in clarification.message

    reply = process_telegram_message(
        user_id="tg-user-correction-trigger",
        text="That's wrong. I prefer short and direct replies",
    )

    assert reply.action == "save_correction"
    assert "I'll use this going forward" in reply.message
    recall = process_telegram_message(user_id="tg-user-correction-trigger", text="What do you know about me")
    assert "Preference: Prefers short and direct replies." in recall.message


def test_telegram_does_not_treat_wrong_question_as_correction(fake_home, monkeypatch):
    monkeypatch.setattr(telegram_service, "generate_memory_aware_reply", lambda *_, **__: "General reply.")

    reply = process_telegram_message(user_id="tg-user-wrong-question", text="What is wrong with my code?")

    assert reply.action == "memory_aware_reply"
    assert reply.message == "General reply."
    corrections = process_telegram_message(user_id="tg-user-wrong-question", text="/corrections")
    assert "No corrections yet." in corrections.message


def test_telegram_actually_only_captures_correction_when_replacement_is_memory_fact(fake_home, monkeypatch):
    monkeypatch.setattr(telegram_service, "generate_memory_aware_reply", lambda *_, **__: "General reply.")

    reply = process_telegram_message(user_id="tg-user-actually-general", text="Actually can you explain the plan?")

    assert reply.action == "memory_aware_reply"
    assert reply.message == "General reply."

    correction = process_telegram_message(
        user_id="tg-user-actually-general",
        text="Actually, I prefer short and direct replies",
    )
    assert correction.action == "save_correction"
    recall = process_telegram_message(user_id="tg-user-actually-general", text="What do you know about me")
    assert "Preference: Prefers short and direct replies." in recall.message


def test_telegram_passport_handles_natural_memory_view_variant(fake_home):
    process_telegram_message(user_id="tg-user-passport-natural", text="Remember: keep answers concise")

    reply = process_telegram_message(user_id="tg-user-passport-natural", text="what are you using about me")

    assert reply.action == "memory_passport"
    assert "Here's the memory I'm using for you:" in reply.message


def test_telegram_passport_summarizes_memory_profile(fake_home):
    process_telegram_message(user_id="tg-user-passport", text="Remember: keep answers concise")
    process_telegram_message(user_id="tg-user-passport", text="Correct: do not use emojis")

    reply = process_telegram_message(user_id="tg-user-passport", text="/passport")

    assert reply.action == "memory_passport"
    assert "Here's the memory I'm using for you:" in reply.message
    assert "Preference: Keep answers concise." in reply.message
    assert "Correction: do not use emojis" in reply.message
    assert "Memory status: Stable" in reply.message
    assert reply.photo_path
    assert reply.photo_path.suffix == ".png"
    assert reply.reply_keyboard == [["/passport", "/compare"]]


def test_telegram_compare_requires_a_prompt(fake_home):
    reply = process_telegram_message(user_id="tg-user-compare-help", text="/compare")

    assert reply.action == "compare_help"
    assert "Want to see the difference your memory makes?" in reply.message
    assert "Compare the normal version with mine: answer this client: Can we move the meeting to Friday?" in reply.message
    assert "/compare Draft: write a founder update in my style" in reply.message


def test_telegram_compare_rejects_vague_prompt_with_examples(fake_home):
    reply = process_telegram_message(user_id="tg-user-compare-vague", text="/compare draft")

    assert reply.action == "compare_help"
    assert "Say something like:" in reply.message
    assert "/compare Draft: write a founder update in my style" in reply.message


def test_telegram_compare_rejects_vague_summarize_prompt_with_examples(fake_home):
    reply = process_telegram_message(user_id="tg-user-compare-vague-summary", text="/compare summarize")

    assert reply.action == "compare_help"
    assert "Reply like me: can we move tomorrow's meeting" in reply.message


def test_telegram_compare_rejects_vague_reply_prompt_with_examples(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-compare-vague-reply",
        text="/compare Reply: answer this client in my style",
    )

    assert reply.action == "compare_help"
    assert "Compare the normal version with mine: answer this client: Can we move the meeting to Friday?" in reply.message


def test_telegram_compare_help_handles_natural_variant(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-compare-natural-help",
        text="show me the difference with memory",
    )

    assert reply.action == "compare_help"
    assert "Want to see the difference your memory makes?" in reply.message


def test_telegram_compare_help_handles_normal_version_vs_mine_variant(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-compare-vs-mine",
        text="show me the normal version vs mine",
    )

    assert reply.action == "compare_help"
    assert "Want to see the difference your memory makes?" in reply.message


def test_telegram_start_shows_first_run_onboarding(fake_home):
    reply = process_telegram_message(user_id="tg-user-start", text="/start")

    assert reply.action == "onboarding_help"
    assert "You can talk to me normally." in reply.message
    assert "Keep my work replies concise" in reply.message
    assert "What do you remember about me?" in reply.message
    assert reply.reply_keyboard is None


def test_telegram_context_setup_shows_structured_capture_template(fake_home):
    reply = process_telegram_message(user_id="tg-user-context-template", text="/context")

    assert reply.action == "onboarding_help"
    assert "Send one message in this format" in reply.message
    assert "Working on:" in reply.message
    assert "Assistants should know:" in reply.message
    assert "Do not assume:" in reply.message
    assert "/v1/context" in reply.message


def test_telegram_approvals_lists_pending_request_with_buttons(fake_home):
    approval = create_approval_request(
        user_id="tg-user-approval-list",
        action_type="email_send",
        summary="Send Phase 1 update to investor",
        payload={"to": "investor@example.com", "subject": "Phase 1 update"},
    )

    reply = process_telegram_message(user_id="tg-user-approval-list", text="/approvals")

    assert reply.action == "approval_list"
    assert "Approval needed" in reply.message
    assert "Action: Send email" in reply.message
    assert "Request: Send Phase 1 update to investor" in reply.message
    assert "- To: investor@example.com" in reply.message
    assert "- Subject: Phase 1 update" in reply.message
    assert reply.reply_keyboard == [
        [
            {"text": "Approve", "callback_data": f"approval:approved:{approval.approval_id}"},
            {"text": "Deny", "callback_data": f"approval:denied:{approval.approval_id}"},
            {"text": "Edit", "callback_data": f"approval:edit:{approval.approval_id}"},
        ],
        [{"text": "Show pending approvals", "callback_data": "/approvals"}],
    ]


def test_telegram_approval_callback_approves_pending_request(fake_home):
    approval = create_approval_request(
        user_id="tg-user-approval-approve",
        action_type="email_send",
        summary="Send investor email",
    )

    reply = process_telegram_message(
        user_id="tg-user-approval-approve",
        text=f"approval:approved:{approval.approval_id}",
    )

    assert reply.action == "approval_resolved"
    assert "Approved: Send email" in reply.message
    assert reply.remove_keyboard is True
    fetched = get_approval_request(approval.approval_id, user_id="tg-user-approval-approve")
    assert fetched is not None
    assert fetched.status == "approved"
    assert fetched.resolved_by == "telegram"


def test_telegram_approval_command_denies_pending_request(fake_home):
    approval = create_approval_request(
        user_id="tg-user-approval-deny",
        action_type="public_post",
        summary="Post launch update",
    )

    reply = process_telegram_message(
        user_id="tg-user-approval-deny",
        text=f"/deny {approval.approval_id}",
    )

    assert reply.action == "approval_resolved"
    assert "Denied: Publish public post" in reply.message
    fetched = get_approval_request(approval.approval_id, user_id="tg-user-approval-deny")
    assert fetched is not None
    assert fetched.status == "denied"


def test_telegram_approval_edit_callback_denies_with_edit_reason(fake_home):
    approval = create_approval_request(
        user_id="tg-user-approval-edit",
        action_type="email_send",
        summary="Send investor email",
    )

    reply = process_telegram_message(
        user_id="tg-user-approval-edit",
        text=f"approval:edit:{approval.approval_id}",
    )

    assert reply.action == "approval_edit_requested"
    assert "What would you like to change?" in reply.message
    fetched = get_approval_request(approval.approval_id, user_id="tg-user-approval-edit")
    assert fetched is not None
    assert fetched.status == "denied"
    assert fetched.reason == "User requested edit"


def test_telegram_memory_candidate_save_callback_commits_proposal(fake_home, monkeypatch):
    notifications: list[tuple[str, str]] = []

    def _fake_notify(event, *, user_id):
        notifications.append((event, user_id))
        return 1

    monkeypatch.setattr(telegram_service, "notify_connectors", _fake_notify)
    proposed = memory_service.create_memory_proposal(
        user_id="tg-user-candidate-save",
        file_name="PREFERENCES.md",
        value="Prefers launch updates grouped as risk, decision, and next step.",
        source="hermes_gateway_candidate",
    )

    reply = process_telegram_message(
        user_id="tg-user-candidate-save",
        text=f"memory_proposal:save:{proposed['proposal']['id']}",
    )

    assert reply.action == "memory_proposal_saved"
    assert reply.message == "Saved."
    assert reply.memory_updated is True
    assert reply.remove_keyboard is True
    assert notifications == [("memory.created", "tg-user-candidate-save")]
    recall = process_telegram_message(user_id="tg-user-candidate-save", text="What do you know about me")
    assert "risk, decision, and next step" in recall.message


def test_telegram_memory_candidate_skip_callback_denies_proposal(fake_home):
    proposed = memory_service.create_memory_proposal(
        user_id="tg-user-candidate-skip",
        file_name="PREFERENCES.md",
        value="Prefers no calls during morning deep-work time.",
        source="hermes_gateway_candidate",
    )

    reply = process_telegram_message(
        user_id="tg-user-candidate-skip",
        text=f"memory_proposal:skip:{proposed['proposal']['id']}",
    )

    assert reply.action == "memory_proposal_skipped"
    assert reply.message == "Skipped."
    assert reply.memory_updated is False
    recall = process_telegram_message(user_id="tg-user-candidate-skip", text="What do you know about me")
    assert "morning deep-work" not in recall.message


def test_telegram_approval_callback_rejects_expired_request(fake_home):
    now = datetime(2020, 1, 1, 8, 0, tzinfo=timezone.utc)
    approval = create_approval_request(
        user_id="tg-user-approval-expired",
        action_type="file_delete",
        summary="Delete local file",
        ttl_seconds=30,
        now=now,
    )

    reply = process_telegram_message(
        user_id="tg-user-approval-expired",
        text=f"approval:approved:{approval.approval_id}",
    )

    assert reply.action == "approval_already_resolved"
    assert "already expired" in reply.message
    assert reply.remove_keyboard is True
    fetched = get_approval_request(approval.approval_id, user_id="tg-user-approval-expired")
    assert fetched is not None
    assert fetched.status == "expired"


def test_telegram_compare_setup_shows_card_readiness_template(fake_home):
    reply = process_telegram_message(user_id="tg-user-compare-setup", text="/compare setup")

    assert reply.action == "onboarding_help"
    assert "To make a strong 8mem Compare card" in reply.message
    assert "paste or edit this as your next message" in reply.message
    assert "Working on:" in reply.message
    assert "Assistants should know:" in reply.message
    assert "Do not assume:" in reply.message
    assert "Communication style:" in reply.message
    assert "/compare Draft: write a founder update in my style" in reply.message


def test_telegram_compare_setup_does_not_make_memory_card_ready_by_itself(fake_home):
    process_telegram_message(user_id="tg-user-compare-setup-only", text="/compare setup")

    reply = process_telegram_message(
        user_id="tg-user-compare-setup-only",
        text="/compare Draft: write a founder update in my style",
    )

    assert reply.action == "compare_guided_capture"
    assert "I need a little more memory before this is worth turning into a share card." in reply.message
    assert "I saved your compare request: Draft: write a founder update in my style" in reply.message
    assert "Reply once with this filled in" in reply.message
    assert reply.photo_path is None


def test_telegram_compare_setup_submission_makes_founder_card_ready(fake_home):
    user_id = "tg-user-compare-setup-submit"
    process_telegram_message(user_id=user_id, text="/compare setup")
    setup = process_telegram_message(
        user_id=user_id,
        text=(
            "Working on: 8mem, an AI memory layer for visible, correctable, portable memory.\n"
            "Assistants should know: I care about execution speed, but not at the cost of stability.\n"
            "Do not assume: I want generic motivational language.\n"
            "Communication style: short, direct, structured as Progress / Risk / Next."
        ),
    )

    reply = process_telegram_message(
        user_id=user_id,
        text="/compare Draft: write a founder update in my style",
    )

    assert setup.action == "context_interview_saved"
    assert "I care about execution speed, but not at the cost of stability" in reply.message
    assert "What changed because of memory:" in reply.message
    assert "Project context: I care about execution speed, but not at the cost of stability" in reply.message
    assert "No share card generated" not in reply.message
    assert reply.photo_path
    assert reply.photo_path.exists()


def test_telegram_weak_compare_guides_capture_then_reruns_automatically(fake_home):
    user_id = "tg-user-compare-auto-guide"
    first = process_telegram_message(
        user_id=user_id,
        text="/compare Draft: write a founder update in my style",
    )

    second = process_telegram_message(
        user_id=user_id,
        text=(
            "Working on: 8mem, an AI memory layer for visible, correctable, portable memory.\n"
            "Assistants should know: I care about execution speed, but not at the cost of stability.\n"
            "Do not assume: I want generic motivational language.\n"
            "Communication style: short, direct, structured as Progress / Risk / Next."
        ),
    )

    assert first.action == "compare_guided_capture"
    assert "I saved your compare request: Draft: write a founder update in my style" in first.message
    assert second.action == "compare_guided_capture_complete"
    assert "Context captured." in second.message
    assert "Rerunning your compare now." in second.message
    assert "8mem Compare" in second.message
    assert "No share card generated" not in second.message
    assert second.photo_path
    assert second.photo_path.exists()


def test_telegram_compare_accepts_copied_transcript_prefix(fake_home):
    user_id = "tg-user-compare-transcript-prefix"
    process_telegram_message(
        user_id=user_id,
        text=(
            "Working on: 8mem, an AI memory layer for visible, correctable, portable memory.\n"
            "Assistants should know: I care about execution speed, but not at the cost of stability.\n"
            "Do not assume: I want generic motivational language.\n"
            "Communication style: short, direct, structured as Progress / Risk / Next."
        ),
    )

    reply = process_telegram_message(
        user_id=user_id,
        text="User: /compare Draft a founder update in my style",
    )

    assert reply.action == "compare_with_memory"
    assert "Want to see the difference" not in reply.message
    assert reply.photo_path
    assert reply.photo_path.exists()


def test_telegram_compare_accepts_bulleted_command_copy(fake_home):
    user_id = "tg-user-compare-bullet-prefix"
    process_telegram_message(
        user_id=user_id,
        text=(
            "Working on: 8mem, an AI memory layer for visible, correctable, portable memory.\n"
            "Assistants should know: I care about execution speed, but not at the cost of stability.\n"
            "Do not assume: I want generic motivational language.\n"
            "Communication style: short, direct, structured as Progress / Risk / Next."
        ),
    )

    reply = process_telegram_message(
        user_id=user_id,
        text="- /compare Draft: write a founder update in my style",
    )

    assert reply.action == "compare_with_memory"
    assert "Want to see the difference" not in reply.message
    assert reply.photo_path


def test_telegram_context_interview_submission_feeds_v1_context(fake_home):
    user_id = "tg-user-context-submit"
    reply = process_telegram_message(
        user_id=user_id,
        text=(
            "Name: Ashish\n"
            "Timezone: Asia/Singapore\n"
            "Working on: 8mem, an AI memory layer for visible, correctable, portable memory\n"
            "Assistants should know: Engram v0.1 is a JSON/context interchange spec, not a vector database\n"
            "Do not assume: Engram is a vector database\n"
            "Communication style: short and direct replies, no emojis"
        ),
    )

    assert reply.action == "context_interview_saved"
    assert reply.memory_updated is True
    assert "Context captured." in reply.message
    assert "Project context: 8mem, an AI memory layer" in reply.message
    assert "Guardrail: Do not assume Engram is a vector database." in reply.message

    context = memory_service.build_engram_context(user_id=user_id)
    injection = context["system_prompt_injection"]
    assert str(context["issued_at"]).endswith("+08:00")
    assert "User is Ashish (Asia/Singapore)." in injection
    assert "Prefers short and direct replies" in injection
    assert "8mem is an AI memory layer" in injection
    assert "Engram v0.1 is an open JSON/context interchange spec" in injection
    assert "not a vector database" in injection
    assert "Do not infer Engram is a vector database" in injection


def test_telegram_help_with_existing_memory_shows_power_tools(fake_home):
    process_telegram_message(user_id="tg-user-help", text="Remember: keep answers concise")

    reply = process_telegram_message(user_id="tg-user-help", text="help")

    assert reply.action == "onboarding_help"
    assert "You can ask normally and I'll use the memory I already have for you." in reply.message
    assert "/passport shows the memory I'm using" in reply.message
    assert reply.reply_keyboard == [["/passport", "/compare"]]


def test_telegram_natural_draft_alias_works(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-natural-draft",
        text="reply like me: can we move tomorrow's meeting",
    )

    assert reply.action == "draft_with_memory"
    assert reply.message


def test_telegram_llm_fallback_can_route_recall(fake_home, monkeypatch):
    process_telegram_message(user_id="tg-user-llm-recall", text="Remember: keep answers concise")
    monkeypatch.setattr(telegram_service, "_classify_llm_intent", lambda *_, **__: "recall")

    reply = process_telegram_message(user_id="tg-user-llm-recall", text="tell me the thing you know from before")

    assert reply.action == "recall_summary"
    assert "Preference: Keep answers concise." in reply.message


def test_telegram_answers_about_8mem_without_personal_recall(fake_home):
    reply = process_telegram_message(user_id="tg-user-about-8mem", text="what do you know about 8mem")

    assert reply.action == "meta_about_8mem"
    assert "memory layer for AI" in reply.message
    assert "Here's what I know about you:" not in reply.message


def test_telegram_answers_memory_layer_question_directly(fake_home):
    reply = process_telegram_message(user_id="tg-user-memory-layer", text="are you memory layer")

    assert reply.action == "meta_memory_layer"
    assert "I'm the memory layer" in reply.message


def test_telegram_answers_model_question_with_active_model(fake_home):
    reply = process_telegram_message(user_id="tg-user-model", text="which model you use", model="qwen2.5:14b")

    assert reply.action == "meta_model_info"
    assert "qwen2.5:14b" in reply.message
    assert "Ollama" in reply.message


def test_telegram_explains_passport_command(fake_home):
    reply = process_telegram_message(user_id="tg-user-passport-explain", text="what is /passport here")

    assert reply.action == "meta_passport_info"
    assert "/passport shows the memory I'm currently using for you" in reply.message


def test_telegram_soft_captures_natural_preference_with_undo(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-soft-pref",
        text="Please keep my work replies concise from now on",
    )

    assert reply.action == "soft_memory_capture"
    assert "I’ll keep my work replies concise from now on." in reply.message
    assert "Saved to memory:" in reply.message
    assert "Keep my work replies concise from now on." in reply.message
    assert "Understood." not in reply.message
    assert reply.reply_keyboard == [["Undo last memory change"], ["/passport", "/compare"]]
    exported = memory_service.export_context_text("tg-user-soft-pref")
    assert "Keep my work replies concise from now on." in exported


def test_telegram_soft_captures_natural_correction_with_undo(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-soft-correction",
        text="Don't use emojis in client messages",
    )

    assert reply.action == "soft_memory_capture"
    assert "I won’t use emojis in client messages." in reply.message
    assert "Saved to memory:" in reply.message
    assert "don't use emojis in client messages" in reply.message.lower()
    assert "Understood." not in reply.message
    assert reply.reply_keyboard == [["Undo last memory change"], ["/passport", "/compare"]]
    recall = process_telegram_message(user_id="tg-user-soft-correction", text="What do you know about me")
    assert "Correction:" in recall.message


def test_telegram_soft_captures_bare_imperative_preference(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-soft-imperative",
        text="Use emojis",
    )

    assert reply.action == "soft_memory_capture"
    assert "I’ll use emojis." in reply.message
    assert "Saved to memory: Use emojis." in reply.message

    recall = process_telegram_message(user_id="tg-user-soft-imperative", text="What do you know about me")
    assert "Preference: Use emojis." in recall.message


def test_telegram_does_not_soft_capture_ambiguous_statement(fake_home, monkeypatch):
    monkeypatch.setattr(telegram_service, "generate_memory_aware_reply", lambda *_, **__: "General reply.")
    reply = process_telegram_message(
        user_id="tg-user-soft-ambiguous",
        text="Sometimes I like long explanations.",
    )

    assert reply.action == "ambiguous_preference_ignored"
    assert reply.message == "Okay. I haven't saved that as a stable preference."

    recall = process_telegram_message(user_id="tg-user-soft-ambiguous", text="What do you know about me")
    assert "I don't have saved memory for you yet." in recall.message


def test_telegram_remember_cleans_old_preference_variants(fake_home):
    process_telegram_message(user_id="tg-user-clean", text="Remember: keep answers concise")
    process_telegram_message(user_id="tg-user-clean", text="Remember: keep answers concise")

    exported = memory_service.export_context_text("tg-user-clean")

    assert "Keep answers concise." in exported
    assert "Prefers keep answers concise." not in exported


def test_telegram_draft_uses_memory_aware_reply(fake_home, monkeypatch):
    monkeypatch.setattr(memory_service, "generate_text", lambda **_: _FakeResult(raw={}))
    process_telegram_message(user_id="tg-user-4", text="Remember: avoid buzzwords")

    reply = process_telegram_message(
        user_id="tg-user-4",
        text="Draft: reply to the investor with a short update",
        model="qwen2.5:14b",
    )

    assert reply.action == "draft_with_memory"
    assert "Founder update:" in reply.message
    assert "## EVOLUTION" not in reply.message


def test_telegram_draft_reschedule_is_shaped_by_memory_controls(fake_home):
    process_telegram_message(
        user_id="tg-user-reschedule-draft",
        text="Please keep my work replies concise from now on",
    )
    process_telegram_message(
        user_id="tg-user-reschedule-draft",
        text="Don't use emojis in client messages",
    )

    reply = process_telegram_message(
        user_id="tg-user-reschedule-draft",
        text="Draft: reply to this client about moving tomorrow's meeting",
    )

    assert reply.action == "draft_with_memory"
    assert reply.message == "Can we move tomorrow's meeting? Share a time that works for you."
    assert "I received your message" not in reply.message
    assert "adjust my calendar" not in reply.message


def test_memory_aware_reply_strips_assistant_filler_when_concise(fake_home, monkeypatch):
    monkeypatch.setattr(
        memory_service,
        "generate_text",
        lambda **_: type(
            "_FakeResult",
            (),
            {
                "text": "I received your message and we can move the meeting to another time. Please suggest a preferred slot, and I'll adjust my calendar accordingly.",
                "text_source": "response",
                "done": True,
                "done_reason": "stop",
                "eval_count": 1,
                "eval_duration": 1,
                "raw": {},
            },
        )(),
    )
    process_telegram_message(
        user_id="tg-user-reschedule-reply",
        text="Please keep my work replies concise from now on",
    )

    reply = memory_service.generate_memory_aware_reply(
        "tg-user-reschedule-reply",
        "reply to this client about moving tomorrow's meeting",
    )

    assert reply == "Can we move tomorrow's meeting? Share a time that works for you."


def test_telegram_compare_shows_generic_and_memory_shaped_founder_update(fake_home):
    process_telegram_message(
        user_id="tg-user-compare-founder",
        text="Remember: I prefer short structured updates with bullets",
    )
    process_telegram_message(
        user_id="tg-user-compare-founder",
        text="Remember: I value execution speed, but not at the cost of stability",
    )
    process_telegram_message(
        user_id="tg-user-compare-founder",
        text="Correct: do not give generic motivational language",
    )

    reply = process_telegram_message(
        user_id="tg-user-compare-founder",
        text="/compare Draft: write a founder update in my style",
    )

    assert reply.action == "compare_with_memory"
    assert "8mem Compare" in reply.message
    assert "Prompt: Draft: write a founder update in my style" in reply.message
    assert "Standard answer:" in reply.message
    assert "Answer shaped by what I know about you:" in reply.message
    assert "What changed because of memory:" in reply.message
    assert "Format: structured bullets" in reply.message
    assert "kept delivery moving without expanding scope" in reply.message
    assert "holding the line on stability" in reply.message
    assert reply.photo_path
    assert reply.photo_path.exists()
    assert reply.reply_keyboard == [["/passport", "/compare"]]


def test_telegram_compare_founder_update_without_style_stays_safe(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-compare-safe-founder",
        text="/compare Draft: write a founder update",
    )

    assert reply.action == "compare_guided_capture"
    assert "I need a little more memory before this is worth turning into a share card." in reply.message
    assert "funding round" not in reply.message.lower()
    assert "marketing campaign" not in reply.message.lower()
    assert "website traffic" not in reply.message.lower()
    assert "Reply once with this filled in" in reply.message
    assert "Communication style: short, direct, structured as Progress / Risk / Next." in reply.message
    assert reply.photo_path is None


def test_telegram_compare_generic_detailed_memory_is_not_card_ready(fake_home):
    process_telegram_message(user_id="tg-user-compare-generic-detailed", text="Remember: give detailed explanations")

    reply = process_telegram_message(
        user_id="tg-user-compare-generic-detailed",
        text="/compare Draft: write a founder update in my style",
    )

    assert reply.action == "compare_guided_capture"
    assert "I need a little more memory before this is worth turning into a share card." in reply.message
    assert "I saved your compare request: Draft: write a founder update in my style" in reply.message
    assert reply.photo_path is None


def test_telegram_compare_reports_when_memory_diff_is_weak(fake_home):
    process_telegram_message(user_id="tg-user-compare-weak", text="Correct: do not use emojis")

    reply = process_telegram_message(
        user_id="tg-user-compare-weak",
        text="/compare Draft: write a founder update in my style",
    )

    assert reply.action == "compare_guided_capture"
    assert "I need a little more memory before this is worth turning into a share card." in reply.message
    assert "Reply once with this filled in" in reply.message
    assert reply.photo_path is None


def test_telegram_compare_founder_update_shows_visible_diff_for_concise_memory(fake_home):
    process_telegram_message(
        user_id="tg-user-compare-concise",
        text="Please keep my work replies concise from now on",
    )

    reply = process_telegram_message(
        user_id="tg-user-compare-concise",
        text="/compare Draft: write a founder update in my style",
    )

    assert reply.action == "compare_with_memory"
    assert "Standard answer:" in reply.message
    assert "Answer shaped by what I know about you:" in reply.message
    assert "What changed because of memory:" in reply.message
    assert "Reply length/style: concise" in reply.message
    assert "- Progress:" in reply.message
    assert "Progress:" in reply.message
    assert "Memory signal is weak" not in reply.message
    assert reply.photo_path
    assert reply.photo_path.exists()


def test_telegram_compare_summarize_uses_clean_english_clarification(fake_home):
    process_telegram_message(
        user_id="tg-user-compare-summary",
        text="Remember: I prefer short structured updates with bullets",
    )
    process_telegram_message(
        user_id="tg-user-compare-summary",
        text="Correct: do not use emojis",
    )

    reply = process_telegram_message(
        user_id="tg-user-compare-summary",
        text="/compare Summarize: summarize this update in my style",
    )

    assert reply.action == "compare_with_memory"
    assert "Standard answer:" in reply.message
    assert "Answer shaped by what I know about you:" in reply.message
    assert "Please send the text or update you want summarized." in reply.message
    assert "I’ll keep it structured and easy to scan." in reply.message
    assert "I’ll avoid emojis." in reply.message
    assert "具体内容" not in reply.message


def test_telegram_reset_memory_clears_user_state(fake_home):
    process_telegram_message(user_id="tg-user-reset", text="Remember: avoid emojis")
    process_telegram_message(user_id="tg-user-reset", text="Correct: do not use long paragraphs")

    reply = process_telegram_message(user_id="tg-user-reset", text="reset memory")

    assert reply.action == "reset_memory"
    recall = process_telegram_message(user_id="tg-user-reset", text="What do you know about me")
    assert "I don't have saved memory for you yet." in recall.message


def test_telegram_multiline_commands_are_processed_independently(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-batch",
        text=(
            "reset memory\n"
            "Remember: I prefer structured weekly plans with clear owners and deadlines\n"
            "Remember: I care about product reliability more than flashy demos\n"
            "Correct: do not assume I want long strategic essays"
        ),
    )

    assert reply.action == "batch_commands"
    recall = process_telegram_message(user_id="tg-user-batch", text="What do you know about me")
    assert "Prefers structured weekly plans with clear owners and deadlines." in recall.message
    assert "Values product reliability more than flashy demos." in recall.message
    assert "Correction: do not assume I want long strategic essays" in recall.message
    assert "Avoid emojis." not in recall.message
    assert "Prefers keep answers concise." not in recall.message


def test_telegram_multiline_commands_ignore_sequence_heading(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-heading",
        text=(
            "Sequence 4\n"
            "reset memory\n"
            "Remember: I like decisions framed as tradeoffs\n"
            "Remember: I want direct answers with explicit risks\n"
            "Correct: do not hide uncertainty"
        ),
    )

    assert reply.action == "batch_commands"
    recall = process_telegram_message(user_id="tg-user-heading", text="What do you know about me")
    assert "Prefers decisions framed as tradeoffs." in recall.message
    assert "Prefers direct answers with explicit risks." in recall.message
    assert "Correction: do not hide uncertainty" in recall.message


def test_telegram_multiline_commands_with_extra_chat_text_still_process_commands(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-mixed",
        text=(
            "reset memory\n"
            "Can you help me later with this too?\n"
            "Remember: keep answers concise\n"
            "Correct: do not use long paragraphs"
        ),
    )

    assert reply.action == "batch_commands"
    assert "Memory reset for this chat user." in reply.message
    assert "Keep answers concise." in reply.message
    assert "do not use long paragraphs" in reply.message
    assert "I skipped one unrelated line in that message." in reply.message

    recall = process_telegram_message(user_id="tg-user-mixed", text="What do you know about me")
    assert "Preference: Keep answers concise." in recall.message
    assert "Correction: do not use long paragraphs" in recall.message


def test_telegram_multiline_batch_processes_natural_memory_capture(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-natural-batch",
        text=(
            "reset memory\n"
            "Please keep my work replies concise from now on\n"
            "What do you know about me\n"
            "/passport"
        ),
    )

    assert reply.action == "batch_commands"
    assert "Memory reset for this chat user." in reply.message
    assert "Saved to memory: Keep my work replies concise from now on." in reply.message
    assert "Preference: Keep my work replies concise from now on." in reply.message
    assert "Memory status: Stable" in reply.message


def test_telegram_multiline_batch_dedupes_duplicate_passport_blocks(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-passport-batch-dedupe",
        text=(
            "reset memory\n"
            "Please keep my work replies concise from now on\n"
            "what are you using about me\n"
            "/passport"
        ),
    )

    assert reply.action == "batch_commands"
    assert reply.message.count("Here's the memory I'm using for you:") == 1


def test_telegram_multiline_batch_preserves_conflict_reply_keyboard(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-batch-keyboard",
        text=(
            "reset memory\n"
            "Remember: use emojis\n"
            "Correct: do not use emojis"
        ),
    )

    assert reply.action == "batch_commands"
    assert 'Updated communication style: "Use emojis" -> "do not use emojis"' in reply.message
    assert reply.reply_keyboard is None


def test_telegram_multiline_batch_natural_preference_and_correction_trigger_conflict(fake_home):
    reply = process_telegram_message(
        user_id="tg-user-natural-conflict",
        text=(
            "reset memory\n"
            "Use emojis\n"
            "Don't use emojis in client messages"
        ),
    )

    assert reply.action == "batch_commands"
    assert "Saved to memory: Use emojis." in reply.message
    assert "Saved to memory: Don't use emojis in client messages." in reply.message
    assert "These two memory notes conflict:" in reply.message
    assert reply.message.count("These two memory notes conflict:") == 1
    assert reply.reply_keyboard == [["Keep no emojis", "Keep emojis"], ["Review later"], ["/passport", "/compare"]]


def test_telegram_recall_surfaces_preference_tension(fake_home):
    process_telegram_message(user_id="tg-user-tension", text="Remember: keep answers concise")
    reply = process_telegram_message(user_id="tg-user-tension", text="Remember: give detailed explanations")

    assert reply.action == "contradiction_prompt"
    assert 'Previous: "Keep answers concise."' in reply.message
    assert 'New: "Give detailed explanations."' in reply.message


def test_telegram_recall_prefers_specific_structured_vs_long_form_tension(fake_home):
    process_telegram_message(
        user_id="tg-user-structured-tension",
        text="Remember: I like short structured updates with bullets",
    )
    reply = process_telegram_message(
        user_id="tg-user-structured-tension",
        text="Remember: give long detailed explanations",
    )

    assert reply.action == "contradiction_prompt"
    assert 'Previous: "Prefers short structured updates with bullets."' in reply.message
    assert 'New: "Give long detailed explanations."' in reply.message


def test_telegram_preference_normalization_preserves_values_statement(fake_home):
    process_telegram_message(
        user_id="tg-user-values",
        text="Remember: I care about product reliability more than flashy demos",
    )

    recall = process_telegram_message(user_id="tg-user-values", text="What do you know about me")

    assert "Values product reliability more than flashy demos." in recall.message
    assert "Prefers Values product reliability more than flashy demos." not in recall.message


def test_telegram_preference_normalization_maps_i_want_to_prefers(fake_home):
    process_telegram_message(
        user_id="tg-user-wants",
        text="Remember: I want direct answers with explicit risks",
    )

    recall = process_telegram_message(user_id="tg-user-wants", text="What do you know about me")

    assert "Prefers direct answers with explicit risks." in recall.message
    assert "Wants direct answers with explicit risks." not in recall.message


def test_telegram_preference_normalization_preserves_directive_give(fake_home):
    process_telegram_message(
        user_id="tg-user-give",
        text="Remember: give detailed explanations",
    )

    recall = process_telegram_message(user_id="tg-user-give", text="What do you know about me")

    assert "Give detailed explanations." in recall.message
    assert "Prefers give detailed explanations." not in recall.message


def test_telegram_preference_normalization_preserves_write_in_directive(fake_home):
    process_telegram_message(
        user_id="tg-user-write-in",
        text="Remember: write in long narrative paragraphs",
    )

    recall = process_telegram_message(user_id="tg-user-write-in", text="What do you know about me")

    assert "Preference: Write in long narrative paragraphs." in recall.message
    assert "Prefers write in long narrative paragraphs." not in recall.message


def test_telegram_recall_surfaces_emoji_tension(fake_home):
    process_telegram_message(user_id="tg-user-emoji-tension", text="Remember: use emojis")
    process_telegram_message(user_id="tg-user-emoji-tension", text="Correct: do not use emojis")

    recall = process_telegram_message(user_id="tg-user-emoji-tension", text="What do you know about me")

    assert "Correction: do not use emojis" in recall.message
    assert "Preference: Use emojis." not in recall.message
    assert "Possible conflict:" not in recall.message


def test_telegram_prompts_for_conflict_resolution_inline_for_emoji_tension(fake_home):
    process_telegram_message(user_id="tg-user-emoji-inline", text="Remember: use emojis")
    reply = process_telegram_message(user_id="tg-user-emoji-inline", text="Correct: do not use emojis")

    assert 'Updated communication style: "Use emojis" -> "do not use emojis"' in reply.message
    assert reply.reply_keyboard is None


def test_telegram_can_resolve_emoji_conflict_inline(fake_home):
    process_telegram_message(user_id="tg-user-emoji-resolve", text="Remember: use emojis")
    process_telegram_message(user_id="tg-user-emoji-resolve", text="Remember: do not use emojis")

    reply = process_telegram_message(user_id="tg-user-emoji-resolve", text="Use new")

    assert reply.action == "resolve_memory_conflict"
    assert "going forward" in reply.message.lower()
    assert "What do you know about me" not in reply.message

    recall = process_telegram_message(user_id="tg-user-emoji-resolve", text="What do you know about me")
    assert "Preference: Use emojis." not in recall.message
    assert "Possible conflict:" not in recall.message
    assert "These two memory notes conflict:" not in recall.message


def test_telegram_resolution_phrase_without_pending_is_not_saved_as_memory(fake_home):
    process_telegram_message(user_id="tg-user-no-pending-resolution", text="Remember: keep answers concise")

    reply = process_telegram_message(user_id="tg-user-no-pending-resolution", text="Use new")

    assert reply.action == "resolve_memory_conflict_missing"
    assert "no memory conflict waiting" in reply.message.lower()
    recall = process_telegram_message(user_id="tg-user-no-pending-resolution", text="What do you know about me")
    assert "Preference: Use new." not in recall.message


def test_telegram_both_true_keeps_pending_old_and_new_values(fake_home):
    process_telegram_message(user_id="tg-user-both-true", text="Remember: I like mornings for admin work")
    prompt = process_telegram_message(user_id="tg-user-both-true", text="Remember: I prefer late-night deep work")

    assert prompt.action == "contradiction_prompt"

    reply = process_telegram_message(user_id="tg-user-both-true", text="Both are true")

    assert reply.action == "resolve_memory_conflict"
    assert "Prefers mornings for admin work." in reply.message
    assert "Prefers late-night deep work." in reply.message

    recall = process_telegram_message(user_id="tg-user-both-true", text="What do you know about me")
    assert "Preference: Prefers mornings for admin work." in recall.message
    assert "Preference: Prefers late-night deep work." in recall.message
    assert "Prefers Both are true." not in recall.message


def test_telegram_can_defer_conflict_resolution_inline(fake_home):
    process_telegram_message(user_id="tg-user-review-later", text="Remember: use emojis")
    process_telegram_message(user_id="tg-user-review-later", text="Correct: do not use emojis")

    reply = process_telegram_message(user_id="tg-user-review-later", text="Review later")

    assert reply.action == "defer_memory_conflict"
    assert "won't change your memory yet" in reply.message.lower()


def test_telegram_can_resolve_concise_vs_detailed_inline(fake_home):
    process_telegram_message(user_id="tg-user-inline-detail", text="Remember: keep answers concise")
    reply = process_telegram_message(user_id="tg-user-inline-detail", text="Remember: give detailed explanations")

    assert reply.action == "contradiction_prompt"
    assert "Which is current?" in reply.message

    resolve = process_telegram_message(user_id="tg-user-inline-detail", text="Keep old")
    assert resolve.action == "resolve_memory_conflict"

    recall = process_telegram_message(user_id="tg-user-inline-detail", text="What do you know about me")
    assert "Preference: Keep answers concise." in recall.message
    assert "Preference: Give detailed explanations." not in recall.message
    assert "These two memory notes conflict:" not in recall.message


def test_telegram_keep_old_copy_has_single_terminal_period(fake_home):
    process_telegram_message(user_id="tg-user-copy-polish", text="Remember: keep answers concise")
    process_telegram_message(user_id="tg-user-copy-polish", text="Remember: give detailed explanations")

    reply = process_telegram_message(user_id="tg-user-copy-polish", text="Keep old")

    assert reply.message == 'Kept the existing memory: "Keep answers concise".'


def test_telegram_detects_location_contradiction_before_write(fake_home):
    process_telegram_message(user_id="tg-user-location-conflict", text="Remember: I live in Singapore")

    reply = process_telegram_message(user_id="tg-user-location-conflict", text="Remember: I live in London")

    assert reply.action == "contradiction_prompt"
    assert 'Previous: "Current location: Singapore."' in reply.message
    assert 'New: "Current location: London."' in reply.message


def test_telegram_detects_timezone_contradiction_before_write(fake_home):
    process_telegram_message(user_id="tg-user-timezone-conflict", text="Remember: timezone UTC+8")

    reply = process_telegram_message(user_id="tg-user-timezone-conflict", text="Remember: timezone UTC+5")

    assert reply.action == "contradiction_prompt"
    assert 'Previous: "Timezone UTC+8."' in reply.message
    assert 'New: "Timezone UTC+5."' in reply.message


def test_telegram_detects_default_tool_contradiction_before_write(fake_home):
    process_telegram_message(user_id="tg-user-tool-conflict", text="Remember: use Python by default")

    reply = process_telegram_message(user_id="tg-user-tool-conflict", text="Remember: use TypeScript by default")

    assert reply.action == "contradiction_prompt"
    assert 'Previous: "Use Python by default."' in reply.message
    assert 'New: "Use TypeScript by default."' in reply.message


def test_telegram_can_resolve_bullets_vs_long_form_inline(fake_home):
    process_telegram_message(
        user_id="tg-user-inline-format",
        text="Remember: I like short structured updates with bullets",
    )
    reply = process_telegram_message(
        user_id="tg-user-inline-format",
        text="Remember: write in long narrative paragraphs",
    )

    assert reply.action == "contradiction_prompt"
    assert "Which is current?" in reply.message

    resolve = process_telegram_message(user_id="tg-user-inline-format", text="Keep old")
    assert resolve.action == "resolve_memory_conflict"

    recall = process_telegram_message(user_id="tg-user-inline-format", text="What do you know about me")
    assert "structured updates with bullets" in recall.message
    assert "Write in long narrative paragraphs." not in recall.message
    assert "These two memory notes conflict:" not in recall.message


def test_telegram_can_resolve_bullets_vs_detailed_explanations_inline(fake_home):
    process_telegram_message(
        user_id="tg-user-inline-format-detailed",
        text="Remember: I prefer short work updates with bullets",
    )
    reply = process_telegram_message(
        user_id="tg-user-inline-format-detailed",
        text="Remember: give detailed explanations",
    )

    assert reply.action == "contradiction_prompt"
    assert reply.reply_keyboard == [["Use new", "Keep old"], ["Both are true", "Review later"]]

    resolve = process_telegram_message(user_id="tg-user-inline-format-detailed", text="Keep old")
    assert resolve.action == "resolve_memory_conflict"
    assert resolve.remove_keyboard is True

    recall = process_telegram_message(user_id="tg-user-inline-format-detailed", text="What do you know about me")
    assert "Preference: Prefers short work updates with bullets." in recall.message
    assert "Preference: Give detailed explanations." not in recall.message
    assert "Possible conflict:" not in recall.message


def test_telegram_recall_does_not_repeat_inline_resolution_prompt(fake_home):
    process_telegram_message(user_id="tg-user-recall-clean", text="Remember: use emojis")
    process_telegram_message(user_id="tg-user-recall-clean", text="Correct: do not use emojis")

    recall = process_telegram_message(user_id="tg-user-recall-clean", text="What do you know about me")

    assert "Possible conflict:" not in recall.message
    assert "Keep no emojis" not in recall.message
    assert "Review later" not in recall.message


def test_build_telegram_reply_keyboard_returns_none_without_conflict(fake_home):
    process_telegram_message(user_id="tg-user-no-keyboard", text="Remember: keep answers concise")

    keyboard = build_telegram_reply_keyboard("tg-user-no-keyboard")

    assert keyboard is None


def test_telegram_recall_does_not_flag_false_long_form_tension_for_do_not_use_long_paragraphs(fake_home):
    process_telegram_message(user_id="tg-user-no-false-tension", text="Remember: keep answers concise")
    process_telegram_message(user_id="tg-user-no-false-tension", text="Correct: do not use long paragraphs")

    recall = process_telegram_message(user_id="tg-user-no-false-tension", text="What do you know about me")

    assert "Preference: Keep answers concise." in recall.message
    assert "Correction: do not use long paragraphs" in recall.message
    assert "Possible conflict: Concise-answer preference may conflict with later long-form guidance." not in recall.message


def test_telegram_draft_strips_generic_preamble(fake_home, monkeypatch):
    monkeypatch.setattr(
        memory_service,
        "generate_text",
        lambda **_: type(
            "_FakeResult",
            (),
            {
                "text": "Here is a short weekly execution update in your style:\n\nThis week we focused on reliability and clear execution.",
                "text_source": "response",
                "done": True,
                "done_reason": "stop",
                "eval_count": 1,
                "eval_duration": 1,
                "raw": {},
            },
        )(),
    )

    reply = process_telegram_message(
        user_id="tg-user-draft-clean",
        text="Draft: write a short weekly execution update in my style",
    )

    assert reply.message == "This week we focused on reliability and clear execution."


def test_telegram_draft_prompt_adds_structured_weekly_hint(fake_home, monkeypatch):
    captured: dict[str, str] = {}

    def _fake_generate_text(**kwargs):
        captured["prompt"] = kwargs["prompt"]
        return type(
            "_FakeResult",
            (),
            {
                "text": "Progress: tightened memory logic.\nRisks: draft quality still being tuned.\nNext: validate Telegram sync.",
                "text_source": "response",
                "done": True,
                "done_reason": "stop",
                "eval_count": 1,
                "eval_duration": 1,
                "raw": {},
            },
        )()

    monkeypatch.setattr(memory_service, "generate_text", _fake_generate_text)
    process_telegram_message(
        user_id="tg-user-hints",
        text="Remember: I prefer structured weekly plans with clear owners and deadlines",
    )
    process_telegram_message(
        user_id="tg-user-hints",
        text="Correct: do not assume I want long strategic essays",
    )

    process_telegram_message(
        user_id="tg-user-hints",
        text="Draft: write a short weekly execution update in my style",
    )

    prompt = captured["prompt"]
    assert "Format preference: prefer a structured layout or bullets when appropriate." in prompt
    assert "For a weekly update, prefer compact bullets covering progress, risks, and next steps." in prompt
    assert "Keep the output compact and practical; avoid strategic-essay tone." in prompt


def test_founder_update_is_shaped_into_bullets_when_user_prefers_structure(fake_home, monkeypatch):
    monkeypatch.setattr(
        memory_service,
        "generate_text",
        lambda **_: type(
            "_FakeResult",
            (),
            {
                "text": "We improved reliability this week. The main risk is slower delivery if testing expands. Next we will tighten release checks.",
                "text_source": "response",
                "done": True,
                "done_reason": "stop",
                "eval_count": 1,
                "eval_duration": 1,
                "raw": {},
            },
        )(),
    )
    process_telegram_message(
        user_id="tg-user-founder-shape",
        text="Remember: I like short structured updates with bullets",
    )

    reply = process_telegram_message(
        user_id="tg-user-founder-shape",
        text="Draft: write a founder update in my style",
    )

    assert reply.message.startswith("- Progress:")
    assert "- Risk:" in reply.message
    assert "- Next:" in reply.message


def test_product_recommendation_is_shaped_into_labeled_bullets(fake_home, monkeypatch):
    monkeypatch.setattr(
        memory_service,
        "generate_text",
        lambda **_: type(
            "_FakeResult",
            (),
            {
                "text": "Use the simpler option first. It gives faster execution but less flexibility. The risk is that you may need to migrate later.",
                "text_source": "response",
                "done": True,
                "done_reason": "stop",
                "eval_count": 1,
                "eval_duration": 1,
                "raw": {},
            },
        )(),
    )

    reply = process_telegram_message(
        user_id="tg-user-reco-shape",
        text="Draft: write a product recommendation in my style",
    )

    assert "- Recommendation:" in reply.message
    assert "- Tradeoff:" in reply.message
    assert "- Risk:" in reply.message


def test_product_recommendation_defaults_to_decision_framework(fake_home, monkeypatch):
    monkeypatch.setattr(
        memory_service,
        "generate_text",
        lambda **_: type(
            "_FakeResult",
            (),
            {
                "text": 'I recommend the "ClearChoice" decision-making tool, which provides direct answers with explicit risks and tradeoffs.',
                "text_source": "response",
                "done": True,
                "done_reason": "stop",
                "eval_count": 1,
                "eval_duration": 1,
                "raw": {},
            },
        )(),
    )
    process_telegram_message(
        user_id="tg-user-reco-grounded",
        text="Remember: I like decisions framed as tradeoffs",
    )
    process_telegram_message(
        user_id="tg-user-reco-grounded",
        text="Remember: I want direct answers with explicit risks",
    )
    process_telegram_message(
        user_id="tg-user-reco-grounded",
        text="Correct: do not hide uncertainty",
    )

    reply = process_telegram_message(
        user_id="tg-user-reco-grounded",
        text="Draft: write a product recommendation in my style",
    )

    assert "ClearChoice" not in reply.message
    assert "decision framework" in reply.message.lower() or "validate" in reply.message.lower()
    assert "- Recommendation:" in reply.message
    assert "product-specific context" in reply.message or "validate" in reply.message


def test_founder_update_rewrites_generic_boilerplate(fake_home, monkeypatch):
    monkeypatch.setattr(
        memory_service,
        "generate_text",
        lambda **_: type(
            "_FakeResult",
            (),
            {
                "text": (
                    "We've made significant progress on our product development, with the core team now fully assembled "
                    "and working towards a Q2 launch. Key technical challenges have been addressed. "
                    "Our financial projections indicate a strong potential for growth."
                ),
                "text_source": "response",
                "done": True,
                "done_reason": "stop",
                "eval_count": 1,
                "eval_duration": 1,
                "raw": {},
            },
        )(),
    )
    process_telegram_message(
        user_id="tg-user-founder-generic",
        text="Remember: I prefer decisions framed with tradeoffs",
    )
    process_telegram_message(
        user_id="tg-user-founder-generic",
        text="Remember: I value execution speed, but not at the cost of stability",
    )
    process_telegram_message(
        user_id="tg-user-founder-generic",
        text="Remember: I like short structured updates with bullets",
    )
    process_telegram_message(
        user_id="tg-user-founder-generic",
        text="Correct: do not give generic motivational language",
    )

    reply = process_telegram_message(
        user_id="tg-user-founder-generic",
        text="Draft: write a founder update in my style",
    )

    assert reply.message.startswith("- Progress:")
    assert "significant progress" not in reply.message.lower()
    assert "q2 launch" not in reply.message.lower()
    assert "speed now versus stability later" in reply.message.lower()


def test_founder_update_in_my_style_uses_grounded_template_without_model_facts(fake_home, monkeypatch):
    monkeypatch.setattr(
        memory_service,
        "generate_text",
        lambda **_: type(
            "_FakeResult",
            (),
            {
                "text": (
                    "- Launched new marketing campaign; increased website traffic by 20%.\n"
                    "- Closed Series A funding round; secured $5M investment.\n"
                    "- Implemented CRM system; improved customer engagement metrics."
                ),
                "text_source": "response",
                "done": True,
                "done_reason": "stop",
                "eval_count": 1,
                "eval_duration": 1,
                "raw": {},
            },
        )(),
    )
    process_telegram_message(
        user_id="tg-user-founder-live-shape",
        text="Remember: I prefer short structured updates with bullets",
    )
    process_telegram_message(
        user_id="tg-user-founder-live-shape",
        text="Remember: I value execution speed, but not at the cost of stability",
    )
    process_telegram_message(
        user_id="tg-user-founder-live-shape",
        text="Correct: do not give generic motivational language",
    )

    reply = process_telegram_message(
        user_id="tg-user-founder-live-shape",
        text="Draft: write a founder update in my style",
    )

    assert reply.message.startswith("- Progress:")
    assert "marketing campaign" not in reply.message.lower()
    assert "series a" not in reply.message.lower()
    assert "crm system" not in reply.message.lower()
    assert "stability" in reply.message.lower()


def test_recommend_laptop_in_my_style_is_treated_as_product_recommendation(fake_home, monkeypatch):
    monkeypatch.setattr(
        memory_service,
        "generate_text",
        lambda **_: type(
            "_FakeResult",
            (),
            {
                "text": (
                    "You prefer direct answers with explicit risks. Given your preferences, I recommend the MacBook Pro "
                    "for its sleek design and powerful performance."
                ),
                "text_source": "response",
                "done": True,
                "done_reason": "stop",
                "eval_count": 1,
                "eval_duration": 1,
                "raw": {},
            },
        )(),
    )
    process_telegram_message(
        user_id="tg-user-laptop-reco",
        text="Remember: I like decisions framed as tradeoffs",
    )
    process_telegram_message(
        user_id="tg-user-laptop-reco",
        text="Remember: I want direct answers with explicit risks",
    )
    process_telegram_message(
        user_id="tg-user-laptop-reco",
        text="Correct: do not hide uncertainty",
    )

    reply = process_telegram_message(
        user_id="tg-user-laptop-reco",
        text="Draft: recommend a laptop in my style",
    )

    assert "- Recommendation:" in reply.message
    assert "- Tradeoff:" in reply.message
    assert "- Risk:" in reply.message
    assert "MacBook Pro" not in reply.message


def test_telegram_draft_handles_backend_unavailable(fake_home, monkeypatch):
    def _boom(*args, **kwargs):
        raise RuntimeError("ollama unavailable")

    monkeypatch.setattr(telegram_service, "generate_memory_aware_draft", _boom)

    reply = process_telegram_message(
        user_id="tg-user-draft-down",
        text="Draft: write a founder update in my style",
    )

    assert reply.action == "draft_backend_unavailable"
    assert "model backend is unavailable" in reply.message.lower()


def test_telegram_reply_handles_backend_unavailable(fake_home, monkeypatch):
    def _boom(*args, **kwargs):
        raise RuntimeError("ollama unavailable")

    monkeypatch.setattr(telegram_service, "generate_memory_aware_reply", _boom)

    reply = process_telegram_message(
        user_id="tg-user-reply-down",
        text="Tell me something useful",
    )

    assert reply.action == "reply_backend_unavailable"
    assert "model backend is unavailable" in reply.message.lower()
