"""复盘自动 K 线:后台线程生成,避免 /add_journal 同步卡住."""

from __future__ import annotations

import logging
import threading
from typing import Any, Callable

logger = logging.getLogger(__name__)


def schedule_journal_exchange_chart(
    *,
    entry_id: str,
    exchange_symbol: str,
    title_prefix: str,
    journal_tfs: list[str],
    journal_limit: int,
    marker_payload: dict[str, Any],
    upload_folder: str,
    generate_chart_fn: Callable[..., str | None],
    get_db_fn: Callable[[], Any],
) -> None:
    """提交后立即返回;线程内画图并写回 journal_entries.image."""
    entry_id = str(entry_id or "").strip()
    if not entry_id or not callable(generate_chart_fn) or not callable(get_db_fn):
        return

    tfs = [str(x).strip() for x in (journal_tfs or []) if str(x).strip()]
    if not tfs:
        return

    def _run() -> None:
        try:
            chart_fname = f"journal_{entry_id}.png"
            saved = generate_chart_fn(
                exchange_symbol,
                title_prefix,
                timeframes=tfs,
                limit=journal_limit,
                out_dir=upload_folder,
                filename=chart_fname,
                filename_prefix="journal",
                marker_payload=marker_payload,
                marker_timeframes={x.lower() for x in tfs},
                layout="vertical",
            )
            if not saved:
                logger.warning("journal chart async empty entry_id=%s", entry_id)
                return
            conn = get_db_fn()
            try:
                conn.execute(
                    "UPDATE journal_entries SET image=? WHERE id=?",
                    (saved, entry_id),
                )
                conn.commit()
            finally:
                conn.close()
        except Exception:
            logger.exception("journal chart async failed entry_id=%s", entry_id)

    threading.Thread(
        target=_run,
        name=f"journal-chart-{entry_id[:8]}",
        daemon=True,
    ).start()


def request_wants_journal_ajax(request: Any) -> bool:
    """XHR / Accept:json / form ajax=1 → 返回 JSON,避免整页刷新."""
    xrw = str(getattr(request, "headers", {}).get("X-Requested-With") or "").lower()
    if xrw == "xmlhttprequest":
        return True
    form = getattr(request, "form", None)
    if form is not None:
        raw = str(form.get("ajax") or "").strip().lower()
        if raw in ("1", "true", "yes", "on"):
            return True
    accept = str(getattr(request, "headers", {}).get("Accept") or "").lower()
    if "application/json" in accept and accept.strip().startswith("application/json"):
        return True
    return False


def journal_ajax_or_flash_error(request: Any, msg: str, *, redirect_fn: Callable[[], Any]):
    """校验失败:AJAX 返回 JSON,否则 flash + 跳转."""
    from flask import flash, jsonify

    if request_wants_journal_ajax(request):
        return jsonify({"ok": False, "msg": msg}), 400
    flash(msg)
    return redirect_fn()
