// OrgChart — React Flow central view + AgentDrawer + ExecutionsDrawer
// D-01: uses window.jsxRuntime shim (loaded before this script in Dashboard.html)
// D-02: agents grouped heuristically by role/traits into categories

// ── Status → border color ──────────────────────────────────────────────────
const STATUS_COLORS = {
  idle:    '#7BC773',
  running: '#7B9DEC',
  stale:   '#F0B45C',
  error:   '#EE6E6E',
  offline: '#7C8592',
};

const statusColor = (s) => STATUS_COLORS[s] || STATUS_COLORS.idle;

// ── Category heuristic (D-02) ─────────────────────────────────────────────
const deriveCategory = (agent) => {
  const hay = ((agent.role || '') + ' ' + (agent.traits || []).join(' ')).toLowerCase();
  if (/e[-\s]?mail|inbox|gmail/.test(hay))           return 'Inbox';
  if (/briefing|matinal|diário|diario/.test(hay))    return 'Briefing';
  if (/pesquisa|mídia|media|notícia|noticia/.test(hay)) return 'Pesquisa';
  if (/aula|apresenta|slide|powerpoint/.test(hay))   return 'Conteúdo';
  if (/clínico|clinico|onco|paciente/.test(hay))     return 'Clínico';
  return 'Outros';
};

// Category order determines row Y
const CATEGORY_ORDER = ['Briefing', 'Inbox', 'Pesquisa', 'Conteúdo', 'Clínico', 'Outros'];
const EMPTY_AGENTS = [];

// ── Hand-coded dependency edges (D-02 note: future deps from I/O observado) ──
// Format: [sourceId, targetId]
const STATIC_EDGES_RAW = [
  // leader → all category representatives (will be expanded from agents list)
];

// ── Layout helpers ────────────────────────────────────────────────────────
const NODE_W = 200;
const NODE_H = 90;
const H_GAP  = 220;
const V_GAP  = 190;

const buildLayout = (agents) => {
  // Group by category
  const groups = {};
  CATEGORY_ORDER.forEach(c => { groups[c] = []; });
  agents.forEach(a => {
    const cat = deriveCategory(a);
    if (!groups[cat]) groups[cat] = [];
    groups[cat].push(a);
  });

  const nodes = [];
  const edges = [];

  // Leader node
  const totalCols = Math.max(
    ...Object.values(groups).map(g => g.length), 1
  );
  const leaderX = ((totalCols - 1) * H_GAP) / 2;

  nodes.push({
    id: '_leader',
    type: 'agentNode',
    position: { x: leaderX, y: 0 },
    data: {
      id: '_leader',
      name: 'Vinícius',
      role: 'Orquestrador',
      status: 'idle',
      statusLabel: 'Líder',
      photo: null,
      avatarColor: '#B589E0',
      pendingApprovals: 0,
      lastRun: '',
      cadence: null,
      isLeader: true,
      model: 'none',
    },
  });

  let rowIdx = 0;
  CATEGORY_ORDER.forEach(cat => {
    const group = groups[cat];
    if (!group || group.length === 0) return;

    const rowY = (rowIdx + 1) * V_GAP;
    const groupW = (group.length - 1) * H_GAP;
    const startX = leaderX - groupW / 2;

    group.forEach((agent, colIdx) => {
      const x = startX + colIdx * H_GAP;
      nodes.push({
        id: agent.id,
        type: 'agentNode',
        position: { x, y: rowY },
        data: {
          ...agent,
          cadence: null, // enriched externally via crons
        },
      });
      // every agent reports to the leader — no floating nodes
      edges.push({
        id: `_leader->${agent.id}`,
        source: '_leader',
        target: agent.id,
        style: { stroke: '#3A3F4C', strokeWidth: 1.5 },
        animated: false,
      });
    });

    rowIdx++;
  });

  return { nodes, edges };
};

// ── Custom Agent Node ─────────────────────────────────────────────────────
const AgentNode = ({ data, selected }) => {
  const bcolor = statusColor(data.status);
  const FlowHandle = window.ReactFlow && window.ReactFlow.Handle;
  const Badge = window.ModelBadge;
  return (
    <div
      className={'orgchart-node status-' + data.status + (selected ? ' selected' : '')}
      style={{ borderColor: bcolor }}
      title={`status: ${data.status}${data.lastRun ? ' · última: ' + data.lastRun : ''}`}
    >
      {FlowHandle && (
        <>
          <FlowHandle type="target" position="top" style={{ opacity: 0 }} />
          <FlowHandle type="source" position="bottom" style={{ opacity: 0 }} />
        </>
      )}

      {/* Avatar */}
      <div className="orgchart-node-avatar">
        {data.photo ? (
          <img
            src={data.photo}
            alt={data.name}
            style={{ width: 32, height: 32, borderRadius: 8, objectFit: 'cover' }}
            onError={(e) => { e.currentTarget.style.display = 'none'; }}
          />
        ) : (
          <div
            className="avatar"
            style={{
              width: 32, height: 32, fontSize: 11,
              background: data.avatarColor || '#7B9DEC',
              borderRadius: 8,
            }}
          >
            {typeof window.initials === 'function' ? window.initials(data.name) : data.name[0]}
          </div>
        )}
      </div>

      {/* Name + Role */}
      <div className="orgchart-node-info">
        <div className="orgchart-node-name">{data.name}</div>
        {!data.isLeader && Badge && (
          <div className="orgchart-node-model">
            <Badge model={data.model} compact />
          </div>
        )}
        {!data.isLeader && (
          <div className="orgchart-node-cadence">
            {data.cadence || 'on-demand'}
          </div>
        )}
      </div>

      {/* Pending badge */}
      {data.pendingApprovals > 0 && (
        <div className="orgchart-node-pending">{data.pendingApprovals}</div>
      )}
    </div>
  );
};

