import { CodeBlock } from "../components/CodeBlock";
import { Callout } from "../components/Callout";

export function RoutingGuide() {
  return (
    <div>
      <h1 id="routing-rules">Routing Rules Engine</h1>
      <p>
        The routing engine matches incoming AI requests against a prioritized list of rules and
        dispatches them to the appropriate LLM provider. Rules are stored in PostgreSQL (JSONB
        conditions) and cached in memory.
      </p>

      <h2 id="evaluation-order">Evaluation Order</h2>
      <ul>
        <li>Rules are sorted <strong>ascending by priority</strong> (lower number = evaluated first)</li>
        <li><strong>First match wins</strong> — once a rule matches, evaluation stops</li>
        <li>All conditions within a rule are <strong>AND-joined</strong></li>
        <li>An empty <code>conditions</code> array is a <strong>catch-all</strong> that matches everything</li>
      </ul>

      <Callout type="tip" title="Priority design">
        Use gaps between priorities (10, 20, 30, ...) so you can insert rules later without
        renumbering. The catch-all rule should have the highest priority number (e.g. 999).
      </Callout>

      <h2 id="condition-fields">Condition Fields & Operators</h2>
      <div className="overflow-x-auto my-4">
        <table className="w-full text-sm border rounded-lg overflow-hidden">
          <thead>
            <tr className="bg-muted/50 border-b">
              <th className="text-left px-4 py-2.5 font-semibold">Field</th>
              <th className="text-left px-4 py-2.5 font-semibold">Supported Operators</th>
              <th className="text-left px-4 py-2.5 font-semibold">Value Type</th>
            </tr>
          </thead>
          <tbody>
            {[
              { field: "user.role", ops: "eq, neq, in, nin", type: "string" },
              { field: "user.department", ops: "eq, neq, in, nin, contains", type: "string" },
              { field: "request.model", ops: "eq, neq, in, nin", type: "string (model ID)" },
              { field: "request.sensitivity", ops: "eq, neq, gte, lte", type: "low | medium | high" },
              { field: "request.use_case", ops: "eq, neq, contains, matches", type: "string" },
              { field: "request.token_estimate", ops: "gte, lte", type: "integer (token count)" },
            ].map((row) => (
              <tr key={row.field} className="border-b last:border-0">
                <td className="px-4 py-2.5 font-mono text-xs">{row.field}</td>
                <td className="px-4 py-2.5 text-xs text-muted-foreground">{row.ops}</td>
                <td className="px-4 py-2.5 text-xs text-muted-foreground">{row.type}</td>
              </tr>
            ))}
          </tbody>
        </table>
      </div>

      <h2 id="examples">Example Rule Configurations</h2>

      <h3 id="example-department">Route legal department to Anthropic</h3>
      <CodeBlock
        language="json"
        code={`{
  "name": "Legal → Claude",
  "priority": 10,
  "provider": "anthropic",
  "target_model": "claude-3-5-sonnet-20241022",
  "fallback_providers": ["openai"],
  "conditions": [
    {"field": "user.department", "operator": "eq", "value": "legal"}
  ]
}`}
      />

      <h3 id="example-cost-optimize">Cost-optimize small requests</h3>
      <CodeBlock
        language="json"
        code={`{
  "name": "Small requests → GPT-4o-mini",
  "priority": 20,
  "provider": "openai",
  "target_model": "gpt-4o-mini",
  "conditions": [
    {"field": "request.token_estimate", "operator": "lte", "value": "1000"},
    {"field": "request.sensitivity",    "operator": "eq",  "value": "low"}
  ]
}`}
      />

      <h3 id="example-multi-condition">HR department, high-sensitivity requests</h3>
      <CodeBlock
        language="json"
        code={`{
  "name": "HR high-sensitivity → Azure GPT-4",
  "priority": 15,
  "provider": "azure",
  "fallback_providers": ["anthropic", "openai"],
  "conditions": [
    {"field": "user.department", "operator": "eq",  "value": "hr"},
    {"field": "request.sensitivity", "operator": "eq", "value": "high"}
  ]
}`}
      />

      <h3 id="example-catchall">Catch-all fallback</h3>
      <CodeBlock
        language="json"
        code={`{
  "name": "Default → OpenAI GPT-4o",
  "priority": 999,
  "provider": "openai",
  "target_model": "gpt-4o",
  "fallback_providers": ["mistral"],
  "conditions": []
}`}
      />

      <h2 id="fallback-chain">Fallback Chain</h2>
      <p>
        The <code>fallback_providers</code> array defines ordered fallbacks. The routing engine
        tries providers in order:
      </p>
      <ol>
        <li>Check if primary provider's circuit breaker is open → skip if open</li>
        <li>Try primary provider → if error, try next fallback</li>
        <li>Continue through the fallback chain</li>
        <li>If all providers fail → return 503</li>
      </ol>

      <h2 id="caching">Rule Caching</h2>
      <p>
        Rules are loaded from PostgreSQL and cached in memory. The cache is invalidated when a
        rule is created, updated, or deleted via the admin API. You can also force a reload:
      </p>
      <CodeBlock
        language="bash"
        code={`# Restart the proxy to force rule cache reload
# (or wait for the TTL refresh — default 60s)
docker compose restart proxy`}
      />

      <Callout type="info" title="Rule cache TTL">
        The in-memory rule cache refreshes every 60 seconds from PostgreSQL. Admin API changes
        (create/update/delete) invalidate the cache immediately via a shared channel.
      </Callout>
    </div>
  );
}
