
    *i)                     R   d Z ddlmZ ddlZddlZddlmZmZmZm	Z	 ddl
mZmZ ddlmZ  ej                  e      Zej$                  j'                  ej$                  j)                  e      dd      Z ed	d
      ZdadaddZddZddZddZej=                  d       ee      fdd       Zej=                  d       ee      fd d       Z ej=                  d       ee      fd!d       Z!ej=                  d      d"d       Z"edk(  rddl#Z# e#jH                  edd       yy)#u:  
api/royal_dashboard.py
======================
Story 8.04 — Royal Dashboard FastAPI Routes
Story 8.06 — Royal Dashboard FastAPI Static Mount

Routes:
  GET /              — serve Royal Dashboard HTML frontend (Story 8.06)
  GET /status        — live call status (active_calls, swarm_workers, queue_depth)
  GET /calls/recent  — last 10 calls with status, duration, outcome
  GET /workers/active — list of active swarm worker tasks from Redis

All external I/O (Redis, Postgres) is injectable via set_redis_client/set_pg_pool
globals plus FastAPI Depends, making every route fully testable without real
network connections.

Uvicorn entrypoint: port 8766 (separate from Memory API on 8765).

# VERIFICATION_STAMP
# Story: 8.04
# Verified By: parallel-builder
# Verified At: 2026-02-25
# Tests: 9/9
# Coverage: 100%
    )annotationsN)AnyDictListOptional)DependsFastAPI)FileResponse	templateszroyal_dashboard.htmlzRoyal Dashboardz1.0.0)titleversionc                    | a y)z3Inject a Redis-compatible client for use in routes.N_redis_client)clients    ,/mnt/e/genesis-system/api/royal_dashboard.pyset_redis_clientr   :   s	     M    c                    | a y)z4Inject a Postgres-compatible pool for use in routes.N_pg_pool)pools    r   set_pg_poolr   @   s	     Hr   c                     t         S )zBFastAPI dependency: return the current Redis client (may be None).r    r   r   	get_redisr   F   s    r   c                     t         S )zCFastAPI dependency: return the current Postgres pool (may be None).r   r   r   r   get_pgr   K   s    Or   z/statusc                N  K   d}d}d}| p	 | j                  d      }|rt        |      nd}| j                  d      }|rt        |      nd}| j                  d      xs d}| j                  d      xs d}||z   }|||dS # t        $ r t        j                  d       Y &w xY ww)a  
    Return live call status counts.

    Keys returned:
      - active_calls   : number of active call sessions (aiva:state:* keys)
      - swarm_workers  : number of active swarm worker entries (swarm:worker:* keys)
      - queue_depth    : combined LLEN of both bridge queues
    r   zaiva:state:*swarm:worker:*zbridge:queue:aiva_to_genesiszbridge:queue:genesis_to_aivaz%Failed to read live status from Redis)active_callsswarm_workersqueue_depth)keyslenllen	Exceptionlogger	exception)redisr!   r"   r#   
state_keysworker_keysq1q2s           r   get_live_statusr/   T   s      LMK	FN3J.83z?aL  **%56K0;C,M jj!?@EABjj!?@EABr'K %&"   	FDE	Fs)   	B%A/B ;B%B"B%!B""B%z/calls/recentc                  K   | g S 	 | j                  d      }g }|xs g D ]  }|j                  d      }|j                  d      }d}||	 ||z
  j                         }|j	                  |j                  dd      |t        |      nd|t        |      nd||j                  dd      |j                  dd	      d
        |S # t        $ r d}Y sw xY w# t        $ r t        j                  d       g cY S w xY ww)a%  
    Return the last 10 calls from the royal_conversations table.

    Each entry contains:
      - conversation_id
      - started_at     (ISO string or None)
      - ended_at       (ISO string or None)
      - duration_s     (float seconds or None)
      - caller_number
      - outcome
    NzSELECT conversation_id, started_at, ended_at, caller_number, outcome FROM royal_conversations ORDER BY started_at DESC LIMIT 10
started_atended_atconversation_id caller_numberoutcomeunknown)r3   r1   r2   
duration_sr5   r6   z*Failed to fetch recent calls from Postgres)fetchgettotal_secondsr'   appendstrr(   r)   )pgrowsresultsrowstartedendeddurations          r   get_recent_callsrE      s%     
z	xxI
 )+JB 	Cggl+GGGJ'E(,H"u'8$ %>>@H NN'*ww/@"'E292E#g,4.3.?E
T"*%(WW_b%A"wwy)<		&  ! $#H$  EF	sN   C=AC C A%C C=CC CC  C:7C=9C::C=z/workers/activec                  K   | g S 	 | j                  d      }|sg S g }|D ]  }| j                  |      }t        |t              r|j	                  d      n
t        |      }t        |t              r|j	                  d      n|t        |      nd}|j                  |j                  dd      |d        |S # t        $ r t        j                  d       g cY S w xY ww)z
    Return a list of active swarm worker entries from Redis.

    Each entry contains:
      - worker_id  : the part of the key after "swarm:worker:"
      - status     : string value stored at that key
    r    zutf-8r4   zswarm:worker:)	worker_idstatusz)Failed to fetch active workers from Redis)r$   r:   
isinstancebytesdecoder=   r<   replacer'   r(   r)   )r*   r$   workerskeyvalkey_strval_strs          r   get_active_workersrR      s      }	zz*+I(* 	C))C.C-7U-Ccjj)SG c5) 

7# ? X  NN!("!E%	   DE	s3   CB9 CBB9 8C9 CCCC/c                 ,   K   t        t        d      S w)z(Serve the Royal Dashboard HTML frontend.z	text/html)
media_type)r
   TEMPLATE_PATHr   r   r   serve_dashboardrW      s      +>>s   __main__z0.0.0.0i>"  )hostport)r   r   returnNone)r   r   r[   r\   )r[   r   )r*   r   r[   zDict[str, int])r>   r   r[   zList[Dict[str, Any]])r*   r   r[   zList[Dict[str, str]])r[   r
   )%__doc__
__future__r   loggingostypingr   r   r   r   fastapir   r	   fastapi.responsesr
   	getLogger__name__r(   pathjoindirname__file__rV   	dashboardr   r   r   r   r   r   r:   r/   rE   rR   rW   uvicornrunr   r   r   <module>rm      s;  4 #  	 , , $ *			8	$ RWW__X6E[\ +W=	 
 y'.y'9 # #T %,V_ ,  ,f  !*1)*< % "%Z s? ?" zGKK		5 r   