"""
Standalone background worker — the ONE persistent process for the Telegram
listener + forwarding/fixed-message/interaction engines.

This deliberately does NOT run inside Passenger/WSGI (see ``wsgi.py`` for why:
Passenger can spawn multiple worker processes, and this process must be a
singleton). Instead, it's supervised by ``worker_manager.py`` — a small
long-lived process that checks this one every 30 seconds and restarts it on
crash, with a backoff so a persistently failing worker cannot restart-storm the
host. ``cron_keepalive.py`` sits above that purely as a bootstrap, making sure
the manager itself exists.

A PID-file lock (``app/core/proc_lock.py``) guarantees at most one instance is
ever active, even if the cron job overlaps with a still-running previous copy
or is triggered twice in quick succession.

For local/VPS use where you *do* control the whole box, ``run.py`` remains the
simpler single-process entry point (Telegram loop + admin panel together) —
this file is specifically for the shared-hosting split-process deployment.
"""

import os
import sys

try:
    sys.stdout.reconfigure(encoding="utf-8")
    sys.stderr.reconfigure(encoding="utf-8")
except Exception:
    pass

PROJECT_DIR = os.path.dirname(os.path.abspath(__file__))
if PROJECT_DIR not in sys.path:
    sys.path.insert(0, PROJECT_DIR)

LOCK_PATH = os.path.join(PROJECT_DIR, "data", "worker.lock")


def main():
    from app.core import proc_lock

    if not proc_lock.acquire(LOCK_PATH):
        print("[WORKER] Another instance is already running — exiting.")
        return

    try:
        _run()
    finally:
        proc_lock.release(LOCK_PATH)


def _run():
    # ── 1. Initialise database (create tables) ────────────────────────────
    from app.core.database import init_db
    init_db()

    # ── 2. Seed default data on first run ──────────────────────────────────
    from init_app import seed_all
    seed_all()

    # ── 3. Logging ──────────────────────────────────────────────────────────
    from app.core.logger import get_logger, add_db_handler
    add_db_handler()
    logger = get_logger()
    logger.info(f"[WORKER] Starting (pid={os.getpid()})...")

    # This process (not the Passenger/WSGI web process) owns the runtime loop
    # and every long-running engine — see app/core/state.py::mark_engine_process.
    from app.core.state import mark_engine_process, start_heartbeat_thread
    mark_engine_process()

    # Cross-process heartbeat: lets the admin panel (a separate Passenger/WSGI
    # process) tell whether this worker process is actually alive.
    start_heartbeat_thread()

    # ── Audit worker (async queue drain — safe/cheap, one instance is enough
    #    since this process is now the only place that needs it for
    #    background-originated events; the web process still logs its own
    #    request-triggered audit events independently) ─────────────────────
    from app.core import audit
    from app.models import audit_log as al
    audit.start_worker()
    audit.record(module=al.MODULE_SYSTEM, action="startup", severity=al.SEV_INFO,
                 message=f"سرویس پس‌زمینهٔ FinanceGPT راه‌اندازی شد (pid={os.getpid()})")

    # ── Resume account-based forward tasks left active/paused before a
    #    restart (engine control state lives in memory only) ────────────────
    try:
        from app.forwarding.service import ForwardTaskService
        resumed = ForwardTaskService().resume_active()
        if resumed:
            logger.info(f"[WORKER] Resumed {resumed} forward task(s) from previous run")
    except Exception as exc:
        logger.error(f"[WORKER] Failed to resume forward tasks: {exc}")

    # ── Re-arm forward-approval bot pollers so تایید/رد buttons on any
    #    already-sent approval message keep working after a restart (poller
    #    state is in-memory only) ────────────────────────────────────────────
    try:
        from app.services.forward_bot_service import resume_pollers
        fb_resumed = resume_pollers()
        if fb_resumed:
            logger.info(f"[WORKER] Started {fb_resumed} forward-approval bot poller(s)")
    except Exception as exc:
        logger.error(f"[WORKER] Failed to start forward-approval bot pollers: {exc}")

    # ── Resume fixed messages left active/paused before a restart ───────────
    try:
        from app.fixed_messages.service import FixedMessageService
        fm_resumed = FixedMessageService().resume_active()
        if fm_resumed:
            logger.info(f"[WORKER] Resumed {fm_resumed} fixed message(s) from previous run")
    except Exception as exc:
        logger.error(f"[WORKER] Failed to resume fixed messages: {exc}")

    # ── Resume interactions left running/paused before a restart ────────────
    try:
        from app.interactions.service import InteractionService
        inter_resumed = InteractionService().resume_active()
        if inter_resumed:
            logger.info(f"[WORKER] Resumed {inter_resumed} interaction(s) from previous run")
    except Exception as exc:
        logger.error(f"[WORKER] Failed to resume interactions: {exc}")

    # ── Keep fixed messages in sync with admin-panel edits made from the
    #    separate Passenger/WSGI process (which cannot reach this process's
    #    in-memory engine state directly) — polls every few seconds ──────────
    try:
        from app.fixed_messages import engine as fixed_messages_engine
        fixed_messages_engine.start_sync_loop()
    except Exception as exc:
        logger.error(f"[WORKER] Failed to start fixed-message sync loop: {exc}")

    # ── Same cross-process sync, for account-based forward tasks ─────────────
    try:
        from app.forwarding import engine as forwarding_engine
        forwarding_engine.start_sync_loop()
    except Exception as exc:
        logger.error(f"[WORKER] Failed to start forwarding sync loop: {exc}")

    # ── Same cross-process sync, for interactions ────────────────────────────
    try:
        from app.interactions import engine as interactions_engine
        interactions_engine.start_sync_loop()
    except Exception as exc:
        logger.error(f"[WORKER] Failed to start interactions sync loop: {exc}")

    # ── Legacy channel-based Telegram client (asyncio loop, THIS thread) ────
    # Optional and fault-isolated: a failure here (bad/duplicated session,
    # connectivity issues) must never take down the account-based engines
    # started above (fixed messages, forwarding, interactions) — those run
    # independently on TelegramRuntime's own daemon thread. On failure we log
    # and fall back to an idle blocking loop so this process (and therefore
    # the daemon thread) stays alive.
    try:
        from app.services.telegram_service import create_client, run_telegram_service
        from app.core.state import set_telegram_client

        tg_client = create_client()
        set_telegram_client(tg_client)
        logger.info("[WORKER] Telegram client created. Connecting...")

        with tg_client:
            tg_client.loop.run_until_complete(run_telegram_service(tg_client))
    except Exception as exc:
        logger.error(f"[WORKER] Legacy Telegram client failed, continuing without it: {exc}")
        import time
        while True:
            time.sleep(3600)


if __name__ == "__main__":
    main()
