import sys
import re
from pathlib import Path

# Ensure the project root is in sys.path so imports like `from backend import prompt` work
ROOT = Path(__file__).resolve().parents[2]
BACKEND_DIR = ROOT / "backend"
sys.path.insert(0, str(ROOT))
sys.path.insert(0, str(BACKEND_DIR))

from backend import prompt  # type: ignore


def test_get_current_datetime_auto_format():
    s = prompt._get_current_datetime("auto")
    assert isinstance(s, str)
    # Expect a date-like prefix: YYYY-MM-DD
    assert re.match(r"^\d{4}-\d{2}-\d{2}", s)
    # Expect a 3-letter weekday somewhere
    assert re.search(r"\b[A-Za-z]{3}\b", s)
    # Accept either an explicit UTC offset or a UTC label
    assert re.search(r"UTC|[+-]\d{2}:?\d{2}", s)


def test_get_current_datetime_utc_plus5():
    s = prompt._get_current_datetime("UTC+5")
    assert isinstance(s, str)
    assert "UTC+5" in s


def test_get_current_datetime_gmt_minus3():
    s = prompt._get_current_datetime("GMT-3")
    assert isinstance(s, str)
    assert "GMT-3" in s


def test_get_current_datetime_new_york_fallback():
    s = prompt._get_current_datetime("America/New_York")
    assert isinstance(s, str)
    # Fallback behavior: allow either an explicit offset or a simple date prefix
    ok = bool(re.search(r"[+-]\d{2}:?\d{2}", s)) or bool(re.match(r"^\d{4}-\d{2}-\d{2}", s))
    assert ok


def test_sanitize_language_id_empty_none_and_chars():
    # Empty / None should map to markdown by design
    assert prompt._sanitize_language_id("") == "markdown"
    assert prompt._sanitize_language_id(None) == "markdown"
    # Dangerous chars should be stripped
    sanitized = prompt._sanitize_language_id("<script>alert(1)</script>")
    assert "<" not in sanitized and ">" not in sanitized
    # Valid input preserved
    assert prompt._sanitize_language_id("python") == "python"
    # Truncation at 32 chars
    long_input = "a" * 50
    trimmed = prompt._sanitize_language_id(long_input)
    assert len(trimmed) <= 32
    assert trimmed == "a" * min(32, len(long_input))


def test_normalize_newlines():
    mixed = "line1\r\nline2\rline3\n"
    norm = prompt._normalize_newlines(mixed)
    assert norm == "line1\nline2\nline3\n"


def test_canonical_language_id_synonyms_and_unknown():
    assert prompt._canonical_language_id("md") == "markdown"
    assert prompt._canonical_language_id("py") == "python"
    assert prompt._canonical_language_id("js") == "javascript"
    assert prompt._canonical_language_id("ts") == "typescript"
    assert prompt._canonical_language_id("yml") == "yaml"
    assert prompt._canonical_language_id("Rust") == "rust"


def test_language_guidance_behaviors():
    # markdown yields empty guidance
    assert prompt._language_guidance("markdown") == ""
    # mermaid guidance should mention mermaid
    g_mermaid = prompt._language_guidance("mermaid")
    assert isinstance(g_mermaid, str)
    assert "mermaid" in g_mermaid.lower()
    # python / javascript should reference the language
    g_py = prompt._language_guidance("python")
    assert isinstance(g_py, str) and "python" in g_py.lower()
    g_js = prompt._language_guidance("javascript")
    assert isinstance(g_js, str) and "javascript" in g_js.lower()
    # unknown language should return a string as fallback
    g_unknown = prompt._language_guidance("unknownlang")
    assert isinstance(g_unknown, str)


def test_build_inline_system_prompt_templates():
    s_md = prompt.build_inline_system_prompt("markdown")
    assert isinstance(s_md, str) and "markdown" in s_md.lower()
    s_mermaid = prompt.build_inline_system_prompt("mermaid")
    assert isinstance(s_mermaid, str) and "mermaid" in s_mermaid.lower()


def test_prepare_context_strips_br_tags():
    prefix, suffix = prompt._prepare_context("<br>hello<br/>", "world<br />")
    assert "<br" not in prefix
    assert "<br" not in suffix


def test_cursor_and_fence_helpers_basic():
    sample = "```python\nprint('hi')\n"
    assert prompt._cursor_in_fenced_code_block(sample) is True
    assert prompt._cursor_in_fenced_code_block("plain text") is False
    assert prompt._active_fence_language(sample) == "python"
    assert prompt._active_fence_language("plain text") == "none"


def test_is_mermaid_context_detection():
    assert prompt._is_mermaid_context("flowchart TD", "", "none") is True
    assert prompt._is_mermaid_context("```mermaid\n", "\n```", "mermaid") is True
    assert prompt._is_mermaid_context("plain text", "", "none") is False


def test_build_completion_prompts_with_userprefs():
    class UserPrefs:
        language = "python"
        currency = "USD"
        timezone = "UTC+0"
    system, user, prefill = prompt.build_completion_prompts(
        prefix="hello", suffix="world", language_id="markdown",
        preferences=UserPrefs(),
    )
    assert isinstance(system, str)
    assert isinstance(user, str)
    assert prefill == "hello"
    assert "python" in user.lower() or "USD" in user


def test_build_completion_prompts_privacy_mode_location_empty():
    system, user, prefill = prompt.build_completion_prompts(
        prefix="hello", suffix="world", language_id="markdown",
        location="",
    )
    assert isinstance(system, str)
    assert isinstance(user, str)
    assert prefill == "hello"


def test_build_prompt_backward_compatibility():
    res = prompt.build_prompt(prefix="hello", suffix="world", language_id="markdown")
    assert isinstance(res, str)