// Close on Escape — shared by both drawers (must run unconditionally; safe even if onClose is undefined)
const useEscapeToClose = (onClose) => {
  React.useEffect(() => {
    if (typeof onClose !== 'function') return;
    const onKey = (e) => { if (e.key === 'Escape') onClose(); };
    window.addEventListener('keydown', onKey);
    return () => window.removeEventListener('keydown', onKey);
  }, [onClose]);
};

// ── AgentDrawer ───────────────────────────────────────────────────────────
const AgentDrawer = ({ agent, crons, onClose, onToast, onStatClick, onRunAgent, onToggleCron, onDeleteCron, onAddCron, isRunning = false }) => {
  useEscapeToClose(onClose);
  if (!agent) return null;

  const Hero = window.AgentHero;
  const Stats = window.StatStrip;
  const Profiles = window.ProfileCards;
  const Crons = window.CronSection;
  const noop = () => {};

  return (
    <>
      <div
        className="agent-drawer-overlay"
        onClick={onClose}
        role="presentation"
      />
      <div className="agent-drawer" role="dialog" aria-label={'Detalhes: ' + agent.name}>
        <div className="agent-drawer-header">
          <span className="agent-drawer-title">{agent.name}</span>
          <button
            className="icon-btn"
            onClick={onClose}
            title="Fechar"
          >
            <Icon name="x" size={16} />
          </button>
        </div>
        <div className="agent-drawer-body">
          {Hero && (
            <Hero key={agent.id} agent={agent} onRunAgent={onRunAgent} onToast={onToast} isRunning={isRunning} />
          )}
          {Stats && (
            <Stats
              agent={agent}
              onStatClick={onStatClick ? () => onStatClick(agent.id) : undefined}
            />
          )}
          <div className="section">
            {Profiles && <Profiles agent={agent} />}
          </div>
          {Crons && (
            <Crons
              agent={agent}
              crons={crons}
              onToggle={onToggleCron || noop}
              onDelete={onDeleteCron || noop}
              onAdd={onAddCron ? (text, expr) => onAddCron(text, expr, agent.id) : noop}
            />
          )}
        </div>
      </div>
    </>
  );
};

// ── ExecutionsDrawer ──────────────────────────────────────────────────────
const ExecutionsDrawer = ({ agentId, onClose }) => {
  const [rows, setRows] = React.useState(null);
  const [err, setErr] = React.useState(null);

  React.useEffect(() => {
    if (!agentId) return;
    setRows(null);
    setErr(null);
    const tok = localStorage.getItem('hub_token');
    fetch(`/api/v1/agents/${agentId}/executions?limit=50`, {
      headers: { Authorization: `Bearer ${tok}` },
    })
      .then(r => {
        if (!r.ok) throw new Error(r.status);
        return r.json();
      })
      .then(data => setRows(Array.isArray(data) ? data : []))
      .catch(e => setErr('Erro ao carregar execuções: ' + e.message));
  }, [agentId]);

  useEscapeToClose(onClose);

  if (!agentId) return null;

  const relTime = (ms) => {
    if (!ms) return '—';
    if (ms < 1000) return ms + 'ms';
    return (ms / 1000).toFixed(1) + 's';
  };

  return (
    <>
      <div
        className="agent-drawer-overlay"
        onClick={onClose}
        role="presentation"
      />
      <div className="agent-drawer executions-drawer" role="dialog" aria-label="Execuções">
        <div className="agent-drawer-header">
          <span className="agent-drawer-title">Execuções recentes</span>
          <button className="icon-btn" onClick={onClose} title="Fechar">
            <Icon name="x" size={16} />
          </button>
        </div>
        <div className="agent-drawer-body">
          {err && <div style={{ color: 'var(--d-red)', fontSize: 13, padding: 16 }}>{err}</div>}
          {!err && rows === null && (
            <div style={{ color: 'var(--d-fg-3)', fontSize: 13, padding: 16 }}>Carregando...</div>
          )}
          {!err && rows !== null && rows.length === 0 && (
            <div className="card" style={{ textAlign: 'center', color: 'var(--d-fg-3)', padding: 28 }}>
              <div style={{ fontSize: 14, fontWeight: 600, marginBottom: 8 }}>
                Nenhuma execução registrada ainda.
              </div>
              <div style={{ fontSize: 13 }}>
                O audit log está sendo construído — fica disponível em breve.
              </div>
            </div>
          )}
          {!err && rows !== null && rows.length > 0 && (
            <table className="executions-table">
              <thead>
                <tr>
                  <th>Horário</th>
                  <th>Duração</th>
                  <th>Tokens</th>
                  <th>Custo</th>
                  <th>Status</th>
                  <th>Erro</th>
                </tr>
              </thead>
              <tbody>
                {rows.map(r => (
                  <tr key={r.id}>
                    <td title={r.started_at} style={{ fontFamily: 'monospace', fontSize: 12 }}>
                      {r.started_at ? new Date(r.started_at).toLocaleString('pt-BR') : '—'}
                    </td>
                    <td>{relTime(r.duration_ms)}</td>
                    <td>{(r.tokens_in != null || r.tokens_out != null)
                         ? ((r.tokens_in || 0) + (r.tokens_out || 0)).toLocaleString('pt-BR')
                         : '—'}</td>
                    <td>{r.cost_cents != null ? '$' + (r.cost_cents / 100).toFixed(2) : '—'}</td>
                    <td><span className={'pill ' + (r.status || 'idle')}>{r.status || '—'}</span></td>
                    <td style={{ fontSize: 12, color: 'var(--d-fg-3)', maxWidth: 120, overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                      {r.error || '—'}
                    </td>
                  </tr>
                ))}
              </tbody>
            </table>
          )}
        </div>
      </div>
    </>
  );
};

// ── OrgChart (main export) ────────────────────────────────────────────────
const OrgChart = ({ agents, crons, onSelect, setChatScope }) => {
  const RF = window.ReactFlow;
  const safeAgents = Array.isArray(agents) ? agents : EMPTY_AGENTS;

  // Build cadence map from crons
  const cadenceByAgent = React.useMemo(() => {
    const map = {};
    if (!Array.isArray(crons)) return map;
    crons.forEach(c => {
      const aid = c.agentId || c.agent_id;
      if (!aid || !c.enabled) return;
      if (!map[aid]) map[aid] = c.natural || c.expr;
    });
    return map;
  }, [crons]);

  const { nodes: baseNodes, edges } = React.useMemo(() => buildLayout(safeAgents), [safeAgents]);

  // Inject cadence into node data
  const nodes = React.useMemo(() =>
    baseNodes.map(n => ({
      ...n,
      data: {
        ...n.data,
        cadence: cadenceByAgent[n.data.id] || null,
      },
    })), [baseNodes, cadenceByAgent]);

  const nodeTypes = React.useMemo(() => ({ agentNode: AgentNode }), []);

  const onNodeClick = React.useCallback((event, node) => {
    if (node.id === '_leader') return;
    if (typeof onSelect === 'function') onSelect(node.id);
    if (typeof setChatScope === 'function') {
      setChatScope({ type: 'agent', agentId: node.id });
    }
  }, [onSelect, setChatScope]);

  if (safeAgents.length === 0) {
    return (
      <div className="orgchart-wrap orgchart-empty-wrap">
        <div className="dashboard-empty-card">
          <div className="dashboard-empty-kicker">Catálogo vazio</div>
          <h2>Registrar primeiro agente</h2>
          <p>
            Nenhum agente real foi retornado por <code>/api/v1/agents</code>.
            Configure um app com <code>AGENT_HUB_URL</code>, <code>AGENT_HUB_API_KEY</code>
            e <code>AGENT_ID</code>, ou rode o mirror launchd.
          </p>
          <div className="dashboard-empty-actions">
            <code>from agent_hub_sdk import register_agent</code>
          </div>
        </div>
      </div>
    );
  }
  if (!RF) {
    return (
      <div style={{ padding: 40, color: 'var(--d-fg-3)', textAlign: 'center' }}>
        React Flow não carregou. Verifique a conexão com o CDN.
      </div>
    );
  }

  const { ReactFlow, Background, Controls } = RF;

  return (
    <div className="orgchart-wrap">
      <ReactFlow
        nodes={nodes}
        edges={edges}
        nodeTypes={nodeTypes}
        onNodeClick={onNodeClick}
        fitView
        fitViewOptions={{ padding: 0.2 }}
        nodesDraggable={false}
        nodesConnectable={false}
        elementsSelectable={true}
        proOptions={{ hideAttribution: true }}
      >
        <Background color="#2A2F3A" gap={24} />
        <Controls showInteractive={false} />
      </ReactFlow>
    </div>
  );
};

window.OrgChart = OrgChart;
window.AgentDrawer = AgentDrawer;
window.ExecutionsDrawer = ExecutionsDrawer;
