import React, { useState, useEffect, useCallback, useRef } from 'react';
import { createRoot } from 'react-dom/client';
import {
  Button,
  Input,
  CustomSelect,
  Card,
  Badge,
  DataTable,
  Text,
  Alert,
  ConfirmDialog,
  Spinner,
  LoadingIndicator,
  Tabs,
  Switch,
  Checkbox,
  DropdownMenu,
  TextArea,
  Label,
  Separator,
  type Column,
  type SelectOption,
  type TabItem,
  type DropdownMenuItem,
} from '@alga-psa/ui-kit';

// ============================================================================
// Theme Bridge - Receives theme from host app and applies CSS variables
// ============================================================================

/**
 * Apply theme variables to the document root
 */
function applyTheme(vars: Record<string, string>) {
  if (typeof document === 'undefined') return;
  const root = document.documentElement;
  Object.entries(vars).forEach(([key, value]) => {
    root.style.setProperty(key, value);
  });
}

/**
 * Get the parent origin for postMessage
 */
function getParentOrigin(): string {
  const params = new URLSearchParams(window.location.search);
  const parentOrigin = params.get('parentOrigin');
  if (parentOrigin) return parentOrigin;

  if (document.referrer) {
    try {
      return new URL(document.referrer).origin;
    } catch {
      // Invalid referrer
    }
  }
  return '*';
}

/**
 * Send ready message to parent and set up theme listener
 */
function initializeThemeBridge() {
  const parentOrigin = getParentOrigin();

  // Listen for theme messages from parent
  const handleMessage = (ev: MessageEvent) => {
    const data = ev.data;
    if (!data || typeof data !== 'object') return;

    // Check for Alga envelope format with theme message
    if (data.alga === true && data.version === '1' && data.type === 'theme') {
      console.log('[Extension] Received theme from host:', data.payload);
      applyTheme(data.payload || {});
    }
  };

  window.addEventListener('message', handleMessage);

  // Send ready message to parent so it knows to send theme
  window.parent.postMessage(
    { alga: true, version: '1', type: 'ready' },
    parentOrigin
  );

  console.log('[Extension] Sent ready message to parent:', parentOrigin);

  return () => window.removeEventListener('message', handleMessage);
}

// Initialize theme bridge on load
if (typeof window !== 'undefined') {
  initializeThemeBridge();
}

// ============================================================================
// Extension Proxy Bridge - Calls WASM handler via ext-proxy
// ============================================================================

const ENVELOPE_VERSION = '1';

/**
 * IframeBridge for calling the extension's WASM handler via postMessage.
 * The host's iframeBridge handles 'apiproxy' messages and forwards them to ext-proxy.
 */
class IframeBridge {
  private listeners: Map<string, (data: any) => void> = new Map();
  private parentOrigin: string;

  constructor() {
    this.parentOrigin = getParentOrigin();

    // Listen for responses from host
    window.addEventListener('message', (ev: MessageEvent) => {
      const data = ev.data;
      if (!data || typeof data !== 'object') return;
      if (data.alga !== true || data.version !== ENVELOPE_VERSION) return;

      // Handle apiproxy responses
      if (data.type === 'apiproxy_response' && data.request_id) {
        const listener = this.listeners.get(data.request_id);
        if (listener) {
          this.listeners.delete(data.request_id);
          listener(data);
        }
      }
    });
  }

  /**
   * Call the extension's WASM handler via the proxy.
   * The route is relative to the extension's handler (e.g., '/reports', '/schema').
   */
  async callProxy<T>(route: string, payload?: Uint8Array | null, options?: { method?: string }): Promise<T> {
    return new Promise((resolve, reject) => {
      const requestId = crypto.randomUUID();

      // Set up listener for response
      const timeoutId = setTimeout(() => {
        this.listeners.delete(requestId);
        reject(new Error('Proxy request timed out'));
      }, 30000);

      this.listeners.set(requestId, (data) => {
        clearTimeout(timeoutId);
        if (data.payload?.error) {
          reject(new Error(data.payload.error));
        } else if (data.payload?.body) {
          // Decode base64 response body
          try {
            const binaryString = atob(data.payload.body);
            const bytes = new Uint8Array(binaryString.length);
            for (let i = 0; i < binaryString.length; i++) {
              bytes[i] = binaryString.charCodeAt(i);
            }
            const text = new TextDecoder().decode(bytes);
            resolve(JSON.parse(text));
          } catch (e) {
            reject(new Error('Failed to decode proxy response'));
          }
        } else {
          resolve(data.payload as T);
        }
      });

      // Encode payload to base64 if present
      let bodyBase64: string | undefined;
      if (payload) {
        let binaryString = '';
        for (let i = 0; i < payload.length; i++) {
          binaryString += String.fromCharCode(payload[i]);
        }
        bodyBase64 = btoa(binaryString);
      }

      // Send apiproxy message to host
      window.parent.postMessage(
        {
          alga: true,
          version: ENVELOPE_VERSION,
          type: 'apiproxy',
          request_id: requestId,
          payload: {
            route,
            body: bodyBase64,
            // Only include method when non-POST to preserve backward compatibility
            // with deployed iframeBridge versions
            ...(options?.method && options.method !== 'POST' ? { method: options.method } : {}),
          },
        },
        this.parentOrigin
      );
    });
  }
}

// Initialize bridge
const bridge = new IframeBridge();

/**
 * Map internal API paths to WASM handler routes.
 * e.g., '/api/v1/platform-reports' -> '/reports'
 *       '/api/v1/platform-reports/schema' -> '/schema'
 */
function mapApiPathToHandlerRoute(path: string): string {
  // Remove the /api/v1/platform-reports prefix if present
  const prefix = '/api/v1/platform-reports';
  if (path.startsWith(prefix)) {
    const suffix = path.slice(prefix.length);
    if (suffix === '' || suffix === '/') {
      return '/reports';
    }
    if (suffix === '/schema') {
      return '/schema';
    }
    if (suffix === '/access') {
      return '/access';
    }
    if (suffix === '/audit' || suffix.startsWith('/audit?')) {
      return suffix; // Keep audit path as-is
    }
    // For report-specific routes like /report-id, /report-id/execute
    return `/reports${suffix}`;
  }

  // Handle feature flags prefix
  const ffPrefix = '/api/v1/platform-feature-flags';
  if (path.startsWith(ffPrefix)) {
    const suffix = path.slice(ffPrefix.length);
    if (suffix === '' || suffix === '/') {
      return '/feature-flags';
    }
    return `/feature-flags${suffix}`;
  }

  // Handle platform notifications prefix
  const notifPrefix = '/api/v1/platform-notifications';
  if (path.startsWith(notifPrefix)) {
    const suffix = path.slice(notifPrefix.length);
    if (suffix === '' || suffix === '/') {
      return '/notifications';
    }
    return `/notifications${suffix}`;
  }

  // Return as-is if it doesn't match the expected prefix
  return path;
}

/**
 * Call the WASM handler via the extension proxy.
 * This is the proper pattern: UI -> postMessage -> iframeBridge -> ext-proxy -> Runner -> WASM handler
 *
 * The deployed iframeBridge always sends POST regardless of the method field in postMessage.
 * We use two mechanisms to convey the intended HTTP method:
 * 1. __method query param: The ext-proxy reads this and overrides the POST method before
 *    forwarding to the runner. This ensures the WASM handler sees the correct HTTP method.
 * 2. __action body field: Legacy disambiguation for operations on the same path.
 */
async function proxyApiCall<T>(
  route: string,
  options?: { method?: string; body?: unknown }
): Promise<T> {
  // Map the internal API path to the WASM handler route
  const handlerRoute = mapApiPathToHandlerRoute(route);
  const method = options?.method?.toUpperCase() || 'GET';

  // For GET requests, append __method=GET to the query string so the ext-proxy
  // converts the POST (forced by iframeBridge) into GET.
  // DELETE/PUT continue to use the __action body field for disambiguation.
  let finalRoute = handlerRoute;
  if (method === 'GET') {
    const separator = handlerRoute.includes('?') ? '&' : '?';
    finalRoute = `${handlerRoute}${separator}__method=${method}`;
  }

  // Build the body with __action field for non-GET methods
  let bodyData: Record<string, unknown> | undefined;

  if (options?.body && typeof options.body === 'object') {
    bodyData = { ...(options.body as Record<string, unknown>) };
  }

  // Add __action field for methods that need disambiguation
  if (method === 'DELETE') {
    bodyData = bodyData || {};
    bodyData.__action = 'delete';
  } else if (method === 'PUT') {
    bodyData = bodyData || {};
    bodyData.__action = 'update';
  } else if (method === 'POST' && handlerRoute === '/reports') {
    bodyData = bodyData || {};
    bodyData.__action = 'create';
  } else if (method === 'POST' && handlerRoute === '/feature-flags') {
    bodyData = bodyData || {};
    bodyData.__action = 'create';
  } else if (method === 'POST' && handlerRoute === '/notifications') {
    bodyData = bodyData || {};
    bodyData.__action = 'create';
  }

  // Encode body if present
  let payload: Uint8Array | undefined;
  if (bodyData) {
    const bodyJson = JSON.stringify(bodyData);
    payload = new TextEncoder().encode(bodyJson);
  }

  console.log('[Extension] Calling proxy:', { route, handlerRoute: finalRoute, method, hasBody: !!payload });

  try {
    const result = await bridge.callProxy<T>(finalRoute, payload, { method });
    console.log('[Extension] Proxy response:', result);
    return result;
  } catch (error) {
    console.error('[Extension] Proxy call failed:', error);
    throw error;
  }
}

// ============================================================================
// Types
// ============================================================================

// Types
interface PlatformReport {
  report_id: string;
  name: string;
  description: string | null;
  category: string | null;
  report_definition: ReportDefinition;
  is_active: boolean;
  created_at: string;
  updated_at: string;
}

interface ReportDefinition {
  id?: string;
  name?: string;
  description?: string;
  category?: string;
  version?: string;
  metrics: MetricDefinition[];
  permissions?: {
    roles?: string[];
    resources?: string[];
  };
}

interface ConditionalLabel {
  column: string;
  operator: 'lt' | 'gt' | 'lte' | 'gte' | 'eq';
  value: number;
  tone: 'danger' | 'warning' | 'success' | 'info';
  label?: string;
}

interface MetricDefinition {
  id: string;
  name: string;
  type: 'count' | 'sum' | 'avg' | 'query';
  query: QueryDefinition;
  conditionalLabels?: ConditionalLabel[];
}

interface QueryDefinition {
  table: string;
  fields: string[];
  filters?: FilterDefinition[];
  joins?: JoinDefinition[];
  groupBy?: string[];
  orderBy?: OrderByDefinition[];
  limit?: number;
}

interface FilterDefinition {
  field: string;
  operator: 'eq' | 'neq' | 'gt' | 'gte' | 'lt' | 'lte' | 'like' | 'in';
  value: unknown;
}

interface OrderByDefinition {
  field: string;
  direction: 'asc' | 'desc';
}

type JoinType = 'inner' | 'left' | 'right' | 'full';

interface JoinCondition {
  left: string;
  right: string;
  operator?: string;
}

interface JoinDefinition {
  type: JoinType;
  table: string;
  on: JoinCondition[];
}

interface ApiResponse<T> {
  success: boolean;
  error?: string;
  data?: T;
}

// Audit log types - matches extension_audit_logs table
interface AuditLogEntry {
  log_id: string;
  tenant: string;
  event_type: string;
  user_id: string | null;
  user_email: string | null;
  resource_type: 'report' | 'tenant' | 'user' | 'subscription' | 'notification' | null;
  resource_id: string | null;
  resource_name: string | null;
  workflow_id: string | null;
  status: 'pending' | 'completed' | 'failed' | 'running' | null;
  error_message: string | null;
  details: Record<string, unknown> | null;
  ip_address: string | null;
  user_agent: string | null;
  created_at: string;
}

// Get host origin from referrer (the main app that embeds this iframe)
function getHostOrigin(): string {
  // Priority: URL param > referrer > current origin
  const params = new URLSearchParams(window.location.search);
  const hostParam = params.get('host');
  if (hostParam) {
    return hostParam;
  }

  // Use referrer (the page that embedded this iframe)
  if (document.referrer) {
    try {
      const referrerUrl = new URL(document.referrer);
      return referrerUrl.origin;
    } catch {
      // Invalid referrer URL
    }
  }

  // Fallback to current origin (won't work for cross-origin iframes)
  return window.location.origin;
}

// API client that calls the platform API through the internal proxy
// Uses postMessage to avoid CORS issues with cross-origin iframes
async function callExtensionApi<T>(path: string, options: RequestInit = {}): Promise<ApiResponse<T>> {
  const route = `/api/v1/platform-reports${path}`;

  try {
    // Parse body from options if present
    let body: any = undefined;
    if (options.body && typeof options.body === 'string') {
      try {
        body = JSON.parse(options.body);
      } catch {
        body = options.body;
      }
    }

    const result = await proxyApiCall<any>(route, {
      method: options.method as string || 'GET',
      body,
    });

    // Normalize response format
    if (result && typeof result === 'object') {
      if ('success' in result) {
        return result as ApiResponse<T>;
      }
      // If response has 'data' field, it's already the expected format
      if ('data' in result) {
        return { success: true, data: result.data as T };
      }
      return { success: true, data: result as T };
    }
    return { success: true, data: result as T };
  } catch (error) {
    console.error('API call failed:', error);
    return { success: false, error: String(error) };
  }
}

// API client for feature flag endpoints
async function callFeatureFlagApi<T>(
  path: string,
  options: RequestInit = {}
): Promise<ApiResponse<T>> {
  const route = `/api/v1/platform-feature-flags${path}`;

  try {
    let body: any = undefined;
    if (options.body && typeof options.body === 'string') {
      try {
        body = JSON.parse(options.body);
      } catch {
        body = options.body;
      }
    }

    const result = await proxyApiCall<any>(route, {
      method: options.method as string || 'GET',
      body,
    });

    if (result && typeof result === 'object') {
      if ('success' in result) {
        return result as ApiResponse<T>;
      }
      if ('data' in result) {
        return { success: true, data: result.data as T };
      }
      return { success: true, data: result as T };
    }
    return { success: true, data: result as T };
  } catch (error) {
    console.error('Feature Flag API call failed:', error);
    return { success: false, error: String(error) };
  }
}

// API client for platform notification endpoints
async function callNotificationApi<T>(
  path: string,
  options: RequestInit = {}
): Promise<ApiResponse<T>> {
  const route = `/api/v1/platform-notifications${path}`;

  try {
    let body: any = undefined;
    if (options.body && typeof options.body === 'string') {
      try {
        body = JSON.parse(options.body);
      } catch {
        body = options.body;
      }
    }

    const result = await proxyApiCall<any>(route, {
      method: options.method as string || 'GET',
      body,
    });

    if (result && typeof result === 'object') {
      if ('success' in result) {
        return result as ApiResponse<T>;
      }
      if ('data' in result) {
        return { success: true, data: result.data as T };
      }
      return { success: true, data: result as T };
    }
    return { success: true, data: result as T };
  } catch (error) {
    console.error('Notification API call failed:', error);
    return { success: false, error: String(error) };
  }
}

// Audit logger for feature flag actions
async function logFeatureFlagAudit(
  action: string,
  details: Record<string, unknown>
) {
  try {
    await proxyApiCall('/api/v1/platform-reports/access', {
      method: 'POST',
      body: {
        eventType: `feature_flag.${action}`,
        resourceType: 'feature_flag',
        ...details,
      },
    });
  } catch {
    // Silently fail - audit logging shouldn't break the app
    console.debug('[nineminds-control-panel] Failed to log feature flag audit:', action);
  }
}

// ============================================================================
// PostHog Feature Flag Types
// ============================================================================

interface PostHogFlagProperty {
  key: string;
  type: string;
  value: string[];
  operator: string;
}

interface PostHogFlagGroup {
  properties: PostHogFlagProperty[];
  rollout_percentage: number | null;
  variant: string | null;
}

interface PostHogFeatureFlag {
  id: number;
  key: string;
  name: string;
  active: boolean;
  filters: {
    groups: PostHogFlagGroup[];
    multivariate: {
      variants: { key: string; rollout_percentage: number }[];
    } | null;
  };
  created_at: string;
  tags: string[];
}

// ============================================================================
// Dynamic Schema - Fetched from server (blocklist-filtered)
// ============================================================================

interface TableSchema {
  name: string;
  columns: string[];
}

interface SchemaResponse {
  tables: TableSchema[];
}

// Schema cache to avoid refetching
let schemaCache: TableSchema[] | null = null;
let schemaPromise: Promise<TableSchema[]> | null = null;

/**
 * Fetch available tables and columns from the server.
 * The server filters the schema using a blocklist for security.
 * Uses the internal proxy to avoid CORS issues.
 */
async function fetchSchema(): Promise<TableSchema[]> {
  if (schemaCache) {
    return schemaCache;
  }

  if (schemaPromise) {
    return schemaPromise;
  }

  schemaPromise = (async () => {
    try {
      const result = await proxyApiCall<any>('/api/v1/platform-reports/schema');

      // Handle the response format from proxy
      const data = result?.data || result;
      if (data?.tables) {
        schemaCache = data.tables;
        return data.tables as TableSchema[];
      }

      if (result?.success === false) {
        console.error('[Schema] Failed to fetch:', result.error);
        return [];
      }

      console.error('[Schema] Unexpected response format:', result);
      return [];
    } catch (error) {
      console.error('[Schema] Fetch error:', error);
      return [];
    }
  })();

  return schemaPromise!;
}

/**
 * Hook to load and use the dynamic schema
 */
function useSchema() {
  const [tables, setTables] = useState<TableSchema[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);

  useEffect(() => {
    fetchSchema()
      .then(schema => {
        setTables(schema);
        setLoading(false);
      })
      .catch(err => {
        setError(String(err));
        setLoading(false);
      });
  }, []);

  const getTableColumns = useCallback((tableName: string): string[] => {
    const table = tables.find(t => t.name === tableName);
    return table?.columns || [];
  }, [tables]);

  const tableOptions: SelectOption[] = tables.map(t => ({
    value: t.name,
    label: t.name.replace(/_/g, ' ').replace(/\b\w/g, c => c.toUpperCase()),
  }));

  return { tables, tableOptions, getTableColumns, loading, error };
}

/**
 * Hook to load existing categories from reports
 */
function useCategories() {
  const [categories, setCategories] = useState<string[]>([]);
  const [loading, setLoading] = useState(true);

  useEffect(() => {
    async function fetchCategories() {
      try {
        const result = await callExtensionApi<PlatformReport[]>('');
        if (result.success && result.data) {
          // Extract distinct non-empty categories using Set for deduplication
          const allCategories = result.data
            .map(r => r.category)
            .filter((c): c is string => !!c && c.trim() !== '');
          const distinctCategories = Array.from(new Set(allCategories)).sort();
          setCategories(distinctCategories);
        }
      } catch (error) {
        console.error('[Categories] Fetch error:', error);
      }
      setLoading(false);
    }
    fetchCategories();
  }, []);

  return { categories, loading };
}

/**
 * Category selector component - allows selecting existing or adding new
 */
function CategorySelect({
  value,
  onChange,
}: {
  value: string;
  onChange: (value: string) => void;
}) {
  const { categories, loading } = useCategories();
  const [isAddingNew, setIsAddingNew] = useState(false);
  const [newCategory, setNewCategory] = useState('');

  // Check if current value is a custom one (not in the list)
  const isCustomValue = value && !categories.includes(value);

  const handleSelectChange = (selected: string) => {
    if (selected === '__new__') {
      setIsAddingNew(true);
      setNewCategory('');
    } else if (selected === '__none__') {
      setIsAddingNew(false);
      onChange('');  // Convert __none__ back to empty string
    } else {
      setIsAddingNew(false);
      onChange(selected);
    }
  };

  const handleNewCategoryConfirm = () => {
    if (newCategory.trim()) {
      onChange(newCategory.trim());
      setIsAddingNew(false);
    }
  };

  const handleNewCategoryCancel = () => {
    setIsAddingNew(false);
    setNewCategory('');
  };

  if (loading) {
    return <LoadingIndicator size="sm" text="Loading categories..." />;
  }

  if (isAddingNew) {
    return (
      <div style={{ display: 'flex', gap: '8px' }}>
        <Input
          type="text"
          value={newCategory}
          onChange={(e) => setNewCategory(e.target.value)}
          placeholder="Enter new category name..."
          style={{ flex: 1 }}
          autoFocus
          onKeyDown={(e) => {
            if (e.key === 'Enter') {
              e.preventDefault();
              handleNewCategoryConfirm();
            } else if (e.key === 'Escape') {
              handleNewCategoryCancel();
            }
          }}
        />
        <Button type="button" variant="primary" onClick={handleNewCategoryConfirm} disabled={!newCategory.trim()}>
          Add
        </Button>
        <Button type="button" variant="ghost" onClick={handleNewCategoryCancel}>
          Cancel
        </Button>
      </div>
    );
  }

  // Build options: existing categories + "Add new..."
  const options: SelectOption[] = [
    { value: '__none__', label: 'No category' },
    ...categories.map(c => ({ value: c, label: c })),
    // If current value is custom (not in list), add it as an option
    ...(isCustomValue ? [{ value: value, label: `${value} (custom)` }] : []),
    { value: '__new__', label: '+ Add new category...' },
  ];

  return (
    <CustomSelect
      options={options}
      value={value || '__none__'}
      onValueChange={handleSelectChange}
      placeholder="Select or add category..."
    />
  );
}

const OPERATORS = [
  { value: 'eq', label: '=' },
  { value: 'neq', label: '!=' },
  { value: 'gt', label: '>' },
  { value: 'gte', label: '>=' },
  { value: 'lt', label: '<' },
  { value: 'lte', label: '<=' },
  { value: 'like', label: 'LIKE' },
];

// Result rendering types
interface ReportResult {
  reportId: string;
  reportName: string;
  executedAt: string;
  parameters: Record<string, unknown>;
  metrics: Record<string, unknown[]>;
  metadata: {
    version: string;
    category: string;
    executionTime: number;
    cacheHit: boolean;
  };
}

// Helper: evaluate conditional label for a cell value
function getConditionalBadge(
  value: unknown,
  columnKey: string,
  labels?: ConditionalLabel[]
): { tone: 'danger' | 'warning' | 'success' | 'info'; text: string } | null {
  if (!labels || labels.length === 0) return null;
  const numValue = Number(value);
  if (isNaN(numValue)) return null;

  for (const label of labels) {
    if (label.column !== '*' && label.column !== columnKey) continue;
    let matches = false;
    switch (label.operator) {
      case 'lt': matches = numValue < label.value; break;
      case 'gt': matches = numValue > label.value; break;
      case 'lte': matches = numValue <= label.value; break;
      case 'gte': matches = numValue >= label.value; break;
      case 'eq': matches = numValue === label.value; break;
    }
    if (matches) {
      return { tone: label.tone, text: label.label || `${label.operator} ${label.value}` };
    }
  }
  return null;
}

// Stat Card for single-value metrics (counts, sums, etc.)
function StatCard({ title, value, subtitle, conditionalLabels }: {
  title: string;
  value: string | number;
  subtitle?: string;
  conditionalLabels?: ConditionalLabel[];
}) {
  const badge = getConditionalBadge(
    typeof value === 'string' ? Number(value.replace(/,/g, '')) : value,
    'count',
    conditionalLabels
  );

  return (
    <div style={{
      background: 'linear-gradient(135deg, var(--alga-primary) 0%, var(--alga-primary-light) 100%)',
      color: 'var(--alga-primary-foreground)',
      borderRadius: '12px',
      padding: '20px',
      minWidth: '200px',
    }}>
      <div style={{ fontSize: '0.875rem', opacity: 0.9, marginBottom: '4px' }}>{title}</div>
      <div style={{ display: 'flex', alignItems: 'center', gap: '10px' }}>
        <div style={{ fontSize: '2rem', fontWeight: 'bold' }}>{value}</div>
        {badge && <Badge tone={badge.tone}>{badge.text}</Badge>}
      </div>
      {subtitle && <div style={{ fontSize: '0.75rem', opacity: 0.8, marginTop: '4px' }}>{subtitle}</div>}
    </div>
  );
}

// Table for displaying metric rows with search and sorting
function ResultsTable({ data, title, conditionalLabels }: {
  data: unknown[];
  title: string;
  conditionalLabels?: ConditionalLabel[];
}) {
  const [search, setSearch] = useState('');

  if (!Array.isArray(data) || data.length === 0) {
    return (
      <Card>
        <h4 style={{ marginTop: 0 }}>{title}</h4>
        <Text tone="muted">No data returned</Text>
      </Card>
    );
  }

  // Get columns from first row
  const firstRow = data[0] as Record<string, unknown>;
  const columnKeys = Object.keys(firstRow);

  // Format column header
  const formatHeader = (col: string): string => {
    return col
      .replace(/_/g, ' ')
      .replace(/\b\w/g, c => c.toUpperCase());
  };

  // Format cell value for display
  const formatValue = (value: unknown): string => {
    if (value === null || value === undefined) return '—';
    if (typeof value === 'boolean') return value ? 'Yes' : 'No';
    if (typeof value === 'number') return value.toLocaleString();
    if (typeof value === 'string' && value.match(/^\d{4}-\d{2}-\d{2}T/)) {
      return new Date(value).toLocaleString();
    }
    return String(value);
  };

  // Filter data by search term
  const filteredData = search
    ? data.filter(row => {
        const rowStr = Object.values(row as Record<string, unknown>)
          .map(v => String(v ?? '').toLowerCase())
          .join(' ');
        return rowStr.includes(search.toLowerCase());
      })
    : data;

  // Build columns for DataTable with conditional label support
  const columns: Column<Record<string, unknown>>[] = columnKeys.map(key => ({
    key: key as keyof Record<string, unknown> & string,
    header: formatHeader(key),
    render: (row: Record<string, unknown>) => {
      const badge = getConditionalBadge(row[key], key, conditionalLabels);
      return (
        <span style={{ display: 'inline-flex', alignItems: 'center', gap: '6px' }}>
          {formatValue(row[key])}
          {badge && <Badge tone={badge.tone}>{badge.text}</Badge>}
        </span>
      );
    },
  }));

  return (
    <Card>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
        <h4 style={{ margin: 0 }}>{title}</h4>
        <Input
          type="text"
          placeholder="Search results..."
          value={search}
          onChange={(e) => setSearch(e.target.value)}
          style={{ width: '250px' }}
        />
      </div>
      <DataTable
        columns={columns}
        data={filteredData as Record<string, unknown>[]}
        paginate
        defaultPageSize={10}
      />
    </Card>
  );
}

// Bar chart for grouped count data
function SimpleBarChart({ data, labelKey, valueKey, title }: {
  data: unknown[];
  labelKey: string;
  valueKey: string;
  title: string;
}) {
  if (!Array.isArray(data) || data.length === 0) return null;

  const maxValue = Math.max(...data.map(d => Number((d as Record<string, unknown>)[valueKey]) || 0));

  return (
    <Card>
      <h4 style={{ marginTop: 0 }}>{title}</h4>
      <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
        {data.map((item, idx) => {
          const label = String((item as Record<string, unknown>)[labelKey] || `Item ${idx + 1}`);
          const value = Number((item as Record<string, unknown>)[valueKey]) || 0;
          const percentage = maxValue > 0 ? (value / maxValue) * 100 : 0;

          return (
            <div key={idx} style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
              <div style={{ width: '120px', fontSize: '0.875rem', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
                {label}
              </div>
              <div style={{ flex: 1, background: 'var(--alga-border)', borderRadius: '4px', height: '24px', overflow: 'hidden' }}>
                <div style={{
                  width: `${percentage}%`,
                  height: '100%',
                  background: 'linear-gradient(90deg, var(--alga-primary) 0%, var(--alga-secondary) 100%)',
                  borderRadius: '4px',
                  transition: 'width 0.3s ease',
                }} />
              </div>
              <div style={{ width: '60px', textAlign: 'right', fontWeight: 'bold' }}>
                {value.toLocaleString()}
              </div>
            </div>
          );
        })}
      </div>
    </Card>
  );
}

// Intelligent results renderer
function ResultsRenderer({ results, report }: { results: ReportResult; report?: PlatformReport }) {
  const { metrics, metadata, parameters, executedAt } = results;

  // Build maps from report definition
  const metricNames: Record<string, string> = {};
  const metricLabels: Record<string, ConditionalLabel[]> = {};
  if (report?.report_definition?.metrics) {
    report.report_definition.metrics.forEach(m => {
      if (m.id && m.name) {
        metricNames[m.id] = m.name;
      }
      if (m.id && m.conditionalLabels?.length) {
        metricLabels[m.id] = m.conditionalLabels;
      }
    });
  }

  // Helper to get display name for a metric
  const getMetricDisplayName = (metricId: string): string => {
    return metricNames[metricId] || metricId.replace(/_/g, ' ').replace(/metric /i, '');
  };

  // Detect if data is a single count result
  const isSingleCount = (data: unknown[]): boolean => {
    if (data.length !== 1) return false;
    const row = data[0] as Record<string, unknown>;
    const keys = Object.keys(row);
    return keys.length === 1 && (keys[0] === 'count' || keys[0].endsWith('_count'));
  };

  // Detect if data is grouped counts (for bar chart)
  const isGroupedCounts = (data: unknown[]): { labelKey: string; valueKey: string } | null => {
    if (data.length === 0) return null;
    const row = data[0] as Record<string, unknown>;
    const keys = Object.keys(row);
    if (keys.length !== 2) return null;
    const countKey = keys.find(k => k === 'count' || k.endsWith('_count'));
    if (!countKey) return null;
    const labelKey = keys.find(k => k !== countKey);
    if (!labelKey) return null;
    return { labelKey, valueKey: countKey };
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
      {/* Execution metadata */}
      <Card style={{ background: 'var(--alga-muted)' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', flexWrap: 'wrap', gap: '16px' }}>
          <div>
            <div style={{ fontSize: '0.75rem', color: 'var(--alga-muted-fg)' }}>Executed At</div>
            <div style={{ fontWeight: 500 }}>{new Date(executedAt).toLocaleString()}</div>
          </div>
          <div>
            <div style={{ fontSize: '0.75rem', color: 'var(--alga-muted-fg)' }}>Execution Time</div>
            <div style={{ fontWeight: 500 }}>{metadata.executionTime}ms</div>
          </div>
          <div>
            <div style={{ fontSize: '0.75rem', color: 'var(--alga-muted-fg)' }}>Category</div>
            <div style={{ fontWeight: 500 }}>{metadata.category || '—'}</div>
          </div>
          <div>
            <div style={{ fontSize: '0.75rem', color: 'var(--alga-muted-fg)' }}>Cache</div>
            <div style={{ fontWeight: 500 }}>{metadata.cacheHit ? 'Hit' : 'Miss'}</div>
          </div>
        </div>
      </Card>

      {/* Render each metric */}
      {Object.entries(metrics).map(([metricId, data]) => {
        // Handle error objects
        if (data && typeof data === 'object' && 'error' in data && (data as Record<string, unknown>).error === true) {
          const errorData = data as unknown as { error: boolean; message: string; metricName: string };
          return (
            <Card key={metricId} style={{ background: 'var(--alga-danger-50)', borderColor: 'var(--alga-danger)' }}>
              <div style={{ display: 'flex', alignItems: 'flex-start', gap: '12px' }}>
                <span style={{ fontSize: '1.5rem' }}>⚠️</span>
                <div>
                  <Text style={{ fontWeight: 600, color: 'var(--alga-danger)' }}>
                    Error in metric: {errorData.metricName || metricId}
                  </Text>
                  <Text tone="muted" style={{ display: 'block', marginTop: '4px', fontSize: '0.875rem' }}>
                    {errorData.message}
                  </Text>
                  <Text tone="muted" style={{ display: 'block', marginTop: '8px', fontSize: '0.75rem' }}>
                    Tip: Check that all non-aggregated columns are included in GROUP BY, or use aggregate functions like COUNT(), SUM(), etc.
                  </Text>
                </div>
              </div>
            </Card>
          );
        }

        if (!Array.isArray(data)) return null;

        const displayName = getMetricDisplayName(metricId);
        const labels = metricLabels[metricId];

        // Single count value → StatCard (fit-to-content width)
        if (isSingleCount(data)) {
          const row = data[0] as Record<string, unknown>;
          const countKey = Object.keys(row)[0];
          return (
            <div key={metricId} style={{ alignSelf: 'flex-start' }}>
              <StatCard
                title={displayName}
                value={Number(row[countKey]).toLocaleString()}
                subtitle="Total count"
                conditionalLabels={labels}
              />
            </div>
          );
        }

        // Grouped counts → Bar chart + Table
        const grouped = isGroupedCounts(data);
        if (grouped && data.length <= 20) {
          return (
            <div key={metricId} style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
              <SimpleBarChart
                data={data}
                labelKey={grouped.labelKey}
                valueKey={grouped.valueKey}
                title={`${displayName} (Chart)`}
              />
              <ResultsTable data={data} title={`${displayName} (Data)`} conditionalLabels={labels} />
            </div>
          );
        }

        // Default → Table
        return <ResultsTable key={metricId} data={data} title={displayName} conditionalLabels={labels} />;
      })}

      {/* Raw JSON toggle */}
      <details style={{ marginTop: '8px' }}>
        <summary style={{ cursor: 'pointer', color: 'var(--alga-muted-fg)', fontSize: '0.875rem' }}>
          View Raw JSON
        </summary>
        <pre style={{ marginTop: '8px', fontSize: '0.75rem' }}>
          {JSON.stringify(results, null, 2)}
        </pre>
      </details>
    </div>
  );
}

// Components
function ReportsList() {
  const [reports, setReports] = useState<PlatformReport[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [selectedReport, setSelectedReport] = useState<PlatformReport | null>(null);
  const [showCreate, setShowCreate] = useState(false);

  useEffect(() => {
    fetchReports();
  }, []);

  async function fetchReports() {
    setLoading(true);
    setError(null);
    const result = await callExtensionApi<PlatformReport[]>('');
    if (result.success && result.data) {
      setReports(result.data);
    } else {
      setError(result.error || 'Failed to fetch reports');
    }
    setLoading(false);
  }

  if (loading) {
    return (
      <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '200px' }}>
        <LoadingIndicator size="md" text="Loading reports..." layout="stacked" />
      </div>
    );
  }

  if (error) {
    return (
      <div>
        <Alert tone="danger">{error}</Alert>
        <Button style={{ marginTop: '16px' }} onClick={fetchReports}>
          Retry
        </Button>
      </div>
    );
  }

  if (showCreate) {
    return (
      <CreateReport
        onBack={() => setShowCreate(false)}
        onCreated={() => {
          setShowCreate(false);
          fetchReports();
        }}
      />
    );
  }

  if (selectedReport) {
    return (
      <ReportDetail
        report={selectedReport}
        onBack={() => setSelectedReport(null)}
        onRefresh={fetchReports}
      />
    );
  }

  const columns: Column<PlatformReport>[] = [
    {
      key: 'name',
      header: 'Name',
      render: (row) => (
        <div>
          <strong>{row.name}</strong>
          {row.description && (
            <div style={{ fontSize: '0.75rem', color: 'var(--alga-muted-fg)' }}>
              {row.description}
            </div>
          )}
        </div>
      ),
    },
    {
      key: 'category',
      header: 'Category',
      render: (row) => row.category ? (
        <Badge tone="info">{row.category}</Badge>
      ) : null,
    },
    {
      key: 'is_active',
      header: 'Status',
      render: (row) => (
        <Badge tone={row.is_active ? 'success' : 'warning'}>
          {row.is_active ? 'Active' : 'Inactive'}
        </Badge>
      ),
    },
    {
      key: 'created_at',
      header: 'Created',
      render: (row) => (
        <Text tone="muted" style={{ fontSize: '0.875rem' }}>
          {new Date(row.created_at).toLocaleDateString()}
        </Text>
      ),
    },
    {
      key: 'report_id',
      header: 'Actions',
      sortable: false,
      render: (row) => (
        <Button
          size="sm"
          onClick={() => setSelectedReport(row)}
        >
          View Details
        </Button>
      ),
    },
  ];

  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
        <h2 style={{ margin: 0 }}>Platform Reports</h2>
        <div style={{ display: 'flex', gap: '8px' }}>
          <Button variant="outline" onClick={fetchReports}>
            Refresh
          </Button>
          <Button onClick={() => setShowCreate(true)}>
            + Add New
          </Button>
        </div>
      </div>

      {reports.length === 0 ? (
        <Card>
          <Text tone="muted">
            No reports found. Click "Add New" to create your first report.
          </Text>
        </Card>
      ) : (
        <DataTable
          columns={columns}
          data={reports}
          paginate
          defaultPageSize={10}
          initialSortKey="created_at"
        />
      )}
    </div>
  );
}

function ReportDetail({
  report,
  onBack,
  onRefresh,
}: {
  report: PlatformReport;
  onBack: () => void;
  onRefresh: () => void;
}) {
  const [executing, setExecuting] = useState(false);
  const [results, setResults] = useState<ReportResult | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [isEditing, setIsEditing] = useState(false);
  const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);

  // If editing, render the EditReport component
  if (isEditing) {
    return (
      <EditReport
        report={report}
        onBack={() => setIsEditing(false)}
        onSave={onRefresh}
      />
    );
  }

  const handleExecute = async () => {
    setExecuting(true);
    setError(null);
    setResults(null);

    const result = await callExtensionApi<ReportResult>(`/${report.report_id}/execute`, {
      method: 'POST',
      body: JSON.stringify({}),
    });

    if (result.success && result.data) {
      setResults(result.data);
    } else {
      setError(result.error || 'Failed to execute report');
    }
    setExecuting(false);
  };

  const handleDeleteConfirmed = async () => {
    const result = await callExtensionApi(`/${report.report_id}`, {
      method: 'DELETE',
    });

    if (result.success) {
      onRefresh();
      onBack();
    } else {
      setError(result.error || 'Failed to delete report');
    }
    setShowDeleteConfirm(false);
  };

  return (
    <div>
      <Button
        variant="ghost"
        style={{ marginBottom: '20px' }}
        onClick={onBack}
      >
        ← Back to Reports
      </Button>

      <Card>
        <h2 style={{ marginTop: 0 }}>{report.name}</h2>
        {report.description && (
          <Text tone="muted" style={{ display: 'block', marginBottom: '12px' }}>{report.description}</Text>
        )}

        <div style={{ display: 'flex', gap: '8px', marginBottom: '16px' }}>
          {report.category && (
            <Badge tone="info">{report.category}</Badge>
          )}
          <Badge tone={report.is_active ? 'success' : 'warning'}>
            {report.is_active ? 'Active' : 'Inactive'}
          </Badge>
        </div>

        <Text tone="muted" style={{ display: 'block', fontSize: '0.875rem', marginBottom: '20px' }}>
          <div>Created: {new Date(report.created_at).toLocaleString()}</div>
          <div>Updated: {new Date(report.updated_at).toLocaleString()}</div>
        </Text>

        <h3>Report Definition</h3>
        <pre style={{
          background: 'var(--alga-muted)',
          color: 'var(--alga-fg)',
          padding: '12px',
          borderRadius: 'var(--alga-radius)',
          overflow: 'auto',
          fontSize: '0.8125rem',
          lineHeight: '1.5',
          fontFamily: 'ui-monospace, SFMono-Regular, "SF Mono", Menlo, Consolas, "Liberation Mono", monospace',
        }}>
          {JSON.stringify(report.report_definition, null, 2)}
        </pre>

        <div style={{ display: 'flex', gap: '8px', marginTop: '20px' }}>
          <Button
            onClick={handleExecute}
            disabled={executing}
          >
            {executing ? 'Executing...' : 'Execute Report'}
          </Button>
          <Button variant="secondary" onClick={() => setIsEditing(true)}>
            Edit Report
          </Button>
          <Button variant="destructive" onClick={() => setShowDeleteConfirm(true)}>
            Delete Report
          </Button>
        </div>

        {/* Delete Confirmation Dialog */}
        <ConfirmDialog
          isOpen={showDeleteConfirm}
          title="Delete Report"
          message="Are you sure you want to delete this report? This action cannot be undone."
          confirmLabel="Delete"
          cancelLabel="Cancel"
          variant="danger"
          onConfirm={handleDeleteConfirmed}
          onCancel={() => setShowDeleteConfirm(false)}
        />
      </Card>

      {error && <Alert tone="danger" style={{ marginTop: '16px' }}>{error}</Alert>}

      {results && (
        <div style={{ marginTop: '16px' }}>
          <h3>Results</h3>
          <ResultsRenderer results={results} report={report} />
        </div>
      )}
    </div>
  );
}


// Metric type options for Select
const METRIC_TYPE_OPTIONS: SelectOption[] = [
  { value: 'count', label: 'Count' },
  { value: 'sum', label: 'Sum' },
  { value: 'avg', label: 'Average' },
  { value: 'query', label: 'Custom Query' },
];

// Operator options for Select
const OPERATOR_OPTIONS: SelectOption[] = OPERATORS.map(op => ({ value: op.value, label: op.label }));

// Join type options for Select
const JOIN_TYPE_OPTIONS: SelectOption[] = [
  { value: 'inner', label: 'INNER JOIN' },
  { value: 'left', label: 'LEFT JOIN' },
  { value: 'right', label: 'RIGHT JOIN' },
  { value: 'full', label: 'FULL JOIN' },
];

// Conditional label operator options
const LABEL_OPERATOR_OPTIONS: SelectOption[] = [
  { value: 'lt', label: '<' },
  { value: 'lte', label: '<=' },
  { value: 'gt', label: '>' },
  { value: 'gte', label: '>=' },
  { value: 'eq', label: '=' },
];

// Conditional label tone options
const LABEL_TONE_OPTIONS: SelectOption[] = [
  { value: 'danger', label: 'Danger (Red)' },
  { value: 'warning', label: 'Warning (Yellow)' },
  { value: 'success', label: 'Success (Green)' },
  { value: 'info', label: 'Info (Blue)' },
];

function CreateReport({ onBack, onCreated }: { onBack?: () => void; onCreated?: () => void } = {}) {
  const [name, setName] = useState('');
  const [description, setDescription] = useState('');
  const [category, setCategory] = useState('');
  const [metrics, setMetrics] = useState<MetricDefinition[]>([]);
  const [creating, setCreating] = useState(false);
  const [success, setSuccess] = useState(false);
  const [error, setError] = useState<string | null>(null);
  // Track which metrics are in "raw SQL" mode
  const [rawSqlMode, setRawSqlMode] = useState<{ [key: string]: boolean }>({});
  const [rawSqlText, setRawSqlText] = useState<{ [key: string]: string }>({});

  // Use dynamic schema from server
  const { tables, tableOptions, getTableColumns, loading: schemaLoading } = useSchema();

  const addMetric = () => {
    // Use first available table, or empty string if schema not loaded yet
    const defaultTable = tables.length > 0 ? tables[0].name : '';
    setMetrics([
      ...metrics,
      {
        id: `metric_${Date.now()}`,
        name: '',
        type: 'count',
        query: {
          table: defaultTable,
          fields: ['COUNT(*) as count'],
          filters: [],
          groupBy: [],
        },
      },
    ]);
  };

  const updateMetric = (index: number, updates: Partial<MetricDefinition>) => {
    const newMetrics = [...metrics];
    newMetrics[index] = { ...newMetrics[index], ...updates };
    setMetrics(newMetrics);
  };

  const updateQuery = (index: number, updates: Partial<QueryDefinition>) => {
    const newMetrics = [...metrics];
    newMetrics[index] = {
      ...newMetrics[index],
      query: { ...newMetrics[index].query, ...updates },
    };
    setMetrics(newMetrics);
  };

  const removeMetric = (index: number) => {
    setMetrics(metrics.filter((_, i) => i !== index));
  };

  const moveMetric = (index: number, direction: 'up' | 'down') => {
    const newIndex = direction === 'up' ? index - 1 : index + 1;
    if (newIndex < 0 || newIndex >= metrics.length) return;
    const newMetrics = [...metrics];
    [newMetrics[index], newMetrics[newIndex]] = [newMetrics[newIndex], newMetrics[index]];
    setMetrics(newMetrics);
  };

  const addFilter = (metricIndex: number) => {
    const newMetrics = [...metrics];
    const filters = [...(newMetrics[metricIndex].query.filters || [])];
    filters.push({ field: '', operator: 'eq', value: '' });
    newMetrics[metricIndex].query.filters = filters;
    setMetrics(newMetrics);
  };

  const updateFilter = (metricIndex: number, filterIndex: number, updates: Partial<FilterDefinition>) => {
    const newMetrics = [...metrics];
    const filters = [...(newMetrics[metricIndex].query.filters || [])];
    filters[filterIndex] = { ...filters[filterIndex], ...updates };
    newMetrics[metricIndex].query.filters = filters;
    setMetrics(newMetrics);
  };

  const removeFilter = (metricIndex: number, filterIndex: number) => {
    const newMetrics = [...metrics];
    newMetrics[metricIndex].query.filters = (newMetrics[metricIndex].query.filters || [])
      .filter((_, i) => i !== filterIndex);
    setMetrics(newMetrics);
  };

  const addJoin = (metricIndex: number) => {
    const newMetrics = [...metrics];
    const joins = [...(newMetrics[metricIndex].query.joins || [])];
    const defaultTable = tables.length > 0 ? tables[0].name : '';
    joins.push({
      type: 'left',
      table: defaultTable,
      on: [{ left: '', right: '' }],
    });
    newMetrics[metricIndex].query.joins = joins;
    setMetrics(newMetrics);
  };

  const updateJoin = (metricIndex: number, joinIndex: number, updates: Partial<JoinDefinition>) => {
    const newMetrics = [...metrics];
    const joins = [...(newMetrics[metricIndex].query.joins || [])];
    joins[joinIndex] = { ...joins[joinIndex], ...updates };
    newMetrics[metricIndex].query.joins = joins;
    setMetrics(newMetrics);
  };

  const updateJoinCondition = (
    metricIndex: number,
    joinIndex: number,
    conditionIndex: number,
    updates: Partial<JoinCondition>
  ) => {
    const newMetrics = [...metrics];
    const joins = [...(newMetrics[metricIndex].query.joins || [])];
    const conditions = [...joins[joinIndex].on];
    conditions[conditionIndex] = { ...conditions[conditionIndex], ...updates };
    joins[joinIndex] = { ...joins[joinIndex], on: conditions };
    newMetrics[metricIndex].query.joins = joins;
    setMetrics(newMetrics);
  };

  const addJoinCondition = (metricIndex: number, joinIndex: number) => {
    const newMetrics = [...metrics];
    const joins = [...(newMetrics[metricIndex].query.joins || [])];
    joins[joinIndex] = {
      ...joins[joinIndex],
      on: [...joins[joinIndex].on, { left: '', right: '' }],
    };
    newMetrics[metricIndex].query.joins = joins;
    setMetrics(newMetrics);
  };

  const removeJoinCondition = (metricIndex: number, joinIndex: number, conditionIndex: number) => {
    const newMetrics = [...metrics];
    const joins = [...(newMetrics[metricIndex].query.joins || [])];
    joins[joinIndex] = {
      ...joins[joinIndex],
      on: joins[joinIndex].on.filter((_, i) => i !== conditionIndex),
    };
    newMetrics[metricIndex].query.joins = joins;
    setMetrics(newMetrics);
  };

  const removeJoin = (metricIndex: number, joinIndex: number) => {
    const newMetrics = [...metrics];
    newMetrics[metricIndex].query.joins = (newMetrics[metricIndex].query.joins || [])
      .filter((_, i) => i !== joinIndex);
    setMetrics(newMetrics);
  };

  const addLabel = (metricIndex: number) => {
    const newMetrics = [...metrics];
    const labels = [...(newMetrics[metricIndex].conditionalLabels || [])];
    labels.push({ column: '', operator: 'gte', value: 0, tone: 'warning', label: '' });
    newMetrics[metricIndex].conditionalLabels = labels;
    setMetrics(newMetrics);
  };

  const updateLabel = (metricIndex: number, labelIndex: number, updates: Partial<ConditionalLabel>) => {
    const newMetrics = [...metrics];
    const labels = [...(newMetrics[metricIndex].conditionalLabels || [])];
    labels[labelIndex] = { ...labels[labelIndex], ...updates };
    newMetrics[metricIndex].conditionalLabels = labels;
    setMetrics(newMetrics);
  };

  const removeLabel = (metricIndex: number, labelIndex: number) => {
    const newMetrics = [...metrics];
    newMetrics[metricIndex].conditionalLabels = (newMetrics[metricIndex].conditionalLabels || [])
      .filter((_, i) => i !== labelIndex);
    setMetrics(newMetrics);
  };

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    setCreating(true);
    setError(null);
    setSuccess(false);

    if (!name.trim()) {
      setError('Report name is required');
      setCreating(false);
      return;
    }

    if (metrics.length === 0) {
      setError('At least one metric is required');
      setCreating(false);
      return;
    }

    const reportDefinition: ReportDefinition = {
      id: `report_${Date.now()}`,
      name: name,
      description: description,
      category: category,
      version: '1.0.0',
      metrics: metrics,
    };

    const result = await callExtensionApi('', {
      method: 'POST',
      body: JSON.stringify({
        name,
        description: description || null,
        category: category || null,
        report_definition: reportDefinition,
      }),
    });

    if (result.success) {
      if (onCreated) {
        onCreated();
      } else {
        setSuccess(true);
        setName('');
        setDescription('');
        setCategory('');
        setMetrics([]);
      }
    } else {
      setError(result.error || 'Failed to create report');
    }
    setCreating(false);
  };

  // Get all field options from base table + all joined tables (for filters)
  const getAllFieldOptions = (metric: MetricDefinition): SelectOption[] => {
    const options: SelectOption[] = [];

    // Base table columns
    if (metric.query.table) {
      getTableColumns(metric.query.table).forEach(col => {
        options.push({ value: col, label: col });
      });
    }

    // Joined table columns (with table prefix)
    (metric.query.joins || []).forEach(join => {
      if (join.table) {
        getTableColumns(join.table).forEach(col => {
          const fullCol = `${join.table}.${col}`;
          options.push({ value: fullCol, label: fullCol });
        });
      }
    });

    return options;
  };

  // Get all columns from base table AND all joined tables
  const getAllMetricColumns = (metric: MetricDefinition): { table: string; columns: string[] }[] => {
    const result: { table: string; columns: string[] }[] = [];

    // Base table columns
    if (metric.query.table) {
      result.push({
        table: metric.query.table,
        columns: getTableColumns(metric.query.table),
      });
    }

    // Joined table columns
    (metric.query.joins || []).forEach(join => {
      if (join.table) {
        result.push({
          table: join.table,
          columns: getTableColumns(join.table),
        });
      }
    });

    return result;
  };

  // State for table search filter
  const [tableSearch, setTableSearch] = useState('');

  // Filtered table options based on search
  const filteredTableOptions = tableOptions.filter(opt =>
    opt.label.toLowerCase().includes(tableSearch.toLowerCase())
  );

  return (
    <div>
      {onBack && (
        <Button
          variant="ghost"
          style={{ marginBottom: '20px' }}
          onClick={onBack}
        >
          ← Back to Reports
        </Button>
      )}
      <h2 style={{ marginTop: 0 }}>Create New Report</h2>

      <form onSubmit={handleSubmit}>
        <Card style={{ marginBottom: '16px' }}>
          <h3 style={{ marginTop: 0 }}>Basic Information</h3>

          <div style={{ marginBottom: '16px' }}>
            <Label required>Report Name</Label>
            <Input
              type="text"
              value={name}
              onChange={(e) => setName(e.target.value)}
              placeholder="e.g., Tenant User Summary"
              style={{ width: '100%', marginTop: '6px' }}
            />
          </div>

          <div style={{ marginBottom: '16px' }}>
            <Label>Description</Label>
            <TextArea
              value={description}
              onChange={(e) => setDescription(e.target.value)}
              placeholder="Describe what this report shows..."
              rows={3}
              style={{ marginTop: '6px' }}
            />
          </div>

          <div style={{ marginBottom: '16px' }}>
            <Label>Category</Label>
            <CategorySelect value={category} onChange={setCategory} />
          </div>
        </Card>

        <Card style={{ marginBottom: '16px' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}>
            <h3 style={{ margin: 0 }}>Metrics</h3>
            <Button type="button" onClick={addMetric}>
              + Add Metric
            </Button>
          </div>

          {metrics.length === 0 ? (
            <Text tone="muted">
              No metrics added yet. Click "Add Metric" to define what data this report should query.
            </Text>
          ) : (
            <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
              {metrics.map((metric, index) => (
                <Card
                  key={metric.id}
                  style={{ background: 'var(--alga-card-bg)' }}
                >
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
                    <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
                      <strong>Metric {index + 1}</strong>
                      <div style={{ display: 'flex', gap: '4px' }}>
                        <Button
                          type="button"
                          variant="ghost"
                          size="sm"
                          onClick={() => moveMetric(index, 'up')}
                          disabled={index === 0}
                          title="Move up"
                        >
                          ↑
                        </Button>
                        <Button
                          type="button"
                          variant="ghost"
                          size="sm"
                          onClick={() => moveMetric(index, 'down')}
                          disabled={index === metrics.length - 1}
                          title="Move down"
                        >
                          ↓
                        </Button>
                      </div>
                    </div>
                    <Button
                      type="button"
                      variant="destructive"
                      size="sm"
                      onClick={() => removeMetric(index)}
                    >
                      Remove
                    </Button>
                  </div>

                  <div style={{ marginBottom: '16px' }}>
                    <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Metric Name</Text>
                    <Input
                      type="text"
                      value={metric.name}
                      onChange={(e) => updateMetric(index, { name: e.target.value })}
                      placeholder="e.g., Active Users Count"
                      style={{ width: '100%' }}
                    />
                  </div>

                  <div style={{ marginBottom: '16px' }}>
                    <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Metric Type</Text>
                    <CustomSelect
                      options={METRIC_TYPE_OPTIONS}
                      value={metric.type}
                      onValueChange={(value) => updateMetric(index, { type: value as 'count' | 'sum' | 'avg' | 'query' })}
                    />
                  </div>

                  {/* Mode Toggle: Builder vs Raw SQL */}
                  <div style={{ marginBottom: '16px', display: 'flex', gap: '8px', alignItems: 'center' }}>
                    <Text style={{ fontWeight: 500, fontSize: '0.875rem' }}>Mode:</Text>
                    <div style={{ display: 'flex', gap: '4px' }}>
                      <Button
                        type="button"
                        variant={!rawSqlMode[metric.id] ? 'primary' : 'secondary'}
                        size="sm"
                        onClick={() => setRawSqlMode(prev => ({ ...prev, [metric.id]: false }))}
                      >
                        Builder
                      </Button>
                      <Button
                        type="button"
                        variant={rawSqlMode[metric.id] ? 'primary' : 'secondary'}
                        size="sm"
                        onClick={() => {
                          setRawSqlMode(prev => ({ ...prev, [metric.id]: true }));
                          // Initialize raw SQL from current query if not set
                          if (!rawSqlText[metric.id]) {
                            // If already in raw_sql mode, use the existing SQL from fields[0]
                            if (metric.query.table === 'raw_sql' && metric.query.fields?.[0]) {
                              setRawSqlText(prev => ({ ...prev, [metric.id]: metric.query.fields[0] }));
                            } else {
                              // Generate SQL from builder state
                              const fields = metric.query.fields.join(', ') || '*';
                              const from = metric.query.table || 'table_name';
                              let sql = `SELECT ${fields}\nFROM ${from}`;
                              if ((metric.query.joins || []).length > 0) {
                                metric.query.joins!.forEach(j => {
                                  const joinType = j.type.toUpperCase();
                                  const onClauses = j.on.map(c => `${c.left} = ${c.right}`).join(' AND ');
                                  sql += `\n${joinType} JOIN ${j.table} ON ${onClauses}`;
                                });
                              }
                              if ((metric.query.filters || []).length > 0) {
                                const whereClause = metric.query.filters!.map(f => `${f.field} ${f.operator} '${f.value}'`).join(' AND ');
                                sql += `\nWHERE ${whereClause}`;
                              }
                              if ((metric.query.groupBy || []).length > 0) {
                                sql += `\nGROUP BY ${metric.query.groupBy!.join(', ')}`;
                              }
                              setRawSqlText(prev => ({ ...prev, [metric.id]: sql }));
                            }
                          }
                        }}
                      >
                        Raw SQL
                      </Button>
                    </div>
                    <Text tone="muted" style={{ fontSize: '0.7rem', marginLeft: '8px' }}>
                      {rawSqlMode[metric.id] ? 'Write SQL directly' : 'Point-and-click query builder'}
                    </Text>
                  </div>

                  {rawSqlMode[metric.id] ? (
                    /* Raw SQL Mode */
                    <div style={{ marginBottom: '16px' }}>
                      <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>SQL Query</Text>
                      <textarea
                        value={rawSqlText[metric.id] || ''}
                        onChange={(e) => {
                          setRawSqlText(prev => ({ ...prev, [metric.id]: e.target.value }));
                          // Store raw SQL in the query as a custom field
                          updateQuery(index, {
                            table: 'raw_sql',
                            fields: [e.target.value],
                          });
                        }}
                        placeholder="SELECT column1, column2&#10;FROM table_name&#10;WHERE condition&#10;GROUP BY column1"
                        style={{
                          width: '100%',
                          minHeight: '200px',
                          fontFamily: 'monospace',
                          fontSize: '0.875rem',
                          padding: '12px',
                          border: '1px solid var(--alga-border)',
                          borderRadius: 'var(--alga-radius)',
                          background: '#1f2937',
                          color: '#f9fafb',
                          resize: 'vertical',
                        }}
                      />
                      <Text tone="muted" style={{ display: 'block', fontSize: '0.7rem', marginTop: '4px' }}>
                        Write your SQL query. Only SELECT statements are allowed. Blocked tables and columns will be rejected.
                      </Text>
                    </div>
                  ) : (
                    /* Builder Mode */
                    <>
                  <div style={{ marginBottom: '16px' }}>
                    <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Table</Text>
                    <Input
                      type="text"
                      placeholder="Search tables..."
                      value={tableSearch}
                      onChange={(e) => setTableSearch(e.target.value)}
                      style={{ marginBottom: '6px' }}
                    />
                    <CustomSelect
                      options={filteredTableOptions}
                      value={metric.query.table}
                      onValueChange={(value) => updateQuery(index, { table: value, fields: ['COUNT(*) as count'] })}
                      disabled={schemaLoading}
                    />
                    {schemaLoading && (
                      <LoadingIndicator size="xs" text="Loading available tables..." style={{ marginTop: '4px' }} />
                    )}
                    {!schemaLoading && filteredTableOptions.length === 0 && tableSearch && (
                      <Text tone="muted" style={{ display: 'block', fontSize: '0.75rem', marginTop: '4px' }}>
                        No tables match "{tableSearch}"
                      </Text>
                    )}
                  </div>

                  {/* Joins Section */}
                  <div style={{ marginBottom: '16px' }}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
                      <Text style={{ fontWeight: 500 }}>Joins</Text>
                      <Button
                        type="button"
                        size="sm"
                        onClick={() => addJoin(index)}
                      >
                        + Add Join
                      </Button>
                    </div>

                    {(metric.query.joins || []).length === 0 ? (
                      <Text tone="muted" style={{ fontSize: '0.75rem' }}>
                        No joins. Add a join to query data from multiple tables.
                      </Text>
                    ) : (
                      <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
                        {(metric.query.joins || []).map((join, joinIndex) => (
                          <Card key={joinIndex} style={{ background: 'var(--alga-muted)', padding: '12px' }}>
                            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
                              <Badge tone="info">Join {joinIndex + 1}</Badge>
                              <Button
                                type="button"
                                variant="destructive"
                                size="sm"
                                onClick={() => removeJoin(index, joinIndex)}
                              >
                                Remove
                              </Button>
                            </div>

                            <div style={{ display: 'flex', gap: '8px', marginBottom: '8px' }}>
                              <div style={{ flex: 1 }}>
                                <Text style={{ display: 'block', fontSize: '0.75rem', marginBottom: '4px' }}>Join Type</Text>
                                <CustomSelect
                                  options={JOIN_TYPE_OPTIONS}
                                  value={join.type}
                                  onValueChange={(value) => updateJoin(index, joinIndex, { type: value as JoinType })}
                                />
                              </div>
                              <div style={{ flex: 2 }}>
                                <Text style={{ display: 'block', fontSize: '0.75rem', marginBottom: '4px' }}>Join Table</Text>
                                <CustomSelect
                                  options={tableOptions}
                                  value={join.table}
                                  onValueChange={(value) => updateJoin(index, joinIndex, { table: value })}
                                />
                              </div>
                            </div>

                            <div style={{ marginBottom: '8px' }}>
                              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '4px' }}>
                                <Text style={{ fontSize: '0.75rem' }}>ON Conditions</Text>
                                <Button
                                  type="button"
                                  variant="ghost"
                                  size="sm"
                                  onClick={() => addJoinCondition(index, joinIndex)}
                                  style={{ fontSize: '0.75rem', padding: '2px 8px' }}
                                >
                                  + Add
                                </Button>
                              </div>

                              {join.on.map((condition, conditionIndex) => (
                                <div
                                  key={conditionIndex}
                                  style={{ display: 'flex', gap: '4px', alignItems: 'center', marginBottom: '4px' }}
                                >
                                  <Input
                                    type="text"
                                    value={condition.left}
                                    onChange={(e) => updateJoinCondition(index, joinIndex, conditionIndex, { left: e.target.value })}
                                    placeholder={`${metric.query.table}.column`}
                                    style={{ flex: 1, fontSize: '0.8125rem' }}
                                  />
                                  <Text style={{ fontSize: '0.75rem', color: 'var(--alga-muted-fg)' }}>=</Text>
                                  <Input
                                    type="text"
                                    value={condition.right}
                                    onChange={(e) => updateJoinCondition(index, joinIndex, conditionIndex, { right: e.target.value })}
                                    placeholder={`${join.table}.column`}
                                    style={{ flex: 1, fontSize: '0.8125rem' }}
                                  />
                                  {join.on.length > 1 && (
                                    <Button
                                      type="button"
                                      variant="destructive"
                                      size="sm"
                                      onClick={() => removeJoinCondition(index, joinIndex, conditionIndex)}
                                      style={{ padding: '2px 6px', fontSize: '0.75rem' }}
                                    >
                                      X
                                    </Button>
                                  )}
                                </div>
                              ))}
                            </div>

                            <Text tone="muted" style={{ display: 'block', fontSize: '0.7rem' }}>
                              Available in {join.table}: {getTableColumns(join.table).slice(0, 5).join(', ')}
                              {getTableColumns(join.table).length > 5 && '...'}
                            </Text>
                          </Card>
                        ))}
                      </div>
                    )}
                  </div>

                  <div style={{ marginBottom: '16px' }}>
                    <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Fields</Text>

                    {/* Selected fields as removable chips */}
                    <div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px', marginBottom: '8px', minHeight: '32px', padding: '8px', background: 'var(--alga-bg)', border: '1px solid var(--alga-border)', borderRadius: 'var(--alga-radius)' }}>
                      {metric.query.fields.length === 0 ? (
                        <Text tone="muted" style={{ fontSize: '0.75rem' }}>No fields selected. Click columns below to add.</Text>
                      ) : (
                        metric.query.fields.map((field, fieldIndex) => (
                          <Badge
                            key={fieldIndex}
                            tone="info"
                            style={{ cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: '4px' }}
                            onClick={() => updateQuery(index, { fields: metric.query.fields.filter((_, i) => i !== fieldIndex) })}
                          >
                            {field}
                            <span style={{ marginLeft: '4px', fontWeight: 'bold' }}>×</span>
                          </Badge>
                        ))
                      )}
                    </div>

                    {/* Available columns - click to add (from ALL tables including joins) */}
                    <Text tone="muted" style={{ display: 'block', fontSize: '0.75rem', marginBottom: '4px' }}>
                      Click to add column:
                    </Text>
                    {getAllMetricColumns(metric).map(({ table, columns }) => (
                      <div key={table} style={{ marginBottom: '8px' }}>
                        <Text style={{ display: 'block', fontSize: '0.7rem', fontWeight: 500, color: 'var(--alga-primary)', marginBottom: '4px' }}>
                          {table}:
                        </Text>
                        <div style={{ display: 'flex', flexWrap: 'wrap', gap: '4px' }}>
                          {columns.map((col) => {
                            const fullCol = `${table}.${col}`;
                            const isSelected = metric.query.fields.includes(col) || metric.query.fields.includes(fullCol);
                            return (
                              <Button
                                key={col}
                                type="button"
                                variant="secondary"
                                size="sm"
                                style={{ fontSize: '0.75rem', padding: '2px 8px' }}
                                onClick={() => {
                                  if (!isSelected) {
                                    // Use table.column format for joined tables, just column for base table
                                    const colName = table === metric.query.table ? col : fullCol;
                                    updateQuery(index, { fields: [...metric.query.fields, colName] });
                                  }
                                }}
                                disabled={isSelected}
                              >
                                {col}
                              </Button>
                            );
                          })}
                        </div>
                      </div>
                    ))}

                    {/* Custom expression input */}
                    <div style={{ display: 'flex', gap: '8px' }}>
                      <Input
                        type="text"
                        id={`custom-field-${index}`}
                        placeholder="Custom: COUNT(*) as count, SUM(amount), etc."
                        style={{ flex: 1 }}
                        onKeyDown={(e) => {
                          if (e.key === 'Enter') {
                            e.preventDefault();
                            const input = e.target as HTMLInputElement;
                            const value = input.value.trim();
                            if (value && !metric.query.fields.includes(value)) {
                              updateQuery(index, { fields: [...metric.query.fields, value] });
                              input.value = '';
                            }
                          }
                        }}
                      />
                      <Button
                        type="button"
                        variant="secondary"
                        size="sm"
                        onClick={() => {
                          const input = document.getElementById(`custom-field-${index}`) as HTMLInputElement;
                          if (input) {
                            const value = input.value.trim();
                            if (value && !metric.query.fields.includes(value)) {
                              updateQuery(index, { fields: [...metric.query.fields, value] });
                              input.value = '';
                            }
                          }
                        }}
                      >
                        Add
                      </Button>
                    </div>
                  </div>

                  <div style={{ marginBottom: '16px' }}>
                    <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Group By</Text>

                    {/* Selected group by fields as removable chips */}
                    <div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px', marginBottom: '8px', minHeight: '28px', padding: '6px', background: 'var(--alga-bg)', border: '1px solid var(--alga-border)', borderRadius: 'var(--alga-radius)' }}>
                      {(metric.query.groupBy || []).length === 0 ? (
                        <Text tone="muted" style={{ fontSize: '0.75rem' }}>No grouping. Click columns below to add.</Text>
                      ) : (
                        (metric.query.groupBy || []).map((field, fieldIndex) => (
                          <Badge
                            key={fieldIndex}
                            tone="info"
                            style={{ cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: '4px' }}
                            onClick={() => updateQuery(index, { groupBy: (metric.query.groupBy || []).filter((_, i) => i !== fieldIndex) })}
                          >
                            {field}
                            <span style={{ marginLeft: '4px', fontWeight: 'bold' }}>×</span>
                          </Badge>
                        ))
                      )}
                    </div>

                    {/* Available columns - click to add (from ALL tables including joins) */}
                    {getAllMetricColumns(metric).map(({ table, columns }) => (
                      <div key={table} style={{ marginBottom: '8px' }}>
                        <Text style={{ display: 'block', fontSize: '0.7rem', fontWeight: 500, color: 'var(--alga-primary)', marginBottom: '4px' }}>
                          {table}:
                        </Text>
                        <div style={{ display: 'flex', flexWrap: 'wrap', gap: '4px' }}>
                          {columns.map((col) => {
                            const fullCol = `${table}.${col}`;
                            const currentGroupBy = metric.query.groupBy || [];
                            const isSelected = currentGroupBy.includes(col) || currentGroupBy.includes(fullCol);
                            return (
                              <Button
                                key={col}
                                type="button"
                                variant="secondary"
                                size="sm"
                                style={{ fontSize: '0.7rem', padding: '2px 6px' }}
                                onClick={() => {
                                  if (!isSelected) {
                                    const colName = table === metric.query.table ? col : fullCol;
                                    updateQuery(index, { groupBy: [...currentGroupBy, colName] });
                                  }
                                }}
                                disabled={isSelected}
                              >
                                {col}
                              </Button>
                            );
                          })}
                        </div>
                      </div>
                    ))}
                  </div>

                  <div style={{ marginBottom: '12px' }}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
                      <Text style={{ fontWeight: 500 }}>Filters</Text>
                      <Button
                        type="button"
                        variant="secondary"
                        size="sm"
                        onClick={() => addFilter(index)}
                      >
                        + Add Filter
                      </Button>
                    </div>

                    {(metric.query.filters || []).map((filter, filterIndex) => (
                      <div
                        key={filterIndex}
                        style={{
                          display: 'flex',
                          gap: '8px',
                          marginBottom: '8px',
                          alignItems: 'center',
                        }}
                      >
                        <CustomSelect
                          options={getAllFieldOptions(metric)}
                          placeholder="Select field..."
                          value={filter.field}
                          onValueChange={(value) => updateFilter(index, filterIndex, { field: value })}
                          style={{ flex: 1 }}
                        />
                        <CustomSelect
                          options={OPERATOR_OPTIONS}
                          value={filter.operator}
                          onValueChange={(value) => updateFilter(index, filterIndex, { operator: value as FilterDefinition['operator'] })}
                          style={{ width: '100px' }}
                        />
                        <Input
                          type="text"
                          value={String(filter.value)}
                          onChange={(e) => updateFilter(index, filterIndex, { value: e.target.value })}
                          placeholder="Value"
                          style={{ flex: 1 }}
                        />
                        <Button
                          type="button"
                          variant="destructive"
                          size="sm"
                          onClick={() => removeFilter(index, filterIndex)}
                        >
                          X
                        </Button>
                      </div>
                    ))}
                  </div>
                    </>
                  )}

                  {/* Conditional Labels Section */}
                  <div style={{ marginTop: '16px', borderTop: '1px solid var(--alga-border)', paddingTop: '16px' }}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
                      <Text style={{ fontWeight: 500 }}>Conditional Labels</Text>
                      <Button
                        type="button"
                        variant="secondary"
                        size="sm"
                        onClick={() => addLabel(index)}
                      >
                        + Add Label
                      </Button>
                    </div>

                    {(metric.conditionalLabels || []).length === 0 ? (
                      <Text tone="muted" style={{ fontSize: '0.75rem' }}>
                        No labels. Add conditional labels to highlight values with colored badges (e.g. "Danger Zone" when risk_score &gt;= 4).
                      </Text>
                    ) : (
                      <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
                        {(metric.conditionalLabels || []).map((label, labelIndex) => (
                          <div
                            key={labelIndex}
                            style={{
                              display: 'flex',
                              gap: '6px',
                              alignItems: 'center',
                              padding: '8px',
                              background: 'var(--alga-muted)',
                              borderRadius: 'var(--alga-radius)',
                            }}
                          >
                            <Input
                              type="text"
                              value={label.column}
                              onChange={(e) => updateLabel(index, labelIndex, { column: e.target.value })}
                              placeholder="Column"
                              style={{ width: '120px', fontSize: '0.8125rem' }}
                            />
                            <CustomSelect
                              options={LABEL_OPERATOR_OPTIONS}
                              value={label.operator}
                              onValueChange={(value) => updateLabel(index, labelIndex, { operator: value as ConditionalLabel['operator'] })}
                              style={{ width: '70px' }}
                            />
                            <Input
                              type="number"
                              value={String(label.value)}
                              onChange={(e) => updateLabel(index, labelIndex, { value: Number(e.target.value) })}
                              placeholder="Value"
                              style={{ width: '80px', fontSize: '0.8125rem' }}
                            />
                            <CustomSelect
                              options={LABEL_TONE_OPTIONS}
                              value={label.tone}
                              onValueChange={(value) => updateLabel(index, labelIndex, { tone: value as ConditionalLabel['tone'] })}
                              style={{ width: '140px' }}
                            />
                            <Input
                              type="text"
                              value={label.label || ''}
                              onChange={(e) => updateLabel(index, labelIndex, { label: e.target.value })}
                              placeholder="Badge text"
                              style={{ flex: 1, fontSize: '0.8125rem' }}
                            />
                            <Button
                              type="button"
                              variant="destructive"
                              size="sm"
                              onClick={() => removeLabel(index, labelIndex)}
                            >
                              X
                            </Button>
                          </div>
                        ))}
                      </div>
                    )}
                    <Text tone="muted" style={{ display: 'block', fontSize: '0.7rem', marginTop: '6px' }}>
                      Labels are evaluated in order — first match wins. Put stricter rules first (e.g. &gt;= 30 before &gt;= 14). Only works on numeric values.
                    </Text>
                  </div>
                </Card>
              ))}
            </div>
          )}
        </Card>

        {error && <Alert tone="danger" style={{ marginBottom: '16px' }}>{error}</Alert>}

        {success && (
          <Alert tone="info" style={{ marginBottom: '16px' }}>
            Report created successfully!
          </Alert>
        )}

        <Button type="submit" disabled={creating}>
          {creating ? 'Creating...' : 'Create Report'}
        </Button>
      </form>
    </div>
  );
}

// Helper: Extract parameter placeholders from report definition
function extractReportParameters(report: PlatformReport): string[] {
  const params = new Set<string>();
  const regex = /\{\{(\w+)\}\}/g;

  // Search in all metric queries
  report.report_definition.metrics?.forEach(metric => {
    // Check fields (raw SQL)
    metric.query.fields?.forEach(field => {
      let match;
      while ((match = regex.exec(field)) !== null) {
        params.add(match[1]);
      }
    });
    // Check filters
    metric.query.filters?.forEach(filter => {
      if (typeof filter.value === 'string') {
        let match;
        while ((match = regex.exec(filter.value)) !== null) {
          params.add(match[1]);
        }
      }
    });
  });

  return Array.from(params);
}

// Known tenant-related parameters that can use dropdowns
const TENANT_PARAMETERS = ['tenant', 'email', 'client_name'];

function ExecuteReport() {
  const [reports, setReports] = useState<PlatformReport[]>([]);
  const [selectedReportId, setSelectedReportId] = useState('');
  const [parameters, setParameters] = useState('{}');
  const [loading, setLoading] = useState(true);
  const [executing, setExecuting] = useState(false);
  const [results, setResults] = useState<ReportResult | null>(null);
  const [error, setError] = useState<string | null>(null);
  const [showParamsHelp, setShowParamsHelp] = useState(false);
  const [showAdvancedJson, setShowAdvancedJson] = useState(false);

  // Parameter dropdown state
  const [tenants, setTenants] = useState<Tenant[]>([]);
  const [tenantsLoading, setTenantsLoading] = useState(false);
  const [selectedFilterParam, setSelectedFilterParam] = useState<string>('');
  const [selectedFilterValue, setSelectedFilterValue] = useState<string>('');
  const [tenantSearch, setTenantSearch] = useState('');

  useEffect(() => {
    async function fetchReports() {
      setLoading(true);
      const result = await callExtensionApi<PlatformReport[]>('');
      if (result.success && result.data) {
        setReports(result.data);
      }
      setLoading(false);
    }
    fetchReports();
  }, []);

  const selectedReport = reports.find(r => r.report_id === selectedReportId);

  // Extract parameters from selected report
  const reportParams = selectedReport ? extractReportParameters(selectedReport) : [];
  const hasTenantParams = reportParams.some(p => TENANT_PARAMETERS.includes(p));
  const tenantParamsInReport = reportParams.filter(p => TENANT_PARAMETERS.includes(p));

  // Fetch tenants when report with tenant params is selected
  useEffect(() => {
    if (hasTenantParams && tenants.length === 0 && !tenantsLoading) {
      setTenantsLoading(true);
      callTenantManagementApi<Tenant[]>('/tenants').then(result => {
        if (result.success && result.data) {
          setTenants(result.data);
        }
        setTenantsLoading(false);
      });
    }
  }, [hasTenantParams, tenants.length, tenantsLoading]);

  // Reset filter selections when report changes
  useEffect(() => {
    setSelectedFilterParam('');
    setSelectedFilterValue('');
    setTenantSearch('');
    setResults(null);
    setError(null);
  }, [selectedReportId]);

  // Build report options for Select
  const reportOptions: SelectOption[] = reports.map(report => ({
    value: report.report_id,
    label: `${report.name}${report.category ? ` (${report.category})` : ''}`,
  }));

  // Build filter parameter options
  const filterParamOptions: SelectOption[] = tenantParamsInReport.map(param => ({
    value: param,
    label: param === 'tenant' ? 'Tenant UUID' :
           param === 'email' ? 'User Email' :
           param === 'client_name' ? 'Company Name' : param,
  }));

  // Build value options based on selected filter parameter
  const getFilterValueOptions = (): SelectOption[] => {
    const searchLower = tenantSearch.toLowerCase();
    const filtered = tenants.filter(t => {
      if (!tenantSearch) return true;
      return (
        t.client_name?.toLowerCase().includes(searchLower) ||
        t.email?.toLowerCase().includes(searchLower) ||
        t.tenant?.toLowerCase().includes(searchLower)
      );
    });

    return filtered.map(t => {
      if (selectedFilterParam === 'tenant') {
        return { value: t.tenant, label: `${t.client_name} (${t.tenant.substring(0, 8)}...)` };
      } else if (selectedFilterParam === 'email') {
        return { value: t.email || '', label: `${t.email || 'No email'} - ${t.client_name}` };
      } else {
        return { value: t.client_name, label: t.client_name };
      }
    }).filter(opt => opt.value); // Remove empty values
  };

  const handleExecute = async () => {
    if (!selectedReportId) {
      setError('Please select a report');
      return;
    }

    setExecuting(true);
    setError(null);
    setResults(null);

    let parsedParams: Record<string, string> = {};

    // If using dropdown mode, build params from selections
    if (hasTenantParams && selectedFilterParam && selectedFilterValue && !showAdvancedJson) {
      // Set all tenant params to empty, then set the selected one
      tenantParamsInReport.forEach(p => {
        parsedParams[p] = '';
      });
      // When filtering by email or client_name, resolve to tenant UUID instead
      // to avoid matching client portal users in the master tenant
      if (selectedFilterParam === 'email' || selectedFilterParam === 'client_name') {
        const matchedTenant = tenants.find(t =>
          selectedFilterParam === 'email'
            ? t.email === selectedFilterValue
            : t.client_name === selectedFilterValue
        );
        if (matchedTenant && tenantParamsInReport.includes('tenant')) {
          parsedParams['tenant'] = matchedTenant.tenant;
        } else {
          parsedParams[selectedFilterParam] = selectedFilterValue;
        }
      } else {
        parsedParams[selectedFilterParam] = selectedFilterValue;
      }
    } else {
      // Parse from JSON
      try {
        parsedParams = JSON.parse(parameters);
      } catch {
        setError('Invalid JSON in parameters');
        setExecuting(false);
        return;
      }
    }

    const result = await callExtensionApi<ReportResult>(`/${selectedReportId}/execute`, {
      method: 'POST',
      body: JSON.stringify(parsedParams),
    });

    if (result.success && result.data) {
      setResults(result.data);
    } else {
      setError(result.error || 'Failed to execute report');
    }
    setExecuting(false);
  };

  if (loading) {
    return (
      <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '200px' }}>
        <LoadingIndicator size="md" text="Loading reports..." layout="stacked" />
      </div>
    );
  }

  return (
    <div>
      <h2 style={{ marginTop: 0 }}>Execute Report</h2>

      <Card>
        <div style={{ marginBottom: '16px' }}>
          <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Select Report</Text>
          <CustomSelect
            options={reportOptions}
            placeholder="Choose a report..."
            value={selectedReportId}
            onValueChange={(value) => {
              setSelectedReportId(value);
              setResults(null);
              setError(null);
            }}
          />
        </div>

        {selectedReport && (
          <Card style={{
            background: 'var(--alga-primary-50)',
            borderColor: 'var(--alga-primary-100)',
            marginBottom: '16px',
            fontSize: '0.875rem',
          }}>
            <strong>{selectedReport.name}</strong>
            {selectedReport.description && (
              <Text tone="muted" style={{ display: 'block', marginTop: '4px' }}>
                {selectedReport.description}
              </Text>
            )}
            <div style={{ marginTop: '8px', display: 'flex', gap: '8px', flexWrap: 'wrap' }}>
              {selectedReport.category && (
                <Badge tone="info">{selectedReport.category}</Badge>
              )}
              <Badge tone="success">
                {selectedReport.report_definition.metrics?.length || 0} metric(s)
              </Badge>
            </div>
          </Card>
        )}

        {/* Parameter Input Section - only show if report has parameters */}
        {reportParams.length > 0 && (
        <div style={{ marginBottom: '16px' }}>
          {/* Show dropdown UI for reports with tenant parameters */}
          {hasTenantParams && !showAdvancedJson && (
            <>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
                <Text style={{ fontWeight: 500 }}>Filter By</Text>
                <Button
                  variant="ghost"
                  size="sm"
                  onClick={() => setShowAdvancedJson(true)}
                  style={{ fontSize: '0.75rem' }}
                >
                  Advanced (JSON)
                </Button>
              </div>

              {/* Two-column layout for filter selectors */}
              <div style={{ display: 'grid', gridTemplateColumns: 'auto 1fr', gap: '16px', alignItems: 'start' }}>
                {/* Filter parameter selector */}
                <div>
                  <Text style={{ display: 'block', marginBottom: '6px', fontSize: '0.75rem', color: 'var(--alga-muted-fg)' }}>
                    Filter Type
                  </Text>
                  <div style={{ minWidth: '180px' }}>
                    <CustomSelect
                      options={filterParamOptions}
                      placeholder="Select..."
                      value={selectedFilterParam}
                      onValueChange={(value) => {
                        setSelectedFilterParam(value);
                        setSelectedFilterValue('');
                        setTenantSearch('');
                      }}
                    />
                  </div>
                </div>

                {/* Value selector with search */}
                {selectedFilterParam && (
                  <div>
                    <Text style={{ display: 'block', marginBottom: '6px', fontSize: '0.75rem', color: 'var(--alga-muted-fg)' }}>
                      {selectedFilterParam === 'tenant' ? 'Select Tenant' :
                       selectedFilterParam === 'email' ? 'Select by Email' : 'Select Company'}
                    </Text>
                    <div style={{ display: 'flex', gap: '8px', alignItems: 'center' }}>
                      <Input
                        type="text"
                        placeholder="Search..."
                        value={tenantSearch}
                        onChange={(e) => setTenantSearch(e.target.value)}
                        style={{ width: '150px' }}
                      />
                      {tenantsLoading ? (
                        <LoadingIndicator size="sm" text="Loading..." />
                      ) : (
                        <div style={{ minWidth: '250px' }}>
                          <CustomSelect
                            options={getFilterValueOptions()}
                            placeholder={`Select...`}
                            value={selectedFilterValue}
                            onValueChange={setSelectedFilterValue}
                          />
                        </div>
                      )}
                    </div>
                  </div>
                )}
              </div>

              {selectedFilterValue && (
                <Text tone="muted" style={{ display: 'block', fontSize: '0.75rem', marginTop: '8px' }}>
                  Will execute with: <code>{
                    (selectedFilterParam === 'email' || selectedFilterParam === 'client_name')
                      ? (() => {
                          const matched = tenants.find(t =>
                            selectedFilterParam === 'email'
                              ? t.email === selectedFilterValue
                              : t.client_name === selectedFilterValue
                          );
                          return matched && tenantParamsInReport.includes('tenant')
                            ? `tenant=${matched.tenant}`
                            : `${selectedFilterParam}=${selectedFilterValue}`;
                        })()
                      : `${selectedFilterParam}=${selectedFilterValue}`
                  }</code>
                </Text>
              )}
            </>
          )}

          {/* Show JSON editor for non-tenant params or when advanced mode is enabled */}
          {(!hasTenantParams || showAdvancedJson) && (
            <>
              <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '6px' }}>
                <Text style={{ fontWeight: 500 }}>Parameters (JSON)</Text>
                <div style={{ display: 'flex', gap: '8px' }}>
                  {hasTenantParams && (
                    <Button
                      variant="ghost"
                      size="sm"
                      onClick={() => setShowAdvancedJson(false)}
                      style={{ fontSize: '0.75rem' }}
                    >
                      Use Dropdowns
                    </Button>
                  )}
                  <Button
                    variant="ghost"
                    size="sm"
                    onClick={() => setShowParamsHelp(!showParamsHelp)}
                    style={{ fontSize: '0.75rem' }}
                  >
                    {showParamsHelp ? 'Hide Help' : 'Help'}
                  </Button>
                </div>
              </div>

              {showParamsHelp && (
                <Card style={{
                  background: 'var(--alga-card-bg)',
                  marginBottom: '12px',
                  fontSize: '0.8rem',
                }}>
                  <div style={{ marginBottom: '12px' }}>
                    <strong>How Parameters Work</strong>
                    <p style={{ margin: '8px 0' }}>
                      In your report filters, use <code style={{ background: 'var(--alga-muted)', padding: '2px 6px', borderRadius: '4px' }}>{'{{param_name}}'}</code> as the value.
                      Then pass the actual value here when executing.
                    </p>
                  </div>

                  {reportParams.length > 0 && (
                    <div style={{ marginBottom: '12px' }}>
                      <strong>Detected Parameters in this Report</strong>
                      <div style={{ display: 'flex', gap: '4px', flexWrap: 'wrap', marginTop: '4px' }}>
                        {reportParams.map(p => (
                          <Badge key={p} tone="info">{p}</Badge>
                        ))}
                      </div>
                    </div>
                  )}

                  <div>
                    <strong>Built-in Parameters (always available)</strong>
                    <ul style={{ margin: '4px 0 0 0', paddingLeft: '20px', fontSize: '0.75rem' }}>
                      <li><code>{'{{start_of_month}}'}</code> - First day of current month</li>
                      <li><code>{'{{end_of_month}}'}</code> - First day of next month</li>
                      <li><code>{'{{start_of_year}}'}</code> - January 1st of current year</li>
                      <li><code>{'{{end_of_year}}'}</code> - January 1st of next year</li>
                    </ul>
                  </div>
                </Card>
              )}

              <TextArea
                value={parameters}
                onChange={(e) => setParameters(e.target.value)}
                rows={3}
                placeholder='{}'
                style={{ fontFamily: 'monospace', fontSize: '0.875rem' }}
              />
              <Text tone="muted" style={{ display: 'block', fontSize: '0.75rem', marginTop: '4px' }}>
                Leave empty <code>{'{}'}</code> to use default parameters
              </Text>
            </>
          )}
        </div>
        )}

        <Button
          onClick={handleExecute}
          disabled={executing || !selectedReportId}
          style={{ minWidth: '150px' }}
        >
          {executing ? (
            <><Spinner size="button" variant="inverted" style={{ marginRight: '8px' }} /> Executing...</>
          ) : 'Execute Report'}
        </Button>
      </Card>

      {error && <Alert tone="danger" style={{ marginTop: '16px' }}>{error}</Alert>}

      {results && (
        <div style={{ marginTop: '16px' }}>
          <h3>Results</h3>
          <ResultsRenderer results={results} report={selectedReport} />
        </div>
      )}
    </div>
  );
}

// Audit event type options for Select
const AUDIT_EVENT_TYPE_OPTIONS: SelectOption[] = [
  { value: '__all__', label: 'All Events' },
  { value: 'report.list', label: 'Report List' },
  { value: 'report.view', label: 'Report View' },
  { value: 'report.create', label: 'Report Create' },
  { value: 'report.update', label: 'Report Update' },
  { value: 'report.delete', label: 'Report Delete' },
  { value: 'report.execute', label: 'Report Execute' },
  { value: 'schema.view', label: 'Schema View' },
  { value: 'extension.access', label: 'Extension Access' },
  { value: 'feature_flag.create', label: 'Flag Create' },
  { value: 'feature_flag.toggle', label: 'Flag Toggle' },
  { value: 'feature_flag.delete', label: 'Flag Delete' },
  { value: 'feature_flag.add_tenant', label: 'Flag Add Tenant' },
  { value: 'feature_flag.remove_tenant', label: 'Flag Remove Tenant' },
  { value: 'feature_flag.enable_all', label: 'Flag Enable All' },
  { value: 'tenant.list', label: 'Tenant List' },
  { value: 'tenant.view', label: 'Tenant View' },
  { value: 'tenant.create', label: 'Tenant Create' },
  { value: 'tenant.resend_email', label: 'Resend Email' },
  { value: 'tenant.cancel_subscription', label: 'Cancel Subscription' },
];

// ActionMenu has been replaced with DropdownMenu from ui-kit

// ============================================================================
// Tenant Management Types and API
// ============================================================================

interface Tenant {
  tenant: string;
  client_name: string;
  email: string | null;
  portal_domain: string | null;
  subscription_status: string | null;
  plan: string | null;
  product_code: string | null;
  subscription?: TenantSubscription | null;
  addons?: TenantAddOn[];
  created_at: string;
}

interface TenantSubscription {
  stripe_subscription_external_id?: string | null;
  status?: string | null;
  quantity?: number | null;
  current_period_end?: string | null;
  billing_interval?: string | null;
  price_billing_interval?: string | null;
  stripe_price_external_id?: string | null;
  unit_amount?: number | null;
  currency?: string | null;
  product_name?: string | null;
  product_type?: string | null;
}

interface TenantAddOn {
  addon_key: string;
  label: string;
  description?: string;
  activated_at?: string | null;
  expires_at?: string | null;
}

interface AddOnDefinition {
  addon_key: string;
  label: string;
  description?: string;
}

interface PendingDeletion {
  deletion_id: string;
  tenant: string;
  tenant_name: string | null;
  trigger_source: string;
  status: string;
  workflow_id: string;
  stats_snapshot: {
    userCount: number;
    activeUserCount: number;
    licenseCount: number;
    ticketCount: number;
    openTicketCount: number;
    invoiceCount: number;
    projectCount: number;
    documentCount: number;
    clientCount: number;
    contactCount: number;
    collectedAt: string;
  } | null;
  confirmation_type: string | null;
  confirmed_by: string | null;
  confirmed_at: string | null;
  deletion_scheduled_for: string | null;
  days_remaining: number | null;
  live_state: {
    step: string;
    status: string;
  } | null;
  created_at: string;
  updated_at: string;
}

type ConfirmationType = 'immediate' | '30_days' | '90_days';

interface TenantManagementResponse<T> {
  success: boolean;
  error?: string;
  data?: T;
  message?: string;
  workflowId?: string;
  tenantId?: string;
  adminUserId?: string;
  email?: string;
  tenantName?: string;
}

// API client for tenant management endpoints
// Uses the internal proxy to avoid CORS issues
async function callTenantManagementApi<T>(
  path: string,
  options: RequestInit = {}
): Promise<TenantManagementResponse<T>> {
  const route = `/api/v1/tenant-management${path}`;

  try {
    // Parse body from options if present
    let body: any = undefined;
    if (options.body && typeof options.body === 'string') {
      try {
        body = JSON.parse(options.body);
      } catch {
        body = options.body;
      }
    }

    const result = await proxyApiCall<any>(route, {
      method: options.method as string || 'GET',
      body,
    });

    // Normalize response format
    if (result && typeof result === 'object') {
      if ('success' in result) {
        return result as TenantManagementResponse<T>;
      }
      if ('data' in result) {
        return { success: true, data: result.data as T };
      }
      return { success: true, data: result as T };
    }
    return { success: true, data: result as T };
  } catch (error) {
    console.error('Tenant Management API call failed:', error);
    return { success: false, error: String(error) };
  }
}

// ============================================================================
// Tenant Management View
// ============================================================================

// Confirmation dialog state type
interface ConfirmAction {
  message: string;
  onConfirm: () => void;
}

function TenantManagementView() {
  const [tenants, setTenants] = useState<Tenant[]>([]);
  const [availableAddOns, setAvailableAddOns] = useState<AddOnDefinition[]>([]);
  const [auditLogs, setAuditLogs] = useState<AuditLogEntry[]>([]);
  const [pendingDeletions, setPendingDeletions] = useState<PendingDeletion[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [actionInProgress, setActionInProgress] = useState<string | null>(null);
  const [showCreateForm, setShowCreateForm] = useState(false);
  const [statusMessage, setStatusMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
  const [confirmAction, setConfirmAction] = useState<ConfirmAction | null>(null);
  const [searchQuery, setSearchQuery] = useState('');
  const [selectedTenantForAddOns, setSelectedTenantForAddOns] = useState<Tenant | null>(null);
  const [createForm, setCreateForm] = useState({
    companyName: '',
    firstName: '',
    lastName: '',
    email: '',
    licenseCount: 5,
    productCode: 'psa',
  });
  // Deletion dialog state
  const [showDeletionDialog, setShowDeletionDialog] = useState(false);
  const [selectedTenantForDeletion, setSelectedTenantForDeletion] = useState<Tenant | null>(null);
  const [deletionReason, setDeletionReason] = useState('');
  // Confirm deletion dialog state
  const [showConfirmDeletionDialog, setShowConfirmDeletionDialog] = useState(false);
  const [selectedPendingDeletion, setSelectedPendingDeletion] = useState<PendingDeletion | null>(null);
  const [confirmationType, setConfirmationType] = useState<ConfirmationType>('90_days');
  // Rollback dialog state
  const [showRollbackDialog, setShowRollbackDialog] = useState(false);
  const [rollbackReason, setRollbackReason] = useState('');
  // Export dialog state
  const [showExportResultDialog, setShowExportResultDialog] = useState(false);
  const [exportResult, setExportResult] = useState<{
    status: 'in_progress' | 'completed';
    tenantName: string;
    workflowId?: string;
    downloadUrl?: string;
    urlExpiresAt?: string;
    tableCount?: number;
    recordCount?: number;
    fileSizeBytes?: number;
    message?: string;
  } | null>(null);
  const [exportPollingInterval, setExportPollingInterval] = useState<NodeJS.Timeout | null>(null);

  // Fetch tenants
  const fetchTenants = useCallback(async () => {
    setLoading(true);
    setError(null);

    const result = await callTenantManagementApi<Tenant[]>('/tenants');
    if (result.success && result.data) {
      setTenants(result.data);
    } else {
      setError(result.error || 'Failed to fetch tenants');
    }
    setLoading(false);
  }, []);

  // Fetch tenant management audit logs (via proxy)
  const fetchAuditLogs = useCallback(async () => {
    try {
      const result = await proxyApiCall<any>(
        '/api/v1/tenant-management/audit?eventTypePrefix=tenant.&limit=50'
      );
      // Handle proxy response format
      const data = result?.data || result;
      if (data && Array.isArray(data)) {
        setAuditLogs(data);
      } else if (result?.success && result?.data) {
        setAuditLogs(result.data);
      }
    } catch (err) {
      console.error('Failed to fetch audit logs:', err);
    }
  }, []);

  // Fetch pending deletions
  const fetchPendingDeletions = useCallback(async () => {
    try {
      const result = await callTenantManagementApi<PendingDeletion[]>('/pending-deletions');
      if (result.success && result.data) {
        setPendingDeletions(result.data);
      }
    } catch (err) {
      console.error('Failed to fetch pending deletions:', err);
    }
  }, []);

  const fetchAvailableAddOns = useCallback(async () => {
    try {
      const result = await callTenantManagementApi<AddOnDefinition[]>('/addons');
      if (result.success && result.data) {
        setAvailableAddOns(result.data);
      }
    } catch (err) {
      console.error('Failed to fetch available add-ons:', err);
    }
  }, []);

  useEffect(() => {
    fetchTenants();
    fetchAvailableAddOns();
    fetchAuditLogs();
    fetchPendingDeletions();
  }, [fetchTenants, fetchAvailableAddOns, fetchAuditLogs, fetchPendingDeletions]);

  // Handle resend welcome email
  const handleResendWelcomeEmail = (tenantId: string, tenantName: string) => {
    setConfirmAction({
      message: `Send new welcome email with reset password to admin of "${tenantName}"?`,
      onConfirm: async () => {
        setConfirmAction(null);
        setActionInProgress(tenantId);
        try {
          const result = await callTenantManagementApi<void>('/resend-welcome-email', {
            method: 'POST',
            body: JSON.stringify({ tenantId }),
          });

          if (result.success) {
            setStatusMessage({ type: 'success', text: result.message || `Welcome email sent` });
            fetchAuditLogs();
          } else {
            setStatusMessage({ type: 'error', text: `Failed: ${result.error}` });
          }
        } catch (err) {
          setStatusMessage({ type: 'error', text: `Error: ${err}` });
        } finally {
          setActionInProgress(null);
        }
      },
    });
  };

  // Handle start Premium trial
  const handleStartPremiumTrial = (tenantId: string, tenantName: string, currentPlan: string | null) => {
    if (currentPlan === 'premium') {
      setStatusMessage({ type: 'error', text: `${tenantName} is already on Premium` });
      return;
    }

    setConfirmAction({
      message: `Start a 30-day Premium trial for "${tenantName}"? This will upgrade them from ${currentPlan || 'Pro'} to Premium with a 30-day trial period. Their card will be charged for Premium when the trial ends.`,
      onConfirm: async () => {
        setConfirmAction(null);
        setActionInProgress(tenantId);
        try {
          const result = await callTenantManagementApi<void>('/start-premium-trial', {
            method: 'POST',
            body: JSON.stringify({ tenantId }),
          });

          if (result.success) {
            setStatusMessage({ type: 'success', text: `Premium trial started for ${tenantName}` });
            fetchTenants(); // Refresh tenant list
            fetchAuditLogs();
          } else {
            setStatusMessage({ type: 'error', text: `Failed: ${result.error}` });
          }
        } catch (err) {
          setStatusMessage({ type: 'error', text: `Error: ${err}` });
        } finally {
          setActionInProgress(null);
        }
      },
    });
  };

  // Handle create tenant
  const handleCreateTenant = () => {
    const { companyName, firstName, lastName, email, licenseCount, productCode } = createForm;

    if (!companyName.trim() || !firstName.trim() || !lastName.trim() || !email.trim()) {
      setStatusMessage({ type: 'error', text: 'Please fill in all required fields' });
      return;
    }

    // Basic email validation
    const emailRegex = /^[^\s@]+@[^\s@]+\.[^\s@]+$/;
    if (!emailRegex.test(email)) {
      setStatusMessage({ type: 'error', text: 'Please enter a valid email address' });
      return;
    }

    setConfirmAction({
      message: `Create tenant "${companyName}" with admin user ${email}?`,
      onConfirm: async () => {
        setConfirmAction(null);
        setActionInProgress('create');
        try {
          const result = await callTenantManagementApi<void>('/create-tenant', {
            method: 'POST',
            body: JSON.stringify({
              companyName: companyName.trim(),
              firstName: firstName.trim(),
              lastName: lastName.trim(),
              email: email.trim(),
              licenseCount,
              productCode,
            }),
          });

          if (result.success) {
            setStatusMessage({ type: 'success', text: result.message || `Tenant "${companyName}" created successfully` });
            setShowCreateForm(false);
            setCreateForm({
              companyName: '',
              firstName: '',
              lastName: '',
              email: '',
              licenseCount: 5,
              productCode: 'psa',
            });
            fetchTenants();
            fetchAuditLogs();
          } else {
            setStatusMessage({ type: 'error', text: `Failed: ${result.error}` });
          }
        } catch (err) {
          setStatusMessage({ type: 'error', text: `Error: ${err}` });
        } finally {
          setActionInProgress(null);
        }
      },
    });
  };

  const handleUpdateTenantAddOn = async (tenant: Tenant, addOnKey: string, action: 'grant' | 'revoke') => {
    setActionInProgress(`${tenant.tenant}:${addOnKey}`);
    try {
      const result = await callTenantManagementApi<void>(
        `/tenants/${encodeURIComponent(tenant.tenant)}/addons`,
        {
          method: 'POST',
          body: JSON.stringify({ addonKey: addOnKey, action }),
        }
      );

      if (result.success) {
        setStatusMessage({ type: 'success', text: result.message || `Add-on ${action === 'grant' ? 'granted' : 'revoked'}` });
        await fetchTenants();
        await fetchAuditLogs();
      } else {
        setStatusMessage({ type: 'error', text: `Failed: ${result.error}` });
      }
    } catch (err) {
      setStatusMessage({ type: 'error', text: `Error: ${err}` });
    } finally {
      setActionInProgress(null);
    }
  };

  // Handle start tenant deletion
  const handleStartDeletion = async () => {
    if (!selectedTenantForDeletion) return;

    setActionInProgress(selectedTenantForDeletion.tenant);
    try {
      const result = await callTenantManagementApi<void>('/start-deletion', {
        method: 'POST',
        body: JSON.stringify({
          tenantId: selectedTenantForDeletion.tenant,
          reason: deletionReason.trim() || 'Manual deletion from extension',
          triggerSource: 'admin_extension',
        }),
      });

      if (result.success) {
        setStatusMessage({
          type: 'success',
          text: `Deletion workflow started for "${selectedTenantForDeletion.client_name}". Workflow ID: ${result.workflowId}`,
        });
        setShowDeletionDialog(false);
        setSelectedTenantForDeletion(null);
        setDeletionReason('');
        fetchTenants();
        fetchAuditLogs();
        fetchPendingDeletions();
      } else {
        setStatusMessage({ type: 'error', text: `Failed to start deletion: ${result.error}` });
      }
    } catch (err) {
      setStatusMessage({ type: 'error', text: `Error: ${err}` });
    } finally {
      setActionInProgress(null);
    }
  };

  // Handle confirm tenant deletion
  const handleConfirmDeletion = async () => {
    if (!selectedPendingDeletion) return;

    setActionInProgress(selectedPendingDeletion.deletion_id);
    try {
      const result = await callTenantManagementApi<void>('/confirm-deletion', {
        method: 'POST',
        body: JSON.stringify({
          workflowId: selectedPendingDeletion.workflow_id,
          type: confirmationType,
        }),
      });

      if (result.success) {
        const delayText = confirmationType === 'immediate' ? 'immediately' :
          confirmationType === '30_days' ? 'in 30 days' : 'in 90 days';
        setStatusMessage({
          type: 'success',
          text: `Deletion confirmed for "${selectedPendingDeletion.tenant_name}". Data will be deleted ${delayText}.`,
        });
        setShowConfirmDeletionDialog(false);
        setSelectedPendingDeletion(null);
        setConfirmationType('90_days');
        fetchPendingDeletions();
        fetchAuditLogs();
      } else {
        setStatusMessage({ type: 'error', text: `Failed to confirm deletion: ${result.error}` });
      }
    } catch (err) {
      setStatusMessage({ type: 'error', text: `Error: ${err}` });
    } finally {
      setActionInProgress(null);
    }
  };

  // Handle rollback tenant deletion
  const handleRollbackDeletion = async () => {
    if (!selectedPendingDeletion) return;

    setActionInProgress(selectedPendingDeletion.deletion_id);
    try {
      const result = await callTenantManagementApi<void>('/rollback-deletion', {
        method: 'POST',
        body: JSON.stringify({
          workflowId: selectedPendingDeletion.workflow_id,
          reason: rollbackReason.trim() || 'Rolled back from extension',
        }),
      });

      if (result.success) {
        setStatusMessage({
          type: 'success',
          text: `Deletion rolled back for "${selectedPendingDeletion.tenant_name}". Users have been reactivated.`,
        });
        setShowRollbackDialog(false);
        setSelectedPendingDeletion(null);
        setRollbackReason('');
        fetchTenants();
        fetchPendingDeletions();
        fetchAuditLogs();
      } else {
        setStatusMessage({ type: 'error', text: `Failed to rollback deletion: ${result.error}` });
      }
    } catch (err) {
      setStatusMessage({ type: 'error', text: `Error: ${err}` });
    } finally {
      setActionInProgress(null);
    }
  };

  // Poll for export status
  const pollExportStatus = async (workflowId: string, tenantName: string) => {
    try {
      const result = await callTenantManagementApi<{
        status: 'pending' | 'in_progress' | 'completed' | 'failed';
        workflowId: string;
        downloadUrl?: string;
        urlExpiresAt?: string;
        tableCount?: number;
        recordCount?: number;
        fileSizeBytes?: number;
        error?: string;
      }>(`/export-status?workflowId=${encodeURIComponent(workflowId)}`);

      if (result.success && result.data) {
        if (result.data.status === 'completed') {
          // Stop polling
          if (exportPollingInterval) {
            clearInterval(exportPollingInterval);
            setExportPollingInterval(null);
          }
          // Update result with completed data
          setExportResult({
            status: 'completed',
            tenantName,
            workflowId,
            downloadUrl: result.data.downloadUrl,
            urlExpiresAt: result.data.urlExpiresAt,
            tableCount: result.data.tableCount,
            recordCount: result.data.recordCount,
            fileSizeBytes: result.data.fileSizeBytes,
          });
          fetchAuditLogs();
        } else if (result.data.status === 'failed') {
          // Stop polling
          if (exportPollingInterval) {
            clearInterval(exportPollingInterval);
            setExportPollingInterval(null);
          }
          setShowExportResultDialog(false);
          setExportResult(null);
          setStatusMessage({ type: 'error', text: `Export failed: ${result.data.error || 'Unknown error'}` });
        }
        // If still in progress, continue polling
      }
    } catch (err) {
      console.error('Error polling export status:', err);
    }
  };

  // Handle export tenant data
  const handleExportTenant = async (tenant: Tenant) => {
    setActionInProgress(tenant.tenant);
    try {
      const result = await callTenantManagementApi<{
        status: 'in_progress' | 'completed';
        workflowId?: string;
        exportId?: string;
        tenantName: string;
        downloadUrl?: string;
        urlExpiresAt?: string;
        tableCount?: number;
        recordCount?: number;
        fileSizeBytes?: number;
        message?: string;
      }>('/export-tenant', {
        method: 'POST',
        body: JSON.stringify({
          tenantId: tenant.tenant,
          reason: 'Manual export from extension',
        }),
      });

      if (result.success && result.data) {
        const data = result.data;

        if (data.status === 'completed') {
          // Export completed immediately
          setExportResult({
            status: 'completed',
            tenantName: data.tenantName || tenant.client_name,
            workflowId: data.workflowId,
            downloadUrl: data.downloadUrl,
            urlExpiresAt: data.urlExpiresAt,
            tableCount: data.tableCount,
            recordCount: data.recordCount,
            fileSizeBytes: data.fileSizeBytes,
          });
          setShowExportResultDialog(true);
          fetchAuditLogs();
        } else if (data.status === 'in_progress' && data.workflowId) {
          // Export is in progress, show dialog and start polling
          setExportResult({
            status: 'in_progress',
            tenantName: data.tenantName || tenant.client_name,
            workflowId: data.workflowId,
            message: data.message || 'Export in progress...',
          });
          setShowExportResultDialog(true);

          // Start polling every 2 seconds
          const interval = setInterval(() => {
            pollExportStatus(data.workflowId!, data.tenantName || tenant.client_name);
          }, 2000);
          setExportPollingInterval(interval);
        } else {
          setStatusMessage({ type: 'error', text: `Unexpected response: ${JSON.stringify(data)}` });
        }
      } else {
        setStatusMessage({ type: 'error', text: `Export failed: ${result.error}` });
      }
    } catch (err) {
      setStatusMessage({ type: 'error', text: `Error: ${err}` });
    } finally {
      setActionInProgress(null);
    }
  };

  // Cleanup polling interval on unmount
  useEffect(() => {
    return () => {
      if (exportPollingInterval) {
        clearInterval(exportPollingInterval);
      }
    };
  }, [exportPollingInterval]);

  // Check if tenant has a pending deletion
  const hasPendingDeletion = (tenantId: string): boolean => {
    return pendingDeletions.some(
      d => d.tenant === tenantId && !['completed', 'rolled_back'].includes(d.status)
    );
  };

  const getStatusBadgeTone = (status: string | null): 'success' | 'warning' | 'info' | 'danger' => {
    if (!status) return 'info';
    if (status === 'active') return 'success';
    if (status === 'canceled' || status === 'cancelled') return 'danger';
    if (status === 'past_due' || status === 'unpaid') return 'warning';
    return 'info';
  };

  const getDeletionStatusBadgeTone = (status: string): 'success' | 'warning' | 'info' | 'danger' => {
    if (status === 'completed') return 'success';
    if (status === 'rolled_back') return 'info';
    if (status === 'awaiting_confirmation' || status === 'pending_deletion') return 'warning';
    if (status === 'deleting') return 'danger';
    return 'info';
  };

  const getAuditStatusBadgeTone = (status: string | null): 'success' | 'warning' | 'info' | 'danger' => {
    if (!status) return 'info';
    if (status === 'completed') return 'success';
    if (status === 'failed') return 'danger';
    if (status === 'pending' || status === 'running') return 'warning';
    return 'info';
  };

  const formatProductCode = (productCode: string | null): string => {
    if (!productCode) return 'PSA';
    if (productCode === 'psa') return 'PSA';
    if (productCode === 'algadesk') return 'AlgaDesk';
    return productCode;
  };

  const formatCurrency = (amount?: number | null, currency?: string | null): string | null => {
    if (amount == null) return null;
    return new Intl.NumberFormat(undefined, {
      style: 'currency',
      currency: (currency || 'usd').toUpperCase(),
    }).format(amount / 100);
  };

  const tenantColumns: Column<Tenant>[] = [
    {
      key: 'client_name',
      header: 'Tenant Name',
      render: (row) => (
        <div>
          <div style={{ fontWeight: 500 }}>{row.client_name}</div>
          <div style={{ fontSize: '0.75rem', color: 'var(--alga-muted-fg)' }}>
            {row.tenant.slice(0, 8)}...
          </div>
        </div>
      ),
    },
    {
      key: 'email',
      header: 'Admin Email',
      render: (row) => (
        <Text style={{ fontSize: '0.875rem' }}>
          {row.email || '—'}
        </Text>
      ),
    },
    {
      key: 'plan',
      header: 'Plan',
      render: (row) => (
        <div style={{ display: 'flex', flexDirection: 'column', gap: '4px' }}>
          <Badge tone={row.plan === 'premium' ? 'info' : 'default'}>
            {row.plan ? row.plan.charAt(0).toUpperCase() + row.plan.slice(1) : '—'}
          </Badge>
          <Text tone="muted" style={{ fontSize: '0.75rem' }}>
            {formatProductCode(row.product_code)}
          </Text>
        </div>
      ),
    },
    {
      key: 'subscription',
      header: 'Subscription Product',
      sortable: false,
      render: (row) => {
        const subscription = row.subscription;
        const price = formatCurrency(subscription?.unit_amount, subscription?.currency);
        return subscription ? (
          <div>
            <Text style={{ display: 'block', fontSize: '0.875rem', fontWeight: 500 }}>
              {subscription.product_name || subscription.product_type || 'Stripe product'}
            </Text>
            <Text tone="muted" style={{ display: 'block', fontSize: '0.75rem' }}>
              {price ? `${price}/${subscription.price_billing_interval || subscription.billing_interval || 'period'}` : subscription.stripe_price_external_id || 'No price'}
              {subscription.quantity ? ` · ${subscription.quantity} seats` : ''}
            </Text>
          </div>
        ) : (
          <Text tone="muted" style={{ fontSize: '0.875rem' }}>Manual / none</Text>
        );
      },
    },
    {
      key: 'addons',
      header: 'Add-ons',
      sortable: false,
      render: (row) => (
        <div style={{ display: 'flex', flexWrap: 'wrap', gap: '4px' }}>
          {(row.addons || []).length === 0 ? (
            <Text tone="muted" style={{ fontSize: '0.75rem' }}>None</Text>
          ) : (
            (row.addons || []).map((addOn) => (
              <Badge key={addOn.addon_key} tone="info">{addOn.label || addOn.addon_key}</Badge>
            ))
          )}
        </div>
      ),
    },
    {
      key: 'subscription_status',
      header: 'Status',
      render: (row) => (
        <Badge tone={getStatusBadgeTone(row.subscription_status)}>
          {row.subscription_status || 'No subscription'}
        </Badge>
      ),
    },
    {
      key: 'created_at',
      header: 'Created',
      render: (row) => (
        <Text tone="muted" style={{ fontSize: '0.875rem' }}>
          {new Date(row.created_at).toLocaleDateString()}
        </Text>
      ),
    },
    {
      key: 'tenant',
      header: 'Actions',
      sortable: false,
      render: (row) => {
        const isPending = hasPendingDeletion(row.tenant);
        const menuItems: DropdownMenuItem[] = [
          {
            key: 'resend',
            label: 'Resend Welcome Email',
            onClick: () => handleResendWelcomeEmail(row.tenant, row.client_name),
          },
          {
            key: 'export',
            label: 'Export Data',
            onClick: () => handleExportTenant(row),
          },
          {
            key: 'addons',
            label: 'Manage Add-ons',
            onClick: () => setSelectedTenantForAddOns(row),
          },
          {
            key: 'premium-trial',
            label: 'Start Premium Trial',
            onClick: () => handleStartPremiumTrial(row.tenant, row.client_name, row.plan),
            disabled: row.plan === 'premium' || row.subscription_status === 'trialing',
          },
          {
            key: 'delete',
            label: isPending ? 'Deletion in Progress...' : 'Delete Tenant',
            onClick: () => {
              setSelectedTenantForDeletion(row);
              setShowDeletionDialog(true);
            },
            disabled: isPending,
            danger: !isPending,
            divider: true,
          },
        ];

        return (
          <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
            <DropdownMenu
              trigger={
                <Button
                  size="sm"
                  disabled={actionInProgress === row.tenant}
                  style={{ minWidth: '80px' }}
                >
                  {actionInProgress === row.tenant ? (
                    <><Spinner size="button" style={{ marginRight: '4px' }} /> Working...</>
                  ) : (
                    <>Actions</>
                  )}
                </Button>
              }
              items={menuItems}
              align="right"
            />
            {isPending && (
              <Badge tone="warning" style={{ fontSize: '0.7rem' }}>
                Deleting
              </Badge>
            )}
          </div>
        );
      },
    },
  ];

  const auditColumns: Column<AuditLogEntry>[] = [
    {
      key: 'created_at',
      header: 'Time',
      width: '20%',
      render: (row) => (
        <Text style={{ fontSize: '0.8125rem', whiteSpace: 'nowrap' }}>
          {new Date(row.created_at).toLocaleString()}
        </Text>
      ),
    },
    {
      key: 'event_type',
      header: 'Event',
      width: '15%',
      render: (row) => {
        const getTone = (type: string): 'success' | 'warning' | 'info' | 'danger' => {
          if (type.includes('create')) return 'success';
          if (type.includes('delete') || type.includes('cancel')) return 'danger';
          return 'info';
        };
        return (
          <Badge tone={getTone(row.event_type)}>
            {row.event_type.replace(/\./g, ' ').replace(/\b\w/g, c => c.toUpperCase())}
          </Badge>
        );
      },
    },
    {
      key: 'user_email',
      header: 'User',
      width: '25%',
      render: (row) => (
        <Text style={{ fontSize: '0.8125rem', wordBreak: 'break-word' }}>
          {row.user_email || 'System'}
        </Text>
      ),
    },
    {
      key: 'status',
      header: 'Status',
      width: '15%',
      render: (row) => row.status ? (
        <Badge tone={getAuditStatusBadgeTone(row.status)}>
          {row.status}
        </Badge>
      ) : null,
    },
    {
      key: 'resource_name',
      header: 'Target',
      width: '25%',
      render: (row) => (
        <Text style={{ fontSize: '0.8125rem', wordBreak: 'break-word' }}>
          {row.resource_name || row.resource_id?.slice(0, 8) || '—'}
        </Text>
      ),
    },
  ];

  const productCodeOptions: SelectOption[] = [
    { value: 'psa', label: 'Alga PSA' },
    { value: 'algadesk', label: 'AlgaDesk' },
  ];

  const currentSelectedTenantForAddOns = selectedTenantForAddOns
    ? tenants.find((tenant) => tenant.tenant === selectedTenantForAddOns.tenant) || selectedTenantForAddOns
    : null;

  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
        <h2 style={{ margin: 0 }}>Tenant Management</h2>
        <div style={{ display: 'flex', gap: '8px' }}>
          <Button variant="outline" onClick={() => { fetchTenants(); fetchAuditLogs(); fetchPendingDeletions(); }} disabled={loading}>
            {loading ? 'Loading...' : 'Refresh'}
          </Button>
          <Button onClick={() => setShowCreateForm(true)}>
            Create Tenant
          </Button>
        </div>
      </div>

      {error && <Alert tone="danger" style={{ marginBottom: '16px' }}>{error}</Alert>}

      {/* Status Message */}
      {statusMessage && (
        <Alert
          tone={statusMessage.type === 'success' ? 'success' : 'danger'}
          style={{ marginBottom: '16px' }}
        >
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <span>{statusMessage.text}</span>
            <Button variant="ghost" size="sm" onClick={() => setStatusMessage(null)}>✕</Button>
          </div>
        </Alert>
      )}

      {/* Confirmation Dialog */}
      <ConfirmDialog
        isOpen={!!confirmAction}
        title="Confirm Action"
        message={confirmAction?.message || ''}
        onConfirm={() => confirmAction?.onConfirm()}
        onCancel={() => setConfirmAction(null)}
      />

      {/* Create Tenant Form */}
      {showCreateForm && (
        <Card style={{ marginBottom: '20px' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}>
            <h3 style={{ margin: 0 }}>Create New Tenant</h3>
            <Button variant="ghost" size="sm" onClick={() => setShowCreateForm(false)}>✕</Button>
          </div>

          <div style={{ display: 'grid', gap: '16px' }}>
            <div>
              <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Company Name *</Text>
              <Input
                type="text"
                value={createForm.companyName}
                onChange={(e) => setCreateForm({ ...createForm, companyName: e.target.value })}
                placeholder="Acme Inc."
              />
            </div>

            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '16px' }}>
              <div>
                <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Admin First Name *</Text>
                <Input
                  type="text"
                  value={createForm.firstName}
                  onChange={(e) => setCreateForm({ ...createForm, firstName: e.target.value })}
                  placeholder="John"
                />
              </div>
              <div>
                <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Admin Last Name *</Text>
                <Input
                  type="text"
                  value={createForm.lastName}
                  onChange={(e) => setCreateForm({ ...createForm, lastName: e.target.value })}
                  placeholder="Doe"
                />
              </div>
            </div>

            <div>
              <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Admin Email *</Text>
              <Input
                type="email"
                value={createForm.email}
                onChange={(e) => setCreateForm({ ...createForm, email: e.target.value })}
                placeholder="admin@company.com"
              />
            </div>

            <div>
              <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Licensed Users</Text>
              <Input
                type="number"
                min={1}
                value={createForm.licenseCount}
                onChange={(e) => setCreateForm({ ...createForm, licenseCount: parseInt(e.target.value) || 5 })}
              />
              <Text tone="muted" style={{ fontSize: '0.75rem', marginTop: '4px' }}>
                Number of licensed users for the tenant
              </Text>
            </div>

            <div>
              <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Product Code</Text>
              <CustomSelect
                options={productCodeOptions}
                value={createForm.productCode}
                onValueChange={(value) => setCreateForm({ ...createForm, productCode: value })}
              />
              <Text tone="muted" style={{ fontSize: '0.75rem', marginTop: '4px' }}>
                Selects the product-specific onboarding bootstrap and welcome email flow.
              </Text>
            </div>

            <div style={{ display: 'flex', gap: '8px', justifyContent: 'flex-end', marginTop: '8px' }}>
              <Button variant="secondary" onClick={() => setShowCreateForm(false)}>
                Cancel
              </Button>
              <Button
                onClick={handleCreateTenant}
                disabled={actionInProgress === 'create'}
              >
                {actionInProgress === 'create' ? 'Creating...' : 'Create Tenant'}
              </Button>
            </div>
          </div>
        </Card>
      )}

      {currentSelectedTenantForAddOns && (
        <Card style={{ marginBottom: '20px' }}>
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', gap: '16px', marginBottom: '16px' }}>
            <div>
              <h3 style={{ margin: 0 }}>Manage Add-ons</h3>
              <Text tone="muted" style={{ display: 'block', fontSize: '0.875rem', marginTop: '4px' }}>
                {currentSelectedTenantForAddOns.client_name} · {formatProductCode(currentSelectedTenantForAddOns.product_code)} · {currentSelectedTenantForAddOns.plan || 'No plan'}
              </Text>
            </div>
            <Button variant="ghost" size="sm" onClick={() => setSelectedTenantForAddOns(null)}>X</Button>
          </div>

          <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(240px, 1fr))', gap: '12px' }}>
            {availableAddOns.map((definition) => {
              const active = (currentSelectedTenantForAddOns.addons || []).some(
                (addOn) => addOn.addon_key === definition.addon_key
              );
              const progressKey = `${currentSelectedTenantForAddOns.tenant}:${definition.addon_key}`;

              return (
                <div
                  key={definition.addon_key}
                  style={{
                    border: '1px solid var(--alga-border)',
                    borderRadius: '8px',
                    padding: '12px',
                    background: active ? 'var(--alga-primary-50)' : 'var(--alga-card-bg)',
                  }}
                >
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: '8px', marginBottom: '6px' }}>
                    <Text style={{ fontWeight: 600 }}>{definition.label}</Text>
                    <Badge tone={active ? 'success' : 'default'}>{active ? 'Active' : 'Not granted'}</Badge>
                  </div>
                  {definition.description && (
                    <Text tone="muted" style={{ display: 'block', fontSize: '0.75rem', minHeight: '34px' }}>
                      {definition.description}
                    </Text>
                  )}
                  <Button
                    size="sm"
                    variant={active ? 'destructive' : 'primary'}
                    style={{ marginTop: '12px' }}
                    disabled={actionInProgress === progressKey}
                    onClick={() => handleUpdateTenantAddOn(
                      currentSelectedTenantForAddOns,
                      definition.addon_key,
                      active ? 'revoke' : 'grant'
                    )}
                  >
                    {actionInProgress === progressKey
                      ? 'Working...'
                      : active ? 'Revoke' : 'Grant'}
                  </Button>
                </div>
              );
            })}
          </div>
        </Card>
      )}

      {/* Tenants List */}
      <Card style={{ marginBottom: '20px' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}>
          <h3 style={{ margin: 0 }}>Tenants</h3>
          <div style={{ width: '300px' }}>
            <Input
              type="text"
              placeholder="Search tenants..."
              value={searchQuery}
              onChange={(e) => setSearchQuery(e.target.value)}
            />
          </div>
        </div>
        {loading ? (
          <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '150px' }}>
            <LoadingIndicator size="md" text="Loading tenants..." layout="stacked" />
          </div>
        ) : tenants.length === 0 ? (
          <Text tone="muted">No tenants found.</Text>
        ) : (
          <>
            {(() => {
              const filteredTenants = searchQuery.trim()
                ? tenants.filter(t => {
                  const query = searchQuery.toLowerCase();
                  return t.client_name.toLowerCase().includes(query) ||
                    t.tenant.toLowerCase().includes(query) ||
                    (t.email && t.email.toLowerCase().includes(query)) ||
                    (t.product_code && t.product_code.toLowerCase().includes(query)) ||
                    (t.plan && t.plan.toLowerCase().includes(query)) ||
                    (t.addons || []).some((addOn) =>
                      addOn.addon_key.toLowerCase().includes(query) ||
                      addOn.label.toLowerCase().includes(query)
                    ) ||
                    Boolean(t.subscription?.product_name?.toLowerCase().includes(query));
                })
                : tenants;

              return filteredTenants.length === 0 ? (
                <Text tone="muted">No tenants match "{searchQuery}"</Text>
              ) : (
                <DataTable
                  columns={tenantColumns}
                  data={filteredTenants}
                  paginate
                  defaultPageSize={10}
                  initialSortKey="client_name"
                />
              );
            })()}
          </>
        )}
      </Card>

      {/* Pending Deletions Section */}
      {pendingDeletions.length > 0 && (
        <Card style={{ marginBottom: '20px' }}>
          <h3 style={{ marginTop: 0, marginBottom: '16px', color: 'var(--alga-warning)' }}>
            Pending Deletions ({pendingDeletions.filter(d => !['completed', 'rolled_back'].includes(d.status)).length})
          </h3>
          <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
            {pendingDeletions
              .filter(d => !['completed', 'rolled_back'].includes(d.status))
              .map((deletion) => (
                <div
                  key={deletion.deletion_id}
                  style={{
                    padding: '12px',
                    border: '1px solid var(--alga-border)',
                    borderRadius: '8px',
                    backgroundColor: 'var(--alga-surface)',
                  }}
                >
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'flex-start', marginBottom: '8px' }}>
                    <div>
                      <Text style={{ fontWeight: 600 }}>{deletion.tenant_name || deletion.tenant}</Text>
                      <div style={{ display: 'flex', gap: '8px', marginTop: '4px' }}>
                        <Badge tone={getDeletionStatusBadgeTone(deletion.status)}>
                          {deletion.status.replace(/_/g, ' ')}
                        </Badge>
                        <Badge tone="info">
                          {deletion.trigger_source === 'stripe_webhook' ? 'Stripe' : 'Manual'}
                        </Badge>
                        {deletion.days_remaining !== null && (
                          <Badge tone={deletion.days_remaining <= 7 ? 'danger' : 'warning'}>
                            {deletion.days_remaining} days remaining
                          </Badge>
                        )}
                      </div>
                    </div>
                    <div style={{ display: 'flex', gap: '8px' }}>
                      {deletion.status === 'awaiting_confirmation' && (
                        <Button
                          variant="primary"
                          size="sm"
                          onClick={() => {
                            setSelectedPendingDeletion(deletion);
                            setShowConfirmDeletionDialog(true);
                          }}
                          disabled={actionInProgress === deletion.deletion_id}
                        >
                          Confirm
                        </Button>
                      )}
                      {['awaiting_confirmation', 'pending_deletion'].includes(deletion.status) && (
                        <Button
                          variant="secondary"
                          size="sm"
                          onClick={() => {
                            setSelectedPendingDeletion(deletion);
                            setShowRollbackDialog(true);
                          }}
                          disabled={actionInProgress === deletion.deletion_id}
                        >
                          Rollback
                        </Button>
                      )}
                    </div>
                  </div>
                  {deletion.stats_snapshot && (
                    <div style={{ display: 'flex', gap: '16px', flexWrap: 'wrap', fontSize: '0.8125rem', color: 'var(--alga-muted-fg)' }}>
                      <span>Users: {deletion.stats_snapshot.userCount} ({deletion.stats_snapshot.activeUserCount} active)</span>
                      <span>Tickets: {deletion.stats_snapshot.ticketCount} ({deletion.stats_snapshot.openTicketCount} open)</span>
                      <span>Invoices: {deletion.stats_snapshot.invoiceCount}</span>
                      <span>Projects: {deletion.stats_snapshot.projectCount}</span>
                    </div>
                  )}
                  <Text tone="muted" style={{ fontSize: '0.75rem', marginTop: '8px' }}>
                    Started: {new Date(deletion.created_at).toLocaleString()}
                    {deletion.confirmed_at && ` | Confirmed: ${new Date(deletion.confirmed_at).toLocaleString()}`}
                  </Text>
                </div>
              ))}
          </div>
        </Card>
      )}

      {/* Start Deletion Dialog */}
      <ConfirmDialog
        isOpen={showDeletionDialog}
        title="Start Tenant Deletion"
        message={`Are you sure you want to start the deletion process for "${selectedTenantForDeletion?.client_name}"? This will:\n\n• Deactivate all users\n• Cancel Stripe subscription (if active)\n• Tag the client as "Canceled"\n\nThe tenant will not be deleted immediately - you'll need to confirm the deletion timing.`}
        onConfirm={handleStartDeletion}
        onCancel={() => {
          setShowDeletionDialog(false);
          setSelectedTenantForDeletion(null);
          setDeletionReason('');
        }}
        confirmText={actionInProgress === selectedTenantForDeletion?.tenant ? 'Starting...' : 'Start Deletion'}
        confirmDisabled={actionInProgress === selectedTenantForDeletion?.tenant}
      >
        <div style={{ marginTop: '12px' }}>
          <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Reason (optional)</Text>
          <Input
            type="text"
            value={deletionReason}
            onChange={(e) => setDeletionReason(e.target.value)}
            placeholder="e.g., Customer requested cancellation"
          />
        </div>
      </ConfirmDialog>

      {/* Confirm Deletion Timing Dialog */}
      <ConfirmDialog
        isOpen={showConfirmDeletionDialog}
        title="Confirm Deletion Timing"
        message={`Choose when to permanently delete all data for "${selectedPendingDeletion?.tenant_name}".`}
        onConfirm={handleConfirmDeletion}
        onCancel={() => {
          setShowConfirmDeletionDialog(false);
          setSelectedPendingDeletion(null);
          setConfirmationType('90_days');
        }}
        confirmText={actionInProgress === selectedPendingDeletion?.deletion_id ? 'Confirming...' : 'Confirm Deletion'}
        confirmDisabled={actionInProgress === selectedPendingDeletion?.deletion_id}
      >
        <div style={{ marginTop: '12px' }}>
          <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Deletion Timing</Text>
          <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
            <label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
              <input
                type="radio"
                name="confirmationType"
                value="90_days"
                checked={confirmationType === '90_days'}
                onChange={() => setConfirmationType('90_days')}
              />
              <span>90 days (recommended for data retention compliance)</span>
            </label>
            <label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
              <input
                type="radio"
                name="confirmationType"
                value="30_days"
                checked={confirmationType === '30_days'}
                onChange={() => setConfirmationType('30_days')}
              />
              <span>30 days</span>
            </label>
            <label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer', color: 'var(--alga-danger)' }}>
              <input
                type="radio"
                name="confirmationType"
                value="immediate"
                checked={confirmationType === 'immediate'}
                onChange={() => setConfirmationType('immediate')}
              />
              <span>Immediately (irreversible!)</span>
            </label>
          </div>
          {selectedPendingDeletion?.stats_snapshot && (
            <Alert tone="warning" style={{ marginTop: '12px' }}>
              <Text style={{ fontWeight: 500 }}>Data to be deleted:</Text>
              <ul style={{ margin: '8px 0 0', paddingLeft: '20px' }}>
                <li>{selectedPendingDeletion.stats_snapshot.userCount} users</li>
                <li>{selectedPendingDeletion.stats_snapshot.ticketCount} tickets</li>
                <li>{selectedPendingDeletion.stats_snapshot.invoiceCount} invoices</li>
                <li>{selectedPendingDeletion.stats_snapshot.projectCount} projects</li>
                <li>{selectedPendingDeletion.stats_snapshot.documentCount} documents</li>
              </ul>
            </Alert>
          )}
        </div>
      </ConfirmDialog>

      {/* Rollback Deletion Dialog */}
      <ConfirmDialog
        isOpen={showRollbackDialog}
        title="Rollback Deletion"
        message={`Are you sure you want to rollback the deletion for "${selectedPendingDeletion?.tenant_name}"? This will:\n\n• Reactivate all users\n• Remove the "Canceled" tag\n• Cancel the scheduled deletion`}
        onConfirm={handleRollbackDeletion}
        onCancel={() => {
          setShowRollbackDialog(false);
          setSelectedPendingDeletion(null);
          setRollbackReason('');
        }}
        confirmText={actionInProgress === selectedPendingDeletion?.deletion_id ? 'Rolling back...' : 'Rollback'}
        confirmDisabled={actionInProgress === selectedPendingDeletion?.deletion_id}
      >
        <div style={{ marginTop: '12px' }}>
          <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Reason (optional)</Text>
          <Input
            type="text"
            value={rollbackReason}
            onChange={(e) => setRollbackReason(e.target.value)}
            placeholder="e.g., Customer renewed subscription"
          />
        </div>
      </ConfirmDialog>

      {/* Export Result Dialog */}
      <ConfirmDialog
        isOpen={showExportResultDialog}
        title={exportResult?.status === 'in_progress' ? 'Export In Progress' : 'Export Complete'}
        message={exportResult ? (
          exportResult.status === 'in_progress'
            ? `Exporting data for "${exportResult.tenantName}"...`
            : `Successfully exported data for "${exportResult.tenantName}".`
        ) : ''}
        onConfirm={() => {
          if (exportResult?.status === 'completed' && exportResult?.downloadUrl) {
            window.open(exportResult.downloadUrl, '_blank');
          }
          if (exportResult?.status === 'completed') {
            setShowExportResultDialog(false);
            setExportResult(null);
          }
        }}
        onCancel={() => {
          // Stop polling if in progress
          if (exportPollingInterval) {
            clearInterval(exportPollingInterval);
            setExportPollingInterval(null);
          }
          setShowExportResultDialog(false);
          setExportResult(null);
        }}
        confirmText={exportResult?.status === 'in_progress' ? 'Please wait...' : 'Download'}
        cancelLabel="Close"
        confirmDisabled={exportResult?.status === 'in_progress'}
      >
        {exportResult && exportResult.status === 'in_progress' && (
          <div style={{ marginTop: '12px' }}>
            <div style={{
              display: 'flex',
              alignItems: 'center',
              justifyContent: 'center',
              padding: '24px',
            }}>
              <Spinner size="sm" />
            </div>
            <Alert tone="info">
              Large exports may take a few minutes. You can close this dialog and check the audit log for status.
            </Alert>
          </div>
        )}
        {exportResult && exportResult.status === 'completed' && (
          <div style={{ marginTop: '12px' }}>
            <div style={{
              backgroundColor: 'var(--alga-surface)',
              border: '1px solid var(--alga-border)',
              borderRadius: '8px',
              padding: '12px',
            }}>
              <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '8px', fontSize: '0.875rem' }}>
                <div>
                  <Text tone="muted">Tables:</Text>
                  <Text style={{ fontWeight: 500 }}>{exportResult.tableCount ?? '-'}</Text>
                </div>
                <div>
                  <Text tone="muted">Records:</Text>
                  <Text style={{ fontWeight: 500 }}>{exportResult.recordCount?.toLocaleString() ?? '-'}</Text>
                </div>
                <div>
                  <Text tone="muted">File Size:</Text>
                  <Text style={{ fontWeight: 500 }}>{exportResult.fileSizeBytes ? ((exportResult.fileSizeBytes / 1024 / 1024).toFixed(2) + ' MB') : '-'}</Text>
                </div>
                <div>
                  <Text tone="muted">Expires:</Text>
                  <Text style={{ fontWeight: 500 }}>{exportResult.urlExpiresAt ? new Date(exportResult.urlExpiresAt).toLocaleTimeString() : '-'}</Text>
                </div>
              </div>
            </div>
            <Alert tone="info" style={{ marginTop: '12px' }}>
              The download link expires in 1 hour. Click "Download" to save the export file.
            </Alert>
          </div>
        )}
      </ConfirmDialog>

      {/* Recent Actions (Audit Log) */}
      <Card>
        <h3 style={{ marginTop: 0, marginBottom: '16px' }}>Recent Actions</h3>
        {auditLogs.length === 0 ? (
          <Text tone="muted">No recent tenant management actions.</Text>
        ) : (
          <DataTable
            columns={auditColumns}
            data={auditLogs}
            paginate
            defaultPageSize={5}
          />
        )}
      </Card>
    </div>
  );
}

function AuditLogs() {
  const PAGE_SIZE = 50;
  const [logs, setLogs] = useState<AuditLogEntry[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [eventTypeFilter, setEventTypeFilter] = useState('__all__');
  const [resourceIdFilter, setResourceIdFilter] = useState('');
  const [page, setPage] = useState(0);
  const [hasMore, setHasMore] = useState(true);

  const fetchLogs = useCallback(async (pageNum: number = 0) => {
    setLoading(true);
    setError(null);

    const params = new URLSearchParams();
    if (eventTypeFilter && eventTypeFilter !== '__all__') params.set('eventType', eventTypeFilter);
    if (resourceIdFilter) params.set('resourceId', resourceIdFilter);
    params.set('limit', String(PAGE_SIZE));
    params.set('offset', String(pageNum * PAGE_SIZE));

    const queryString = params.toString();
    const path = queryString ? `/audit?${queryString}` : '/audit';

    const result = await callExtensionApi<AuditLogEntry[]>(path);

    if (result.success && result.data) {
      setLogs(result.data);
      setHasMore(result.data.length >= PAGE_SIZE);
    } else {
      setError(result.error || 'Failed to fetch audit logs');
    }
    setLoading(false);
  }, [eventTypeFilter, resourceIdFilter]);

  useEffect(() => {
    setPage(0);
    fetchLogs(0);
  }, [fetchLogs]);

  const handlePrevPage = () => {
    if (page > 0) {
      const newPage = page - 1;
      setPage(newPage);
      fetchLogs(newPage);
    }
  };

  const handleNextPage = () => {
    if (hasMore) {
      const newPage = page + 1;
      setPage(newPage);
      fetchLogs(newPage);
    }
  };

  const formatEventType = (type: string): string => {
    return type
      .replace(/\./g, ' ')
      .replace(/\b\w/g, c => c.toUpperCase());
  };

  const getEventBadgeTone = (type: string): 'success' | 'warning' | 'info' | 'danger' => {
    if (type.includes('create')) return 'success';
    if (type.includes('delete')) return 'danger';
    if (type.includes('update')) return 'warning';
    return 'info';
  };

  const columns: Column<AuditLogEntry>[] = [
    {
      key: 'created_at',
      header: 'Time',
      width: '15%',
      render: (row) => (
        <Text style={{ fontSize: '0.8125rem', whiteSpace: 'nowrap' }}>
          {new Date(row.created_at).toLocaleString()}
        </Text>
      ),
    },
    {
      key: 'event_type',
      header: 'Event',
      width: '12%',
      render: (row) => (
        <Badge tone={getEventBadgeTone(row.event_type)}>
          {formatEventType(row.event_type)}
        </Badge>
      ),
    },
    {
      key: 'user_email',
      header: 'User',
      width: '20%',
      render: (row) => (
        <div>
          {row.user_email ? (
            <>
              <div style={{ fontWeight: 500, wordBreak: 'break-word' }}>{row.user_email}</div>
              {row.user_id && (
                <div style={{ fontSize: '0.75rem', color: 'var(--alga-muted-fg)' }}>
                  {row.user_id.slice(0, 8)}...
                </div>
              )}
            </>
          ) : (
            <Text tone="muted">System</Text>
          )}
        </div>
      ),
    },
    {
      key: 'resource_name',
      header: 'Resource',
      width: '18%',
      render: (row) => row.resource_name ? (
        <div>
          <div style={{ fontWeight: 500, wordBreak: 'break-word' }}>{row.resource_name}</div>
          <div style={{ display: 'flex', gap: '8px', fontSize: '0.75rem', color: 'var(--alga-muted-fg)' }}>
            {row.resource_type && <span>{row.resource_type}</span>}
            {row.resource_id && <span>{row.resource_id.slice(0, 8)}...</span>}
          </div>
        </div>
      ) : (
        <Text tone="muted">—</Text>
      ),
    },
    {
      key: 'details',
      header: 'Details',
      width: '25%',
      render: (row) => row.details ? (
        <details style={{ fontSize: '0.8125rem' }}>
          <summary style={{
            cursor: 'pointer',
            color: 'var(--alga-primary-foreground)',
            fontWeight: 500,
            padding: '6px 10px',
            background: 'var(--alga-primary)',
            borderRadius: 'var(--alga-radius, 8px)',
            display: 'inline-block',
            fontSize: '12px',
          }}>
            View
          </summary>
          <pre style={{
            marginTop: '8px',
            fontSize: '0.75rem',
            background: 'var(--alga-bg)',
            color: 'var(--alga-fg)',
            padding: '12px',
            borderRadius: 'var(--alga-radius, 6px)',
            overflow: 'auto',
            maxHeight: '200px',
            whiteSpace: 'pre-wrap',
            wordBreak: 'break-word',
            border: '1px solid var(--alga-border)',
          }}>
            {JSON.stringify(row.details, null, 2)}
          </pre>
        </details>
      ) : (
        <Text tone="muted">—</Text>
      ),
    },
    {
      key: 'ip_address',
      header: 'IP',
      width: '10%',
      render: (row) => (
        <Text tone="muted" style={{ fontSize: '0.75rem' }}>
          {row.ip_address || '—'}
        </Text>
      ),
    },
  ];

  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '20px' }}>
        <h2 style={{ margin: 0 }}>Audit Logs</h2>
        <Button variant="outline" onClick={() => fetchLogs(page)} disabled={loading}>
          {loading ? 'Loading...' : 'Refresh'}
        </Button>
      </div>

      <Card style={{ marginBottom: '16px' }}>
        <div style={{ display: 'flex', gap: '16px', flexWrap: 'wrap', alignItems: 'flex-end' }}>
          <div style={{ minWidth: '200px' }}>
            <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Event Type</Text>
            <CustomSelect
              options={AUDIT_EVENT_TYPE_OPTIONS}
              value={eventTypeFilter}
              onValueChange={setEventTypeFilter}
            />
          </div>
          <div style={{ minWidth: '200px' }}>
            <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Resource ID</Text>
            <Input
              type="text"
              value={resourceIdFilter}
              onChange={(e) => setResourceIdFilter(e.target.value)}
              placeholder="Filter by resource ID..."
            />
          </div>
        </div>
      </Card>

      {error && <Alert tone="danger" style={{ marginBottom: '16px' }}>{error}</Alert>}

      {loading ? (
        <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '200px' }}>
          <LoadingIndicator size="md" text="Loading audit logs..." layout="stacked" />
        </div>
      ) : logs.length === 0 ? (
        <Card>
          <Text tone="muted">
            No audit logs found. Activity will be recorded here when reports are accessed.
          </Text>
        </Card>
      ) : (
        <>
          <DataTable
            columns={columns}
            data={logs}
            initialSortKey="created_at"
            initialSortDir="desc"
          />
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginTop: '12px' }}>
            <Text tone="muted" style={{ fontSize: '0.8125rem' }}>
              Page {page + 1} &middot; Showing {logs.length} entries
            </Text>
            <div style={{ display: 'flex', gap: '8px' }}>
              <Button
                variant="outline"
                size="sm"
                onClick={handlePrevPage}
                disabled={page === 0 || loading}
              >
                Previous
              </Button>
              <Button
                variant="outline"
                size="sm"
                onClick={handleNextPage}
                disabled={!hasMore || loading}
              >
                Next
              </Button>
            </div>
          </div>
        </>
      )}
    </div>
  );
}

// Edit Report component
function EditReport({
  report,
  onBack,
  onSave,
}: {
  report: PlatformReport;
  onBack: () => void;
  onSave: () => void;
}) {
  const [name, setName] = useState(report.name);
  const [description, setDescription] = useState(report.description || '');
  const [category, setCategory] = useState(report.category || '');
  const [isActive, setIsActive] = useState(report.is_active);
  const [metrics, setMetrics] = useState<MetricDefinition[]>(
    report.report_definition.metrics || []
  );
  const [saving, setSaving] = useState(false);
  const [error, setError] = useState<string | null>(null);

  // Use dynamic schema from server
  const { tables, tableOptions, getTableColumns, loading: schemaLoading } = useSchema();

  // Track which metrics are in "raw SQL" mode
  // Initialize from existing metrics that have table === 'raw_sql'
  const [rawSqlMode, setRawSqlMode] = useState<{ [key: string]: boolean }>(() => {
    const initial: { [key: string]: boolean } = {};
    (report.report_definition.metrics || []).forEach(m => {
      if (m.query.table === 'raw_sql') {
        initial[m.id] = true;
      }
    });
    return initial;
  });
  const [rawSqlText, setRawSqlText] = useState<{ [key: string]: string }>(() => {
    const initial: { [key: string]: string } = {};
    (report.report_definition.metrics || []).forEach(m => {
      if (m.query.table === 'raw_sql' && m.query.fields?.[0]) {
        initial[m.id] = m.query.fields[0];
      }
    });
    return initial;
  });
  // Table search filter
  const [tableSearch, setTableSearch] = useState('');

  // Filtered table options based on search
  const filteredTableOptions = tableOptions.filter(opt =>
    opt.label.toLowerCase().includes(tableSearch.toLowerCase())
  );

  const updateMetric = (index: number, updates: Partial<MetricDefinition>) => {
    const newMetrics = [...metrics];
    newMetrics[index] = { ...newMetrics[index], ...updates };
    setMetrics(newMetrics);
  };

  const updateQuery = (index: number, updates: Partial<QueryDefinition>) => {
    const newMetrics = [...metrics];
    newMetrics[index] = {
      ...newMetrics[index],
      query: { ...newMetrics[index].query, ...updates },
    };
    setMetrics(newMetrics);
  };

  const removeMetric = (index: number) => {
    setMetrics(metrics.filter((_, i) => i !== index));
  };

  const moveMetric = (index: number, direction: 'up' | 'down') => {
    const newIndex = direction === 'up' ? index - 1 : index + 1;
    if (newIndex < 0 || newIndex >= metrics.length) return;
    const newMetrics = [...metrics];
    [newMetrics[index], newMetrics[newIndex]] = [newMetrics[newIndex], newMetrics[index]];
    setMetrics(newMetrics);
  };

  const addMetric = () => {
    const defaultTable = tables.length > 0 ? tables[0].name : '';
    setMetrics([
      ...metrics,
      {
        id: `metric_${Date.now()}`,
        name: '',
        type: 'count',
        query: {
          table: defaultTable,
          fields: ['COUNT(*) as count'],
          filters: [],
          groupBy: [],
        },
      },
    ]);
  };

  const addFilter = (metricIndex: number) => {
    const newMetrics = [...metrics];
    const filters = [...(newMetrics[metricIndex].query.filters || [])];
    filters.push({ field: '', operator: 'eq', value: '' });
    newMetrics[metricIndex].query.filters = filters;
    setMetrics(newMetrics);
  };

  const updateFilter = (metricIndex: number, filterIndex: number, updates: Partial<FilterDefinition>) => {
    const newMetrics = [...metrics];
    const filters = [...(newMetrics[metricIndex].query.filters || [])];
    filters[filterIndex] = { ...filters[filterIndex], ...updates };
    newMetrics[metricIndex].query.filters = filters;
    setMetrics(newMetrics);
  };

  const removeFilter = (metricIndex: number, filterIndex: number) => {
    const newMetrics = [...metrics];
    newMetrics[metricIndex].query.filters = (newMetrics[metricIndex].query.filters || [])
      .filter((_, i) => i !== filterIndex);
    setMetrics(newMetrics);
  };

  const addJoin = (metricIndex: number) => {
    const newMetrics = [...metrics];
    const joins = [...(newMetrics[metricIndex].query.joins || [])];
    const defaultTable = tables.length > 0 ? tables[0].name : '';
    joins.push({
      type: 'left',
      table: defaultTable,
      on: [{ left: '', right: '' }],
    });
    newMetrics[metricIndex].query.joins = joins;
    setMetrics(newMetrics);
  };

  const updateJoin = (metricIndex: number, joinIndex: number, updates: Partial<JoinDefinition>) => {
    const newMetrics = [...metrics];
    const joins = [...(newMetrics[metricIndex].query.joins || [])];
    joins[joinIndex] = { ...joins[joinIndex], ...updates };
    newMetrics[metricIndex].query.joins = joins;
    setMetrics(newMetrics);
  };

  const updateJoinCondition = (
    metricIndex: number,
    joinIndex: number,
    conditionIndex: number,
    updates: Partial<JoinCondition>
  ) => {
    const newMetrics = [...metrics];
    const joins = [...(newMetrics[metricIndex].query.joins || [])];
    const conditions = [...joins[joinIndex].on];
    conditions[conditionIndex] = { ...conditions[conditionIndex], ...updates };
    joins[joinIndex] = { ...joins[joinIndex], on: conditions };
    newMetrics[metricIndex].query.joins = joins;
    setMetrics(newMetrics);
  };

  const addJoinCondition = (metricIndex: number, joinIndex: number) => {
    const newMetrics = [...metrics];
    const joins = [...(newMetrics[metricIndex].query.joins || [])];
    joins[joinIndex] = {
      ...joins[joinIndex],
      on: [...joins[joinIndex].on, { left: '', right: '' }],
    };
    newMetrics[metricIndex].query.joins = joins;
    setMetrics(newMetrics);
  };

  const removeJoinCondition = (metricIndex: number, joinIndex: number, conditionIndex: number) => {
    const newMetrics = [...metrics];
    const joins = [...(newMetrics[metricIndex].query.joins || [])];
    joins[joinIndex] = {
      ...joins[joinIndex],
      on: joins[joinIndex].on.filter((_, i) => i !== conditionIndex),
    };
    newMetrics[metricIndex].query.joins = joins;
    setMetrics(newMetrics);
  };

  const removeJoin = (metricIndex: number, joinIndex: number) => {
    const newMetrics = [...metrics];
    newMetrics[metricIndex].query.joins = (newMetrics[metricIndex].query.joins || [])
      .filter((_, i) => i !== joinIndex);
    setMetrics(newMetrics);
  };

  const addLabel = (metricIndex: number) => {
    const newMetrics = [...metrics];
    const labels = [...(newMetrics[metricIndex].conditionalLabels || [])];
    labels.push({ column: '', operator: 'gte', value: 0, tone: 'warning', label: '' });
    newMetrics[metricIndex].conditionalLabels = labels;
    setMetrics(newMetrics);
  };

  const updateLabel = (metricIndex: number, labelIndex: number, updates: Partial<ConditionalLabel>) => {
    const newMetrics = [...metrics];
    const labels = [...(newMetrics[metricIndex].conditionalLabels || [])];
    labels[labelIndex] = { ...labels[labelIndex], ...updates };
    newMetrics[metricIndex].conditionalLabels = labels;
    setMetrics(newMetrics);
  };

  const removeLabel = (metricIndex: number, labelIndex: number) => {
    const newMetrics = [...metrics];
    newMetrics[metricIndex].conditionalLabels = (newMetrics[metricIndex].conditionalLabels || [])
      .filter((_, i) => i !== labelIndex);
    setMetrics(newMetrics);
  };

  const handleSave = async () => {
    setSaving(true);
    setError(null);

    if (!name.trim()) {
      setError('Report name is required');
      setSaving(false);
      return;
    }

    const updatedDefinition: ReportDefinition = {
      ...report.report_definition,
      name,
      description,
      category,
      metrics,
    };

    const result = await callExtensionApi(`/${report.report_id}`, {
      method: 'PUT',
      body: JSON.stringify({
        name,
        description: description || null,
        category: category || null,
        is_active: isActive,
        report_definition: updatedDefinition,
      }),
    });

    if (result.success) {
      onSave();
      onBack();
    } else {
      setError(result.error || 'Failed to update report');
    }
    setSaving(false);
  };

  // Get all field options from base table + all joined tables (for filters)
  const getAllFieldOptions = (metric: MetricDefinition): SelectOption[] => {
    const options: SelectOption[] = [];

    // Base table columns
    if (metric.query.table) {
      getTableColumns(metric.query.table).forEach(col => {
        options.push({ value: col, label: col });
      });
    }

    // Joined table columns (with table prefix)
    (metric.query.joins || []).forEach(join => {
      if (join.table) {
        getTableColumns(join.table).forEach(col => {
          const fullCol = `${join.table}.${col}`;
          options.push({ value: fullCol, label: fullCol });
        });
      }
    });

    return options;
  };

  // Get all columns from base table AND all joined tables
  const getAllMetricColumns = (metric: MetricDefinition): { table: string; columns: string[] }[] => {
    const result: { table: string; columns: string[] }[] = [];

    // Base table columns
    if (metric.query.table) {
      result.push({
        table: metric.query.table,
        columns: getTableColumns(metric.query.table),
      });
    }

    // Joined table columns
    (metric.query.joins || []).forEach(join => {
      if (join.table) {
        result.push({
          table: join.table,
          columns: getTableColumns(join.table),
        });
      }
    });

    return result;
  };

  return (
    <div>
      <Button
        variant="ghost"
        style={{ marginBottom: '20px' }}
        onClick={onBack}
      >
        ← Back to Report
      </Button>

      <h2 style={{ marginTop: 0 }}>Edit Report</h2>

      <Card style={{ marginBottom: '16px' }}>
        <h3 style={{ marginTop: 0 }}>Basic Information</h3>

        <div style={{ marginBottom: '16px' }}>
          <Label required>Report Name</Label>
          <Input
            type="text"
            value={name}
            onChange={(e) => setName(e.target.value)}
            placeholder="e.g., Tenant User Summary"
            style={{ width: '100%', marginTop: '6px' }}
          />
        </div>

        <div style={{ marginBottom: '16px' }}>
          <Label>Description</Label>
          <TextArea
            value={description}
            onChange={(e) => setDescription(e.target.value)}
            placeholder="Describe what this report shows..."
            rows={3}
            style={{ marginTop: '6px' }}
          />
        </div>

        <div style={{ marginBottom: '16px' }}>
          <Label>Category</Label>
          <CategorySelect value={category} onChange={setCategory} />
        </div>

        <div style={{ marginBottom: '16px' }}>
          <label style={{ display: 'flex', alignItems: 'center', gap: '8px', cursor: 'pointer' }}>
            <input
              type="checkbox"
              checked={isActive}
              onChange={(e) => setIsActive(e.target.checked)}
            />
            <Text style={{ fontWeight: 500 }}>Active</Text>
          </label>
          <Text tone="muted" style={{ display: 'block', fontSize: '0.75rem', marginTop: '4px' }}>
            Inactive reports cannot be executed
          </Text>
        </div>
      </Card>

      <Card style={{ marginBottom: '16px' }}>
        <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}>
          <h3 style={{ margin: 0 }}>Metrics</h3>
          <Button type="button" onClick={addMetric}>
            + Add Metric
          </Button>
        </div>

        {metrics.length === 0 ? (
          <Text tone="muted">
            No metrics defined. Click "Add Metric" to add one.
          </Text>
        ) : (
          <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
            {metrics.map((metric, index) => (
              <Card
                key={metric.id}
                style={{ background: 'var(--alga-card-bg)' }}
              >
                <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
                  <div style={{ display: 'flex', alignItems: 'center', gap: '8px' }}>
                    <strong>Metric {index + 1}</strong>
                    <div style={{ display: 'flex', gap: '4px' }}>
                      <Button
                        type="button"
                        variant="ghost"
                        size="sm"
                        onClick={() => moveMetric(index, 'up')}
                        disabled={index === 0}
                        title="Move up"
                      >
                        ↑
                      </Button>
                      <Button
                        type="button"
                        variant="ghost"
                        size="sm"
                        onClick={() => moveMetric(index, 'down')}
                        disabled={index === metrics.length - 1}
                        title="Move down"
                      >
                        ↓
                      </Button>
                    </div>
                  </div>
                  <Button
                    type="button"
                    variant="destructive"
                    size="sm"
                    onClick={() => removeMetric(index)}
                  >
                    Remove
                  </Button>
                </div>

                <div style={{ marginBottom: '16px' }}>
                  <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Metric Name</Text>
                  <Input
                    type="text"
                    value={metric.name}
                    onChange={(e) => updateMetric(index, { name: e.target.value })}
                    placeholder="e.g., Active Users Count"
                    style={{ width: '100%' }}
                  />
                </div>

                <div style={{ marginBottom: '16px' }}>
                  <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Metric Type</Text>
                  <CustomSelect
                    options={METRIC_TYPE_OPTIONS}
                    value={metric.type}
                    onValueChange={(value) => updateMetric(index, { type: value as 'count' | 'sum' | 'avg' | 'query' })}
                  />
                </div>

                {/* Mode Toggle: Builder vs Raw SQL */}
                <div style={{ marginBottom: '16px', display: 'flex', gap: '8px', alignItems: 'center' }}>
                  <Text style={{ fontWeight: 500, fontSize: '0.875rem' }}>Mode:</Text>
                  <div style={{ display: 'flex', gap: '4px' }}>
                    <Button
                      type="button"
                      variant={!rawSqlMode[metric.id] ? 'primary' : 'secondary'}
                      size="sm"
                      onClick={() => setRawSqlMode(prev => ({ ...prev, [metric.id]: false }))}
                    >
                      Builder
                    </Button>
                    <Button
                      type="button"
                      variant={rawSqlMode[metric.id] ? 'primary' : 'secondary'}
                      size="sm"
                      onClick={() => {
                        setRawSqlMode(prev => ({ ...prev, [metric.id]: true }));
                        // Initialize raw SQL from current query if not set
                        if (!rawSqlText[metric.id]) {
                          // If already in raw_sql mode, use the existing SQL from fields[0]
                          if (metric.query.table === 'raw_sql' && metric.query.fields?.[0]) {
                            setRawSqlText(prev => ({ ...prev, [metric.id]: metric.query.fields[0] }));
                          } else {
                            // Generate SQL from builder state
                            const fields = metric.query.fields.join(', ') || '*';
                            const from = metric.query.table || 'table_name';
                            let sql = `SELECT ${fields}\nFROM ${from}`;
                            if ((metric.query.joins || []).length > 0) {
                              metric.query.joins!.forEach(j => {
                                const joinType = j.type.toUpperCase();
                                const onClauses = j.on.map(c => `${c.left} = ${c.right}`).join(' AND ');
                                sql += `\n${joinType} JOIN ${j.table} ON ${onClauses}`;
                              });
                            }
                            if ((metric.query.filters || []).length > 0) {
                              const whereClause = metric.query.filters!.map(f => `${f.field} ${f.operator} '${f.value}'`).join(' AND ');
                              sql += `\nWHERE ${whereClause}`;
                            }
                            if ((metric.query.groupBy || []).length > 0) {
                              sql += `\nGROUP BY ${metric.query.groupBy!.join(', ')}`;
                            }
                            setRawSqlText(prev => ({ ...prev, [metric.id]: sql }));
                          }
                        }
                      }}
                    >
                      Raw SQL
                    </Button>
                  </div>
                  <Text tone="muted" style={{ fontSize: '0.7rem', marginLeft: '8px' }}>
                    {rawSqlMode[metric.id] ? 'Write SQL directly' : 'Point-and-click query builder'}
                  </Text>
                </div>

                {rawSqlMode[metric.id] ? (
                  /* Raw SQL Mode */
                  <div style={{ marginBottom: '16px' }}>
                    <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>SQL Query</Text>
                    <textarea
                      value={rawSqlText[metric.id] || ''}
                      onChange={(e) => {
                        setRawSqlText(prev => ({ ...prev, [metric.id]: e.target.value }));
                        // Store raw SQL in the query as a custom field
                        updateQuery(index, {
                          table: 'raw_sql',
                          fields: [e.target.value],
                        });
                      }}
                      placeholder="SELECT column1, column2&#10;FROM table_name&#10;WHERE condition&#10;GROUP BY column1"
                      style={{
                        width: '100%',
                        minHeight: '200px',
                        fontFamily: 'monospace',
                        fontSize: '0.875rem',
                        padding: '12px',
                        border: '1px solid var(--alga-border)',
                        borderRadius: 'var(--alga-radius)',
                        background: '#1f2937',
                        color: '#f9fafb',
                        resize: 'vertical',
                      }}
                    />
                    <Text tone="muted" style={{ display: 'block', fontSize: '0.7rem', marginTop: '4px' }}>
                      Write your SQL query. Only SELECT statements are allowed. Blocked tables and columns will be rejected.
                    </Text>
                  </div>
                ) : (
                  /* Builder Mode */
                  <>
                <div style={{ marginBottom: '16px' }}>
                  <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Table</Text>
                  <Input
                    type="text"
                    placeholder="Search tables..."
                    value={tableSearch}
                    onChange={(e) => setTableSearch(e.target.value)}
                    style={{ marginBottom: '6px' }}
                  />
                  <CustomSelect
                    options={filteredTableOptions}
                    value={metric.query.table}
                    onValueChange={(value) => updateQuery(index, { table: value, fields: ['COUNT(*) as count'] })}
                    disabled={schemaLoading}
                  />
                  {schemaLoading && (
                    <LoadingIndicator size="xs" text="Loading available tables..." style={{ marginTop: '4px' }} />
                  )}
                  {!schemaLoading && filteredTableOptions.length === 0 && tableSearch && (
                    <Text tone="muted" style={{ display: 'block', fontSize: '0.75rem', marginTop: '4px' }}>
                      No tables match "{tableSearch}"
                    </Text>
                  )}
                </div>

                {/* Joins Section */}
                <div style={{ marginBottom: '16px' }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
                    <Text style={{ fontWeight: 500 }}>Joins</Text>
                    <Button
                      type="button"
                      size="sm"
                      onClick={() => addJoin(index)}
                    >
                      + Add Join
                    </Button>
                  </div>

                  {(metric.query.joins || []).length === 0 ? (
                    <Text tone="muted" style={{ fontSize: '0.75rem' }}>
                      No joins. Add a join to query data from multiple tables.
                    </Text>
                  ) : (
                    <div style={{ display: 'flex', flexDirection: 'column', gap: '12px' }}>
                      {(metric.query.joins || []).map((join, joinIndex) => (
                        <Card key={joinIndex} style={{ background: 'var(--alga-muted)', padding: '12px' }}>
                          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
                            <Badge tone="info">Join {joinIndex + 1}</Badge>
                            <Button
                              type="button"
                              variant="destructive"
                              size="sm"
                              onClick={() => removeJoin(index, joinIndex)}
                            >
                              Remove
                            </Button>
                          </div>

                          <div style={{ display: 'flex', gap: '8px', marginBottom: '8px' }}>
                            <div style={{ flex: 1 }}>
                              <Text style={{ display: 'block', fontSize: '0.75rem', marginBottom: '4px' }}>Join Type</Text>
                              <CustomSelect
                                options={JOIN_TYPE_OPTIONS}
                                value={join.type}
                                onValueChange={(value) => updateJoin(index, joinIndex, { type: value as JoinType })}
                              />
                            </div>
                            <div style={{ flex: 2 }}>
                              <Text style={{ display: 'block', fontSize: '0.75rem', marginBottom: '4px' }}>Join Table</Text>
                              <CustomSelect
                                options={tableOptions}
                                value={join.table}
                                onValueChange={(value) => updateJoin(index, joinIndex, { table: value })}
                              />
                            </div>
                          </div>

                          <div style={{ marginBottom: '8px' }}>
                            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '4px' }}>
                              <Text style={{ fontSize: '0.75rem' }}>ON Conditions</Text>
                              <Button
                                type="button"
                                variant="ghost"
                                size="sm"
                                onClick={() => addJoinCondition(index, joinIndex)}
                                style={{ fontSize: '0.75rem', padding: '2px 8px' }}
                              >
                                + Add
                              </Button>
                            </div>

                            {join.on.map((condition, conditionIndex) => (
                              <div
                                key={conditionIndex}
                                style={{ display: 'flex', gap: '4px', alignItems: 'center', marginBottom: '4px' }}
                              >
                                <Input
                                  type="text"
                                  value={condition.left}
                                  onChange={(e) => updateJoinCondition(index, joinIndex, conditionIndex, { left: e.target.value })}
                                  placeholder={`${metric.query.table}.column`}
                                  style={{ flex: 1, fontSize: '0.8125rem' }}
                                />
                                <Text style={{ fontSize: '0.75rem', color: 'var(--alga-muted-fg)' }}>=</Text>
                                <Input
                                  type="text"
                                  value={condition.right}
                                  onChange={(e) => updateJoinCondition(index, joinIndex, conditionIndex, { right: e.target.value })}
                                  placeholder={`${join.table}.column`}
                                  style={{ flex: 1, fontSize: '0.8125rem' }}
                                />
                                {join.on.length > 1 && (
                                  <Button
                                    type="button"
                                    variant="destructive"
                                    size="sm"
                                    onClick={() => removeJoinCondition(index, joinIndex, conditionIndex)}
                                    style={{ padding: '2px 6px', fontSize: '0.75rem' }}
                                  >
                                    X
                                  </Button>
                                )}
                              </div>
                            ))}
                          </div>

                          <Text tone="muted" style={{ display: 'block', fontSize: '0.7rem' }}>
                            Available in {join.table}: {getTableColumns(join.table).slice(0, 5).join(', ')}
                            {getTableColumns(join.table).length > 5 && '...'}
                          </Text>
                        </Card>
                      ))}
                    </div>
                  )}
                </div>

                <div style={{ marginBottom: '16px' }}>
                  <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Fields</Text>

                  {/* Selected fields as removable chips */}
                  <div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px', marginBottom: '8px', minHeight: '32px', padding: '8px', background: 'var(--alga-bg)', border: '1px solid var(--alga-border)', borderRadius: 'var(--alga-radius)' }}>
                    {metric.query.fields.length === 0 ? (
                      <Text tone="muted" style={{ fontSize: '0.75rem' }}>No fields selected. Click columns below to add.</Text>
                    ) : (
                      metric.query.fields.map((field, fieldIndex) => (
                        <Badge
                          key={fieldIndex}
                          tone="info"
                          style={{ cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: '4px' }}
                          onClick={() => updateQuery(index, { fields: metric.query.fields.filter((_, i) => i !== fieldIndex) })}
                        >
                          {field}
                          <span style={{ marginLeft: '4px', fontWeight: 'bold' }}>×</span>
                        </Badge>
                      ))
                    )}
                  </div>

                  {/* Available columns - click to add (from ALL tables including joins) */}
                  <Text tone="muted" style={{ display: 'block', fontSize: '0.75rem', marginBottom: '4px' }}>
                    Click to add column:
                  </Text>
                  {getAllMetricColumns(metric).map(({ table, columns }) => (
                    <div key={table} style={{ marginBottom: '8px' }}>
                      <Text style={{ display: 'block', fontSize: '0.7rem', fontWeight: 500, color: 'var(--alga-primary)', marginBottom: '4px' }}>
                        {table}:
                      </Text>
                      <div style={{ display: 'flex', flexWrap: 'wrap', gap: '4px' }}>
                        {columns.map((col) => {
                          const fullCol = `${table}.${col}`;
                          const isSelected = metric.query.fields.includes(col) || metric.query.fields.includes(fullCol);
                          return (
                            <Button
                              key={col}
                              type="button"
                              variant="secondary"
                              size="sm"
                              style={{ fontSize: '0.75rem', padding: '2px 8px' }}
                              onClick={() => {
                                if (!isSelected) {
                                  // Use table.column format for joined tables, just column for base table
                                  const colName = table === metric.query.table ? col : fullCol;
                                  updateQuery(index, { fields: [...metric.query.fields, colName] });
                                }
                              }}
                              disabled={isSelected}
                            >
                              {col}
                            </Button>
                          );
                        })}
                      </div>
                    </div>
                  ))}

                  {/* Custom expression input */}
                  <div style={{ display: 'flex', gap: '8px' }}>
                    <Input
                      type="text"
                      id={`edit-custom-field-${index}`}
                      placeholder="Custom: COUNT(*) as count, SUM(amount), etc."
                      style={{ flex: 1 }}
                      onKeyDown={(e) => {
                        if (e.key === 'Enter') {
                          e.preventDefault();
                          const input = e.target as HTMLInputElement;
                          const value = input.value.trim();
                          if (value && !metric.query.fields.includes(value)) {
                            updateQuery(index, { fields: [...metric.query.fields, value] });
                            input.value = '';
                          }
                        }
                      }}
                    />
                    <Button
                      type="button"
                      variant="secondary"
                      size="sm"
                      onClick={() => {
                        const input = document.getElementById(`edit-custom-field-${index}`) as HTMLInputElement;
                        if (input) {
                          const value = input.value.trim();
                          if (value && !metric.query.fields.includes(value)) {
                            updateQuery(index, { fields: [...metric.query.fields, value] });
                            input.value = '';
                          }
                        }
                      }}
                    >
                      Add
                    </Button>
                  </div>
                </div>

                <div style={{ marginBottom: '16px' }}>
                  <Text style={{ display: 'block', marginBottom: '6px', fontWeight: 500 }}>Group By</Text>

                  {/* Selected group by fields as removable chips */}
                  <div style={{ display: 'flex', flexWrap: 'wrap', gap: '6px', marginBottom: '8px', minHeight: '28px', padding: '6px', background: 'var(--alga-bg)', border: '1px solid var(--alga-border)', borderRadius: 'var(--alga-radius)' }}>
                    {(metric.query.groupBy || []).length === 0 ? (
                      <Text tone="muted" style={{ fontSize: '0.75rem' }}>No grouping. Click columns below to add.</Text>
                    ) : (
                      (metric.query.groupBy || []).map((field, fieldIndex) => (
                        <Badge
                          key={fieldIndex}
                          tone="info"
                          style={{ cursor: 'pointer', display: 'inline-flex', alignItems: 'center', gap: '4px' }}
                          onClick={() => updateQuery(index, { groupBy: (metric.query.groupBy || []).filter((_, i) => i !== fieldIndex) })}
                        >
                          {field}
                          <span style={{ marginLeft: '4px', fontWeight: 'bold' }}>×</span>
                        </Badge>
                      ))
                    )}
                  </div>

                  {/* Available columns - click to add (from ALL tables including joins) */}
                  {getAllMetricColumns(metric).map(({ table, columns }) => (
                    <div key={table} style={{ marginBottom: '8px' }}>
                      <Text style={{ display: 'block', fontSize: '0.7rem', fontWeight: 500, color: 'var(--alga-primary)', marginBottom: '4px' }}>
                        {table}:
                      </Text>
                      <div style={{ display: 'flex', flexWrap: 'wrap', gap: '4px' }}>
                        {columns.map((col) => {
                          const fullCol = `${table}.${col}`;
                          const currentGroupBy = metric.query.groupBy || [];
                          const isSelected = currentGroupBy.includes(col) || currentGroupBy.includes(fullCol);
                          return (
                            <Button
                              key={col}
                              type="button"
                              variant="secondary"
                              size="sm"
                              style={{ fontSize: '0.7rem', padding: '2px 6px' }}
                              onClick={() => {
                                if (!isSelected) {
                                  const colName = table === metric.query.table ? col : fullCol;
                                  updateQuery(index, { groupBy: [...currentGroupBy, colName] });
                                }
                              }}
                              disabled={isSelected}
                            >
                              {col}
                            </Button>
                          );
                        })}
                      </div>
                    </div>
                  ))}
                </div>

                <div style={{ marginBottom: '12px' }}>
                  <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
                    <Text style={{ fontWeight: 500 }}>Filters</Text>
                    <Button
                      type="button"
                      variant="secondary"
                      size="sm"
                      onClick={() => addFilter(index)}
                    >
                      + Add Filter
                    </Button>
                  </div>

                  {(metric.query.filters || []).map((filter, filterIndex) => (
                    <div
                      key={filterIndex}
                      style={{
                        display: 'flex',
                        gap: '8px',
                        marginBottom: '8px',
                        alignItems: 'center',
                      }}
                    >
                      <CustomSelect
                        options={getAllFieldOptions(metric)}
                        placeholder="Select field..."
                        value={filter.field}
                        onValueChange={(value) => updateFilter(index, filterIndex, { field: value })}
                        style={{ flex: 1 }}
                      />
                      <CustomSelect
                        options={OPERATOR_OPTIONS}
                        value={filter.operator}
                        onValueChange={(value) => updateFilter(index, filterIndex, { operator: value as FilterDefinition['operator'] })}
                        style={{ width: '100px' }}
                      />
                      <Input
                        type="text"
                        value={String(filter.value)}
                        onChange={(e) => updateFilter(index, filterIndex, { value: e.target.value })}
                        placeholder="Value"
                        style={{ flex: 1 }}
                      />
                      <Button
                        type="button"
                        variant="destructive"
                        size="sm"
                        onClick={() => removeFilter(index, filterIndex)}
                      >
                        X
                      </Button>
                    </div>
                  ))}
                </div>
                  </>
                )}

                  {/* Conditional Labels Section */}
                  <div style={{ marginTop: '16px', borderTop: '1px solid var(--alga-border)', paddingTop: '16px' }}>
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '8px' }}>
                      <Text style={{ fontWeight: 500 }}>Conditional Labels</Text>
                      <Button
                        type="button"
                        variant="secondary"
                        size="sm"
                        onClick={() => addLabel(index)}
                      >
                        + Add Label
                      </Button>
                    </div>

                    {(metric.conditionalLabels || []).length === 0 ? (
                      <Text tone="muted" style={{ fontSize: '0.75rem' }}>
                        No labels. Add conditional labels to highlight values with colored badges (e.g. "Danger Zone" when risk_score &gt;= 4).
                      </Text>
                    ) : (
                      <div style={{ display: 'flex', flexDirection: 'column', gap: '8px' }}>
                        {(metric.conditionalLabels || []).map((label, labelIndex) => (
                          <div
                            key={labelIndex}
                            style={{
                              display: 'flex',
                              gap: '6px',
                              alignItems: 'center',
                              padding: '8px',
                              background: 'var(--alga-muted)',
                              borderRadius: 'var(--alga-radius)',
                            }}
                          >
                            <Input
                              type="text"
                              value={label.column}
                              onChange={(e) => updateLabel(index, labelIndex, { column: e.target.value })}
                              placeholder="Column"
                              style={{ width: '120px', fontSize: '0.8125rem' }}
                            />
                            <CustomSelect
                              options={LABEL_OPERATOR_OPTIONS}
                              value={label.operator}
                              onValueChange={(value) => updateLabel(index, labelIndex, { operator: value as ConditionalLabel['operator'] })}
                              style={{ width: '70px' }}
                            />
                            <Input
                              type="number"
                              value={String(label.value)}
                              onChange={(e) => updateLabel(index, labelIndex, { value: Number(e.target.value) })}
                              placeholder="Value"
                              style={{ width: '80px', fontSize: '0.8125rem' }}
                            />
                            <CustomSelect
                              options={LABEL_TONE_OPTIONS}
                              value={label.tone}
                              onValueChange={(value) => updateLabel(index, labelIndex, { tone: value as ConditionalLabel['tone'] })}
                              style={{ width: '140px' }}
                            />
                            <Input
                              type="text"
                              value={label.label || ''}
                              onChange={(e) => updateLabel(index, labelIndex, { label: e.target.value })}
                              placeholder="Badge text"
                              style={{ flex: 1, fontSize: '0.8125rem' }}
                            />
                            <Button
                              type="button"
                              variant="destructive"
                              size="sm"
                              onClick={() => removeLabel(index, labelIndex)}
                            >
                              X
                            </Button>
                          </div>
                        ))}
                      </div>
                    )}
                    <Text tone="muted" style={{ display: 'block', fontSize: '0.7rem', marginTop: '6px' }}>
                      Labels are evaluated in order — first match wins. Put stricter rules first (e.g. &gt;= 30 before &gt;= 14). Only works on numeric values.
                    </Text>
                  </div>
              </Card>
            ))}
          </div>
        )}
      </Card>

      {error && <Alert tone="danger" style={{ marginBottom: '16px' }}>{error}</Alert>}

      <div style={{ display: 'flex', gap: '8px' }}>
        <Button onClick={handleSave} disabled={saving}>
          {saving ? 'Saving...' : 'Save Changes'}
        </Button>
        <Button variant="secondary" onClick={onBack}>
          Cancel
        </Button>
      </div>
    </div>
  );
}

// ============================================================================
// Feature Flags View
// ============================================================================

function FeatureFlagsView() {
  const [flags, setFlags] = useState<PostHogFeatureFlag[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [selectedFlag, setSelectedFlag] = useState<PostHogFeatureFlag | null>(null);
  const [showCreateForm, setShowCreateForm] = useState(false);
  const [statusMessage, setStatusMessage] = useState<{ type: 'success' | 'error'; text: string } | null>(null);
  const [searchQuery, setSearchQuery] = useState('');
  const [tenantFilter, setTenantFilter] = useState('');
  const [allTenants, setAllTenants] = useState<Record<string, Tenant>>({});

  // Get tenant IDs from a flag's release conditions
  const getFlagTenants = (flag: PostHogFeatureFlag): string[] => {
    const tenants: string[] = [];
    if (flag.filters?.groups) {
      for (const group of flag.filters.groups) {
        for (const prop of group.properties || []) {
          if (prop.key === 'tenant' && Array.isArray(prop.value)) {
            tenants.push(...prop.value);
          }
        }
      }
    }
    return [...new Set(tenants)];
  };

  const filteredFlags = flags.filter(flag => {
    // Text search on key/name
    if (searchQuery) {
      const q = searchQuery.toLowerCase();
      if (!flag.key.toLowerCase().includes(q) && !(flag.name || '').toLowerCase().includes(q)) return false;
    }
    // Tenant filter
    if (tenantFilter) {
      const tenantIds = getFlagTenants(flag);
      if (!tenantIds.includes(tenantFilter)) return false;
    }
    return true;
  });

  const fetchFlags = useCallback(async () => {
    setLoading(true);
    setError(null);
    const result = await callFeatureFlagApi<PostHogFeatureFlag[]>('');
    if (result.success && result.data) {
      setFlags(result.data);
      setSelectedFlag((current) => {
        if (!current) return result.data?.[0] || null;
        return result.data?.find((flag) => flag.id === current.id) || result.data?.[0] || null;
      });
    } else {
      setError(result.error || 'Failed to fetch feature flags');
    }
    setLoading(false);
  }, []);

  // Fetch tenant names for inline display
  useEffect(() => {
    callTenantManagementApi<Tenant[]>('/tenants').then(result => {
      if (result.success && result.data) {
        const map: Record<string, Tenant> = {};
        for (const t of result.data) map[t.tenant] = t;
        setAllTenants(map);
      }
    });
  }, []);

  useEffect(() => {
    fetchFlags();
  }, [fetchFlags]);

  // Get rollout summary
  const getRolloutSummary = (flag: PostHogFeatureFlag): string => {
    if (!flag.filters?.groups?.length) return 'No conditions';
    const tenants = getFlagTenants(flag);
    if (tenants.length > 0) {
      return `${tenants.length} tenant(s)`;
    }
    const group = flag.filters.groups[0];
    if (group.rollout_percentage != null) {
      return `${group.rollout_percentage}% rollout`;
    }
    return `${flag.filters.groups.length} group(s)`;
  };

  const tenantFilterOptions: SelectOption[] = [
    { value: '__all__', label: 'All tenants' },
    ...(() => {
      const tenantIds = new Set<string>();
      for (const flag of flags) {
        for (const tid of getFlagTenants(flag)) tenantIds.add(tid);
      }
      return Array.from(tenantIds)
        .map(tid => ({
          value: tid,
          label: allTenants[tid]?.client_name || tid.slice(0, 12) + '...',
        }))
        .sort((a, b) => a.label.localeCompare(b.label));
    })(),
  ];

  return (
    <div>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '12px' }}>
        <h2 style={{ margin: 0 }}>Feature Flags</h2>
        <div style={{ display: 'flex', gap: '8px' }}>
          <Button variant="outline" onClick={fetchFlags} disabled={loading}>
            {loading ? 'Loading...' : 'Refresh'}
          </Button>
          <Button onClick={() => setShowCreateForm(true)}>
            Create Flag
          </Button>
        </div>
      </div>

      <div style={{ display: 'flex', gap: '8px', marginBottom: '16px' }}>
        <Input
          type="text"
          placeholder="Search flags by key or name..."
          value={searchQuery}
          onChange={(e) => setSearchQuery(e.target.value)}
          style={{ flex: 1 }}
        />
        <CustomSelect
          options={tenantFilterOptions}
          value={tenantFilter || '__all__'}
          onValueChange={(v) => setTenantFilter(v === '__all__' ? '' : v)}
          placeholder="Filter by tenant..."
          style={{ minWidth: '200px' }}
        />
      </div>

      {error && <Alert tone="danger" style={{ marginBottom: '16px' }}>{error}</Alert>}

      {statusMessage && (
        <Alert
          tone={statusMessage.type === 'success' ? 'success' : 'danger'}
          style={{ marginBottom: '16px' }}
        >
          <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
            <span>{statusMessage.text}</span>
            <Button variant="ghost" size="sm" onClick={() => setStatusMessage(null)}>X</Button>
          </div>
        </Alert>
      )}

      {/* Create Flag Form */}
      {showCreateForm && (
        <CreateFeatureFlagForm
          onClose={() => setShowCreateForm(false)}
          onCreated={() => {
            setShowCreateForm(false);
            fetchFlags();
            setStatusMessage({ type: 'success', text: 'Feature flag created successfully' });
          }}
        />
      )}

      {loading ? (
        <div style={{ display: 'flex', justifyContent: 'center', alignItems: 'center', minHeight: '200px' }}>
          <LoadingIndicator size="md" text="Loading feature flags..." layout="stacked" />
        </div>
      ) : flags.length === 0 ? (
        <Card>
          <Text tone="muted">
            No feature flags found. Create your first flag to get started.
          </Text>
        </Card>
      ) : filteredFlags.length === 0 ? (
        <Card>
          <Text tone="muted">
            No flags matching "{searchQuery}"
          </Text>
        </Card>
      ) : (
        <div style={{ display: 'grid', gridTemplateColumns: 'repeat(auto-fit, minmax(min(100%, 420px), 1fr))', gap: '16px', alignItems: 'start' }}>
          <Card style={{ padding: 0, overflow: 'hidden' }}>
            <div style={{ padding: '12px 14px', borderBottom: '1px solid var(--alga-border)', display: 'flex', justifyContent: 'space-between', alignItems: 'center' }}>
              <Text style={{ fontWeight: 600 }}>Flags</Text>
              <Badge tone="info">{filteredFlags.length}</Badge>
            </div>
            <div style={{ maxHeight: '680px', overflowY: 'auto' }}>
              {filteredFlags.map((flag) => {
                const tenantIds = getFlagTenants(flag);
                const selected = selectedFlag?.id === flag.id;
                return (
                  <button
                    key={flag.id}
                    type="button"
                    onClick={() => setSelectedFlag(flag)}
                    style={{
                      width: '100%',
                      textAlign: 'left',
                      padding: '12px 14px',
                      border: 'none',
                      borderBottom: '1px solid var(--alga-border)',
                      background: selected ? 'var(--alga-primary-50)' : 'var(--alga-card-bg)',
                      cursor: 'pointer',
                    }}
                  >
                    <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', gap: '8px' }}>
                      <Text style={{ fontFamily: 'monospace', fontWeight: 600, fontSize: '0.875rem' }}>
                        {flag.key}
                      </Text>
                      <Badge tone={flag.active ? 'success' : 'warning'}>{flag.active ? 'Active' : 'Inactive'}</Badge>
                    </div>
                    {flag.name && (
                      <Text tone="muted" style={{ display: 'block', fontSize: '0.75rem', marginTop: '3px' }}>
                        {flag.name}
                      </Text>
                    )}
                    <div style={{ display: 'flex', gap: '6px', flexWrap: 'wrap', marginTop: '8px' }}>
                      <Badge tone="default">{getRolloutSummary(flag)}</Badge>
                      <Text tone="muted" style={{ fontSize: '0.75rem' }}>
                        Created {new Date(flag.created_at).toLocaleDateString()}
                      </Text>
                    </div>
                    {tenantIds.length > 0 && (
                      <div style={{ display: 'flex', flexWrap: 'wrap', gap: '4px', marginTop: '8px' }}>
                        {tenantIds.slice(0, 3).map((tenantId) => (
                          <Badge key={tenantId} tone="info">
                            {allTenants[tenantId]?.client_name || tenantId.slice(0, 8)}
                          </Badge>
                        ))}
                        {tenantIds.length > 3 && <Badge tone="default">+{tenantIds.length - 3}</Badge>}
                      </div>
                    )}
                  </button>
                );
              })}
            </div>
          </Card>

          <Card>
            {selectedFlag ? (
              <>
                <div style={{ marginBottom: '16px' }}>
                  <Text style={{ display: 'block', fontFamily: 'monospace', fontSize: '1rem', fontWeight: 700 }}>
                    {selectedFlag.key}
                  </Text>
                  {selectedFlag.name && (
                    <Text tone="muted" style={{ display: 'block', marginTop: '4px' }}>{selectedFlag.name}</Text>
                  )}
                </div>
                <FeatureFlagDetail
                  flag={selectedFlag}
                  onUpdate={() => {
                    fetchFlags();
                    setStatusMessage({ type: 'success', text: 'Flag updated successfully' });
                  }}
                  onDelete={() => {
                    setSelectedFlag(null);
                    fetchFlags();
                    setStatusMessage({ type: 'success', text: 'Flag deleted successfully' });
                  }}
                />
              </>
            ) : (
              <Text tone="muted">Select a feature flag to manage rollout.</Text>
            )}
          </Card>
        </div>
      )}
    </div>
  );
}

function CreateFeatureFlagForm({
  onClose,
  onCreated,
}: {
  onClose: () => void;
  onCreated: () => void;
}) {
  const [key, setKey] = useState('');
  const [name, setName] = useState('');
  const [active, setActive] = useState(true);
  const [creating, setCreating] = useState(false);
  const [error, setError] = useState<string | null>(null);

  const handleSubmit = async (e: React.FormEvent) => {
    e.preventDefault();
    if (!key.trim()) {
      setError('Flag key is required');
      return;
    }
    setCreating(true);
    setError(null);

    const result = await callFeatureFlagApi('', {
      method: 'POST',
      body: JSON.stringify({
        key: key.trim(),
        name: name.trim() || undefined,
        active,
      }),
    });

    if (result.success) {
      logFeatureFlagAudit('create', {
        resourceName: key.trim(),
        details: { key: key.trim(), name: name.trim(), active },
      });
      onCreated();
    } else {
      setError(result.error || 'Failed to create feature flag');
    }
    setCreating(false);
  };

  return (
    <Card style={{ marginBottom: '20px' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '16px' }}>
        <h3 style={{ margin: 0 }}>Create Feature Flag</h3>
        <Button variant="ghost" size="sm" onClick={onClose}>X</Button>
      </div>

      <form onSubmit={handleSubmit}>
        <div style={{ display: 'flex', flexDirection: 'column', gap: '16px' }}>
          <div>
            <Label required>Flag Key</Label>
            <Input
              type="text"
              value={key}
              onChange={(e) => setKey(e.target.value.replace(/[^a-z0-9_-]/gi, '-').toLowerCase())}
              placeholder="e.g., enable-new-dashboard"
              style={{ width: '100%', marginTop: '6px' }}
            />
            <Text tone="muted" style={{ display: 'block', fontSize: '0.75rem', marginTop: '4px' }}>
              Lowercase, hyphens, underscores only
            </Text>
          </div>

          <div>
            <Label>Display Name</Label>
            <Input
              type="text"
              value={name}
              onChange={(e) => setName(e.target.value)}
              placeholder="e.g., Enable New Dashboard"
              style={{ width: '100%', marginTop: '6px' }}
            />
          </div>

          <div style={{ display: 'flex', alignItems: 'center', gap: '12px' }}>
            <Switch
              checked={active}
              onCheckedChange={setActive}
              size="sm"
            />
            <Text>{active ? 'Active' : 'Inactive'}</Text>
          </div>

          {error && <Alert tone="danger">{error}</Alert>}

          <div style={{ display: 'flex', gap: '8px', justifyContent: 'flex-end' }}>
            <Button type="button" variant="secondary" onClick={onClose}>Cancel</Button>
            <Button type="submit" disabled={creating}>
              {creating ? 'Creating...' : 'Create Flag'}
            </Button>
          </div>
        </div>
      </form>
    </Card>
  );
}

function TenantPicker({
  excludeIds,
  onSelect,
  disabled,
}: {
  excludeIds: string[];
  onSelect: (tenantId: string) => void;
  disabled?: boolean;
}) {
  const [allTenants, setAllTenants] = useState<Tenant[]>([]);
  const [loading, setLoading] = useState(true);
  const [query, setQuery] = useState('');
  const [showDropdown, setShowDropdown] = useState(false);
  const containerRef = useRef<HTMLDivElement>(null);

  useEffect(() => {
    callTenantManagementApi<Tenant[]>('/tenants').then(result => {
      if (result.success && result.data) {
        setAllTenants(result.data);
      }
      setLoading(false);
    });
  }, []);

  useEffect(() => {
    const handleClickOutside = (e: MouseEvent) => {
      if (containerRef.current && !containerRef.current.contains(e.target as Node)) {
        setShowDropdown(false);
      }
    };
    document.addEventListener('mousedown', handleClickOutside);
    return () => document.removeEventListener('mousedown', handleClickOutside);
  }, []);

  const filtered = allTenants.filter(t => {
    if (excludeIds.includes(t.tenant)) return false;
    if (!query.trim()) return true;
    const q = query.toLowerCase();
    return (
      t.client_name.toLowerCase().includes(q) ||
      (t.email && t.email.toLowerCase().includes(q)) ||
      t.tenant.toLowerCase().includes(q)
    );
  });

  const [customUuid, setCustomUuid] = useState('');

  const handleAddCustomUuid = () => {
    const trimmed = customUuid.trim();
    if (trimmed) {
      onSelect(trimmed);
      setCustomUuid('');
    }
  };

  return (
    <div ref={containerRef} style={{ position: 'relative' }}>
      <div style={{ display: 'flex', gap: '8px' }}>
        <div style={{ flex: 1 }}>
          <Input
            type="text"
            value={query}
            onChange={(e) => {
              setQuery(e.target.value);
              setShowDropdown(true);
            }}
            onFocus={() => setShowDropdown(true)}
            placeholder={loading ? 'Loading tenants...' : 'Search by name, email, or ID...'}
            disabled={disabled || loading}
          />
        </div>
      </div>
      <div style={{ display: 'flex', gap: '8px', marginTop: '6px' }}>
        <Input
          type="text"
          value={customUuid}
          onChange={(e) => setCustomUuid(e.target.value)}
          onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); handleAddCustomUuid(); } }}
          placeholder="Paste custom UUID..."
          disabled={disabled}
          style={{ flex: 1, fontSize: '0.8125rem' }}
        />
        <Button
          variant="outline"
          size="sm"
          onClick={handleAddCustomUuid}
          disabled={disabled || !customUuid.trim()}
          style={{ whiteSpace: 'nowrap' }}
        >
          Add UUID
        </Button>
      </div>
      {showDropdown && !loading && (
        <div style={{
          position: 'absolute',
          top: '100%',
          left: 0,
          right: 0,
          maxHeight: '240px',
          overflowY: 'auto',
          background: 'var(--alga-bg)',
          border: '1px solid var(--alga-border)',
          borderRadius: 'var(--alga-radius)',
          zIndex: 50,
          marginTop: '4px',
          boxShadow: '0 4px 12px rgba(0,0,0,0.15)',
        }}>
          {filtered.length === 0 ? (
            <div style={{ padding: '12px', textAlign: 'center' }}>
              <Text tone="muted" style={{ fontSize: '0.8125rem' }}>No matching tenants</Text>
            </div>
          ) : (
            filtered.map(t => (
              <div
                key={t.tenant}
                onClick={() => {
                  onSelect(t.tenant);
                  setQuery('');
                  setShowDropdown(false);
                }}
                style={{
                  padding: '8px 12px',
                  cursor: 'pointer',
                  borderBottom: '1px solid var(--alga-border)',
                }}
                onMouseEnter={(e) => {
                  (e.currentTarget as HTMLDivElement).style.background = 'var(--alga-muted)';
                }}
                onMouseLeave={(e) => {
                  (e.currentTarget as HTMLDivElement).style.background = 'transparent';
                }}
              >
                <div style={{ fontWeight: 600, fontSize: '0.875rem' }}>{t.client_name}</div>
                {t.email && (
                  <Text tone="muted" style={{ fontSize: '0.75rem', display: 'block' }}>
                    {t.email}
                  </Text>
                )}
                <Text tone="muted" style={{ fontSize: '0.6875rem', fontFamily: 'monospace', display: 'block' }}>
                  {t.tenant}
                </Text>
              </div>
            ))
          )}
        </div>
      )}
    </div>
  );
}

function FeatureFlagDetail({
  flag,
  onUpdate,
  onDelete,
}: {
  flag: PostHogFeatureFlag;
  onUpdate: () => void;
  onDelete: () => void;
}) {
  const [toggling, setToggling] = useState(false);
  const [enablingAll, setEnablingAll] = useState(false);
  const [addingTenant, setAddingTenant] = useState(false);
  const [removingTenant, setRemovingTenant] = useState<string | null>(null);
  const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);
  const [showRawFilters, setShowRawFilters] = useState(false);
  const [error, setError] = useState<string | null>(null);
  const [tenantMap, setTenantMap] = useState<Record<string, Tenant>>({});

  useEffect(() => {
    callTenantManagementApi<Tenant[]>('/tenants').then(result => {
      if (result.success && result.data) {
        const map: Record<string, Tenant> = {};
        for (const t of result.data) {
          map[t.tenant] = t;
        }
        setTenantMap(map);
      }
    });
  }, []);

  const tenants = (() => {
    const ids: string[] = [];
    if (flag.filters?.groups) {
      for (const group of flag.filters.groups) {
        for (const prop of group.properties || []) {
          if (prop.key === 'tenant' && Array.isArray(prop.value)) {
            ids.push(...prop.value);
          }
        }
      }
    }
    return [...new Set(ids)];
  })();

  // Detect if flag is enabled for everyone (100% rollout, no tenant conditions)
  const isEnabledForEveryone = flag.active && flag.filters?.groups?.some(g =>
    g.rollout_percentage === 100 && (!g.properties || g.properties.length === 0)
  ) || false;

  const handleEnableForEveryone = async (enable: boolean) => {
    setEnablingAll(true);
    setError(null);
    if (enable) {
      // Set active + 100% rollout with no conditions
      const result = await callFeatureFlagApi(`/${flag.id}`, {
        method: 'PUT',
        body: JSON.stringify({
          active: true,
          filters: {
            groups: [{ properties: [], rollout_percentage: 100, variant: null }],
            multivariate: flag.filters?.multivariate || null,
          },
        }),
      });
      if (result.success) {
        logFeatureFlagAudit('enable_all', {
          resourceId: String(flag.id),
          resourceName: flag.key,
          details: { enabled: true },
        });
        onUpdate();
      } else {
        setError(result.error || 'Failed to enable for everyone');
      }
    } else {
      // Disable: just deactivate the flag
      const result = await callFeatureFlagApi(`/${flag.id}`, {
        method: 'PUT',
        body: JSON.stringify({ active: false }),
      });
      if (result.success) {
        logFeatureFlagAudit('enable_all', {
          resourceId: String(flag.id),
          resourceName: flag.key,
          details: { enabled: false },
        });
        onUpdate();
      } else {
        setError(result.error || 'Failed to disable flag');
      }
    }
    setEnablingAll(false);
  };

  const handleToggle = async (active: boolean) => {
    setToggling(true);
    setError(null);
    const result = await callFeatureFlagApi(`/${flag.id}`, {
      method: 'PUT',
      body: JSON.stringify({ active }),
    });
    if (result.success) {
      logFeatureFlagAudit('toggle', {
        resourceId: String(flag.id),
        resourceName: flag.key,
        details: { active, previousActive: flag.active },
      });
      onUpdate();
    } else {
      setError(result.error || 'Failed to toggle flag');
    }
    setToggling(false);
  };

  const handleAddTenant = async (tenantId: string) => {
    setAddingTenant(true);
    setError(null);
    const result = await callFeatureFlagApi(`/${flag.id}/tenants`, {
      method: 'POST',
      body: JSON.stringify({ __action: 'add', tenantId }),
    });
    if (result.success) {
      logFeatureFlagAudit('add_tenant', {
        resourceId: String(flag.id),
        resourceName: flag.key,
        details: { tenantId, action: 'add' },
      });
      onUpdate();
    } else {
      setError(result.error || 'Failed to add tenant');
    }
    setAddingTenant(false);
  };

  const handleRemoveTenant = async (tenantId: string) => {
    setRemovingTenant(tenantId);
    setError(null);
    const result = await callFeatureFlagApi(`/${flag.id}/tenants`, {
      method: 'POST',
      body: JSON.stringify({ __action: 'remove', tenantId }),
    });
    if (result.success) {
      logFeatureFlagAudit('remove_tenant', {
        resourceId: String(flag.id),
        resourceName: flag.key,
        details: { tenantId, action: 'remove' },
      });
      onUpdate();
    } else {
      setError(result.error || 'Failed to remove tenant');
    }
    setRemovingTenant(null);
  };

  const handleDeleteConfirmed = async () => {
    const result = await callFeatureFlagApi(`/${flag.id}`, {
      method: 'DELETE',
    });
    if (result.success) {
      logFeatureFlagAudit('delete', {
        resourceId: String(flag.id),
        resourceName: flag.key,
      });
      onDelete();
    } else {
      setError(result.error || 'Failed to delete flag');
    }
    setShowDeleteConfirm(false);
  };

  return (
    <div style={{ display: 'flex', flexDirection: 'column', gap: '20px', padding: '4px' }}>
      {error && <Alert tone="danger">{error}</Alert>}

      {/* Status Toggle */}
      <div>
        <Label>Status</Label>
        <div style={{ display: 'flex', alignItems: 'center', gap: '12px', marginTop: '8px' }}>
          <Switch
            checked={flag.active}
            onCheckedChange={handleToggle}
            disabled={toggling || enablingAll}
            size="sm"
          />
          <Text>{flag.active ? 'Active' : 'Inactive'}</Text>
          {toggling && <Spinner size="button" />}
        </div>
      </div>

      {/* Enable for Everyone */}
      <div>
        <Label>Release to Everyone</Label>
        <div style={{ display: 'flex', alignItems: 'center', gap: '12px', marginTop: '8px' }}>
          <Switch
            checked={isEnabledForEveryone}
            onCheckedChange={handleEnableForEveryone}
            disabled={enablingAll || toggling}
            size="sm"
          />
          <Text>
            {isEnabledForEveryone ? '100% rollout (all users)' : 'Tenant-specific or inactive'}
          </Text>
          {enablingAll && <Spinner size="button" />}
        </div>
        <Text tone="muted" style={{ display: 'block', fontSize: '0.75rem', marginTop: '4px' }}>
          {isEnabledForEveryone
            ? 'This flag is active for all users. Toggle off to deactivate.'
            : 'Toggle on to activate this flag for 100% of users (removes tenant conditions).'}
        </Text>
      </div>

      {flag.name && (
        <div>
          <Label>Name</Label>
          <Text style={{ display: 'block', marginTop: '4px' }}>{flag.name}</Text>
        </div>
      )}

      <div>
        <Label>Created</Label>
        <Text style={{ display: 'block', marginTop: '4px' }}>
          {new Date(flag.created_at).toLocaleString()}
        </Text>
      </div>

      {flag.tags && flag.tags.length > 0 && (
        <div>
          <Label>Tags</Label>
          <div style={{ display: 'flex', gap: '4px', flexWrap: 'wrap', marginTop: '4px' }}>
            {flag.tags.map(tag => (
              <Badge key={tag} tone="info">{tag}</Badge>
            ))}
          </div>
        </div>
      )}

      <Separator />

      {/* Tenant Release Conditions */}
      <div>
        <Label>Tenant Release Conditions</Label>
        <div style={{ marginTop: '8px' }}>
          {tenants.length === 0 ? (
            <Text tone="muted" style={{ fontSize: '0.875rem' }}>
              No tenant-specific conditions. Flag applies to all users (or based on other filters).
            </Text>
          ) : (
            <div style={{ display: 'flex', flexDirection: 'column', gap: '6px' }}>
              {tenants.map(tenantId => {
                const tenant = tenantMap[tenantId];
                return (
                  <div
                    key={tenantId}
                    style={{
                      display: 'flex',
                      justifyContent: 'space-between',
                      alignItems: 'center',
                      padding: '8px 12px',
                      background: 'var(--alga-muted)',
                      borderRadius: 'var(--alga-radius)',
                    }}
                  >
                    <div>
                      {tenant && (
                        <Text style={{ fontWeight: 600, fontSize: '0.875rem', display: 'block' }}>
                          {tenant.client_name}
                        </Text>
                      )}
                      <Text style={{ fontFamily: 'monospace', fontSize: '0.75rem' }} tone="muted">
                        {tenantId}
                      </Text>
                    </div>
                    <Button
                      variant="destructive"
                      size="sm"
                      onClick={() => handleRemoveTenant(tenantId)}
                      disabled={removingTenant === tenantId}
                    >
                      {removingTenant === tenantId ? 'Removing...' : 'Remove'}
                    </Button>
                  </div>
                );
              })}
            </div>
          )}

          <div style={{ marginTop: '12px' }}>
            <TenantPicker
              excludeIds={tenants}
              onSelect={handleAddTenant}
              disabled={addingTenant}
            />
            {addingTenant && (
              <div style={{ marginTop: '4px', display: 'flex', alignItems: 'center', gap: '6px' }}>
                <Spinner size="button" />
                <Text tone="muted" style={{ fontSize: '0.8125rem' }}>Adding tenant...</Text>
              </div>
            )}
          </div>
        </div>
      </div>

      <Separator />

      {/* Raw Filters */}
      <div>
        <Button
          variant="ghost"
          size="sm"
          onClick={() => setShowRawFilters(!showRawFilters)}
          style={{ fontSize: '0.875rem' }}
        >
          {showRawFilters ? 'Hide' : 'Show'} Raw Filters JSON
        </Button>
        {showRawFilters && (
          <pre style={{
            marginTop: '8px',
            fontSize: '0.75rem',
            background: 'var(--alga-muted)',
            padding: '12px',
            borderRadius: 'var(--alga-radius)',
            overflow: 'auto',
            maxHeight: '300px',
          }}>
            {JSON.stringify(flag.filters, null, 2)}
          </pre>
        )}
      </div>

      <Separator />

      {/* Delete */}
      <div>
        <Button variant="destructive" onClick={() => setShowDeleteConfirm(true)}>
          Delete Flag
        </Button>
      </div>

      <ConfirmDialog
        isOpen={showDeleteConfirm}
        title="Delete Feature Flag"
        message={`Are you sure you want to delete the feature flag "${flag.key}"? This cannot be undone.`}
        confirmLabel="Delete"
        cancelLabel="Cancel"
        variant="danger"
        onConfirm={handleDeleteConfirmed}
        onCancel={() => setShowDeleteConfirm(false)}
      />
    </div>
  );
}

// Main App
// ============================================================================
// Notifications View - Platform-wide announcements/alerts management
// ============================================================================

interface PlatformNotification {
  notification_id: string;
  title: string;
  banner_content: string;
  detail_content: string;
  target_audience: {
    filters: {
      roles?: string[];
      tenant_ids?: string[];
      user_types?: string[];
      subscription_statuses?: string[];
      product_names?: string[];
    };
    excluded_user_ids?: string[];
    resolved_user_count?: number;
  };
  variant: 'info' | 'warning' | 'destructive' | 'success' | 'default';
  starts_at: string;
  expires_at: string | null;
  created_by: string | null;
  created_at: string;
  updated_at: string;
  is_active: boolean;
}

interface NotificationStats {
  notification_id: string;
  total_recipients: number;
  total_dismissed: number;
  total_detail_viewed: number;
  reads_by_tenant: Array<{ tenant: string; tenant_name: string | null; total: number; dismissed: number; detail_viewed: number }>;
}

interface NotificationRecipientRead {
  user_id: string;
  tenant: string;
  tenant_name: string | null;
  email: string;
  first_name: string | null;
  last_name: string | null;
  matched_at: string | null;
  dismissed_at: string | null;
  detail_viewed_at: string | null;
}

interface ResolvedRecipient {
  user_id: string;
  tenant: string;
  tenant_name: string | null;
  email: string;
  first_name: string | null;
  last_name: string | null;
  roles: string[];
  user_type: string;
  subscription_status: string | null;
  product_name: string | null;
}

// ── Expandable per-notification stats row ──
function NotificationStatsExpander({ notificationId }: { notificationId: string }) {
  const [stats, setStats] = useState<NotificationStats | null>(null);
  const [reads, setReads] = useState<NotificationRecipientRead[] | null>(null);
  const [loading, setLoading] = useState(true);
  const [tab, setTab] = useState<'summary' | 'users'>('summary');
  const [search, setSearch] = useState('');

  useEffect(() => {
    const fetchData = async () => {
      setLoading(true);
      const [statsRes, readsRes] = await Promise.all([
        callNotificationApi<NotificationStats>(`/${notificationId}/stats`),
        callNotificationApi<NotificationRecipientRead[]>(`/${notificationId}/reads`),
      ]);
      if (statsRes.success && statsRes.data) setStats(statsRes.data);
      if (readsRes.success && readsRes.data) setReads(readsRes.data);
      setLoading(false);
    };
    fetchData();
  }, [notificationId]);

  if (loading) return <LoadingIndicator size="sm" text="Loading stats..." />;
  if (!stats) return <Text tone="muted">No stats available</Text>;

  const filteredReads = reads?.filter(r =>
    !search || `${r.first_name} ${r.last_name} ${r.email} ${r.tenant_name}`.toLowerCase().includes(search.toLowerCase())
  ) || [];

  const noAction = filteredReads.filter(r => !r.dismissed_at && !r.detail_viewed_at).length;
  const dismissed = filteredReads.filter(r => r.dismissed_at && !r.detail_viewed_at).length;
  const viewed = filteredReads.filter(r => r.detail_viewed_at).length;

  return (
    <div style={{ padding: '0.75rem 1rem', background: 'var(--alga-muted, #f8fafc)', borderRadius: '0.375rem' }}>
      {/* Summary cards */}
      <div style={{ display: 'flex', gap: '1.5rem', marginBottom: '0.75rem' }}>
        <div style={{ textAlign: 'center' }}>
          <div style={{ fontSize: '1.25rem', fontWeight: 700 }}>{stats.total_recipients}</div>
          <Text tone="muted" style={{ fontSize: '0.75rem' }}>Recipients</Text>
        </div>
        <div style={{ textAlign: 'center' }}>
          <div style={{ fontSize: '1.25rem', fontWeight: 700, color: 'var(--alga-primary, #9855ee)' }}>{stats.total_detail_viewed}</div>
          <Text tone="muted" style={{ fontSize: '0.75rem' }}>Viewed Details</Text>
        </div>
        <div style={{ textAlign: 'center' }}>
          <div style={{ fontSize: '1.25rem', fontWeight: 700 }}>{stats.total_dismissed}</div>
          <Text tone="muted" style={{ fontSize: '0.75rem' }}>Dismissed</Text>
        </div>
        <div style={{ textAlign: 'center' }}>
          <div style={{ fontSize: '1.25rem', fontWeight: 700, color: 'var(--alga-muted-fg, #666)' }}>{noAction}</div>
          <Text tone="muted" style={{ fontSize: '0.75rem' }}>No Action</Text>
        </div>
      </div>

      {/* Tab toggle */}
      <div style={{ display: 'flex', gap: '0.5rem', marginBottom: '0.75rem' }}>
        <Button size="sm" variant={tab === 'summary' ? 'primary' : 'outline'} onClick={() => setTab('summary')}>By Tenant</Button>
        <Button size="sm" variant={tab === 'users' ? 'primary' : 'outline'} onClick={() => setTab('users')}>Per User</Button>
        {tab === 'users' && (
          <Input
            value={search}
            onChange={(e) => setSearch(e.target.value)}
            placeholder="Filter by name, email, tenant..."
            style={{ marginLeft: 'auto', width: '250px' }}
          />
        )}
      </div>

      {tab === 'summary' && stats.reads_by_tenant.length > 0 && (
        <div style={{ maxHeight: '250px', overflow: 'auto' }}>
          <DataTable
            columns={[
              { key: 'tenant_name', header: 'Tenant', render: (row) => row.tenant_name || row.tenant.slice(0, 8) },
              { key: 'total', header: 'Recipients' },
              { key: 'detail_viewed', header: 'Viewed Details' },
              { key: 'dismissed', header: 'Dismissed' },
            ] as Column<(typeof stats.reads_by_tenant)[0]>[]}
            data={stats.reads_by_tenant}
          />
        </div>
      )}

      {tab === 'users' && (
        <div style={{ maxHeight: '300px', overflow: 'auto', border: '1px solid var(--alga-muted, #e2e8f0)', borderRadius: '0.375rem', background: 'var(--alga-card-bg, white)' }}>
          <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.8rem' }}>
            <thead>
              <tr style={{ borderBottom: '1px solid var(--alga-muted, #e2e8f0)', position: 'sticky', top: 0, background: 'var(--alga-card-bg, white)' }}>
                <th style={{ padding: '0.5rem', textAlign: 'left' }}>User</th>
                <th style={{ padding: '0.5rem', textAlign: 'left' }}>Tenant</th>
                <th style={{ padding: '0.5rem', textAlign: 'left' }}>Status</th>
                <th style={{ padding: '0.5rem', textAlign: 'left' }}>Dismissed</th>
                <th style={{ padding: '0.5rem', textAlign: 'left' }}>Viewed Details</th>
              </tr>
            </thead>
            <tbody>
              {filteredReads.map(r => {
                const hasViewed = !!r.detail_viewed_at;
                const hasDismissed = !!r.dismissed_at;
                return (
                  <tr key={r.user_id} style={{ borderBottom: '1px solid var(--alga-muted, #e2e8f0)' }}>
                    <td style={{ padding: '0.4rem 0.5rem' }}>
                      <div style={{ fontWeight: 500 }}>{r.first_name} {r.last_name}</div>
                      <div style={{ fontSize: '0.7rem', color: 'var(--alga-muted-fg, #666)' }}>{r.email}</div>
                    </td>
                    <td style={{ padding: '0.4rem 0.5rem' }}>{r.tenant_name || r.tenant.slice(0, 8)}</td>
                    <td style={{ padding: '0.4rem 0.5rem' }}>
                      {hasViewed ? <Badge tone="success">Viewed</Badge>
                        : hasDismissed ? <Badge tone="warning">Dismissed</Badge>
                        : <Badge tone="default">Pending</Badge>}
                    </td>
                    <td style={{ padding: '0.4rem 0.5rem', color: hasDismissed ? 'inherit' : 'var(--alga-muted-fg, #999)' }}>
                      {hasDismissed ? new Date(r.dismissed_at!).toLocaleString() : '—'}
                    </td>
                    <td style={{ padding: '0.4rem 0.5rem', color: hasViewed ? 'inherit' : 'var(--alga-muted-fg, #999)' }}>
                      {hasViewed ? new Date(r.detail_viewed_at!).toLocaleString() : '—'}
                    </td>
                  </tr>
                );
              })}
              {filteredReads.length === 0 && (
                <tr><td colSpan={5} style={{ padding: '1rem', textAlign: 'center', color: '#666' }}>No recipients found</td></tr>
              )}
            </tbody>
          </table>
        </div>
      )}
    </div>
  );
}

function NotificationsView() {
  const [view, setView] = useState<'list' | 'create' | 'edit'>('list');
  const [notifications, setNotifications] = useState<PlatformNotification[]>([]);
  const [loading, setLoading] = useState(true);
  const [error, setError] = useState<string | null>(null);
  const [editingNotification, setEditingNotification] = useState<PlatformNotification | null>(null);
  const [expandedId, setExpandedId] = useState<string | null>(null);

  const fetchNotifications = useCallback(async () => {
    setLoading(true);
    setError(null);
    const result = await callNotificationApi<PlatformNotification[]>('?activeOnly=false');
    if (result.success && result.data) {
      setNotifications(result.data);
    } else {
      setError(result.error || 'Failed to load notifications');
    }
    setLoading(false);
  }, []);

  useEffect(() => { fetchNotifications(); }, [fetchNotifications]);

  if (view === 'create') {
    return <NotificationEditor onBack={() => { setView('list'); fetchNotifications(); }} />;
  }

  if (view === 'edit' && editingNotification) {
    return <NotificationEditor notification={editingNotification} onBack={() => { setView('list'); setEditingNotification(null); fetchNotifications(); }} />;
  }

  return (
    <div style={{ padding: '1rem' }}>
      <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '1rem' }}>
        <h3 style={{ margin: 0, fontSize: '1.1rem', fontWeight: 600 }}>Platform Notifications</h3>
        <div style={{ display: 'flex', gap: '0.5rem' }}>
          <Button size="sm" variant="outline" onClick={fetchNotifications}>Refresh</Button>
          <Button size="sm" onClick={() => setView('create')}>Create Notification</Button>
        </div>
      </div>

      {error && <Alert tone="danger">{error}</Alert>}

      {loading ? (
        <LoadingIndicator size="sm" text="Loading notifications..." />
      ) : (
        <div>
          {notifications.map(n => {
            const isExpanded = expandedId === n.notification_id;
            const now = new Date();
            const started = new Date(n.starts_at) <= now;
            const expired = n.expires_at && new Date(n.expires_at) <= now;
            const statusBadge = !n.is_active
              ? <Badge tone="danger">Inactive</Badge>
              : expired ? <Badge tone="warning">Expired</Badge>
              : !started ? <Badge tone="info">Scheduled</Badge>
              : <Badge tone="success">Active</Badge>;
            const toneMap: Record<string, string> = { destructive: 'danger', warning: 'warning', info: 'info', success: 'success', default: 'muted' };
            const f = n.target_audience?.filters || {};
            const audienceParts: string[] = [];
            if (f.roles?.length) audienceParts.push(`Roles: ${f.roles.join(', ')}`);
            if (f.tenant_ids?.length) audienceParts.push(`${f.tenant_ids.length} tenant(s)`);
            if (f.user_types?.length) audienceParts.push(`Types: ${f.user_types.join(', ')}`);
            const count = n.target_audience?.resolved_user_count;

            return (
              <div key={n.notification_id} style={{
                border: '1px solid var(--alga-muted, #e2e8f0)',
                borderRadius: '0.5rem',
                marginBottom: '0.5rem',
                overflow: 'hidden',
              }}>
                {/* Row */}
                <div
                  style={{
                    display: 'grid',
                    gridTemplateColumns: '1fr auto auto auto auto auto',
                    alignItems: 'center',
                    gap: '0.75rem',
                    padding: '0.75rem 1rem',
                    cursor: 'pointer',
                    background: isExpanded ? 'var(--alga-muted, #f8fafc)' : 'var(--alga-card-bg, white)',
                  }}
                  onClick={() => setExpandedId(isExpanded ? null : n.notification_id)}
                >
                  <div>
                    <div style={{ fontWeight: 600, fontSize: '0.9rem' }}>{n.title}</div>
                    <div style={{ fontSize: '0.75rem', color: 'var(--alga-muted-fg, #666)' }}>
                      {n.banner_content.length > 80 ? n.banner_content.slice(0, 80) + '...' : n.banner_content}
                    </div>
                  </div>
                  <Badge tone={(toneMap[n.variant] || 'info') as any}>{n.variant}</Badge>
                  <div style={{ fontSize: '0.8rem', color: 'var(--alga-muted-fg, #666)' }}>
                    {audienceParts.length > 0 ? audienceParts.join(' · ') : 'All'}
                    {count != null && <span> ({count})</span>}
                  </div>
                  {statusBadge}
                  <Text tone="muted" style={{ fontSize: '0.8rem' }}>{new Date(n.created_at).toLocaleDateString()}</Text>
                  <div style={{ display: 'flex', gap: '0.25rem' }}>
                    <Button size="sm" variant="outline" onClick={(e) => { e.stopPropagation(); setEditingNotification(n); setView('edit'); }}>
                      Edit
                    </Button>
                    <Button size="sm" variant="ghost" onClick={(e) => { e.stopPropagation(); setExpandedId(isExpanded ? null : n.notification_id); }}>
                      {isExpanded ? '▲' : '▼'}
                    </Button>
                  </div>
                </div>

                {/* Expanded stats */}
                {isExpanded && (
                  <div style={{ borderTop: '1px solid var(--alga-muted, #e2e8f0)', padding: '0.75rem 1rem' }}>
                    <NotificationStatsExpander notificationId={n.notification_id} />
                  </div>
                )}
              </div>
            );
          })}
          {notifications.length === 0 && (
            <div style={{ textAlign: 'center', padding: '2rem', color: 'var(--alga-muted-fg, #666)' }}>
              No notifications yet. Click "Create Notification" to get started.
            </div>
          )}
        </div>
      )}
    </div>
  );
}

// ── Notification Editor (Create / Edit) ──

function NotificationEditor({ notification, onBack }: { notification?: PlatformNotification; onBack: () => void }) {
  const isEdit = !!notification;

  // Form state
  const [title, setTitle] = useState(notification?.title || '');
  const [bannerContent, setBannerContent] = useState(notification?.banner_content || '');
  const [detailContent, setDetailContent] = useState(notification?.detail_content || '');
  const [variant, setVariant] = useState<PlatformNotification['variant']>(notification?.variant || 'info');
  const [startsAt, setStartsAt] = useState(notification?.starts_at ? notification.starts_at.slice(0, 16) : '');
  const [expiresAt, setExpiresAt] = useState(notification?.expires_at ? notification.expires_at.slice(0, 16) : '');
  const [isActive, setIsActive] = useState(notification?.is_active ?? true);

  // Audience targeting
  const [filterRoles, setFilterRoles] = useState<string[]>(notification?.target_audience?.filters?.roles || []);
  const [filterTenantIds, setFilterTenantIds] = useState<string[]>(notification?.target_audience?.filters?.tenant_ids || []);
  const [filterUserTypes, setFilterUserTypes] = useState<string[]>(notification?.target_audience?.filters?.user_types || []);
  const [filterSubStatuses, setFilterSubStatuses] = useState<string[]>(notification?.target_audience?.filters?.subscription_statuses || []);
  const [filterProductNames, setFilterProductNames] = useState<string[]>(notification?.target_audience?.filters?.product_names || []);
  const [emailSearch, setEmailSearch] = useState('');
  const [roleInput, setRoleInput] = useState('');
  const [productNameInput, setProductNameInput] = useState('');

  // Recipient resolution
  const [recipients, setRecipients] = useState<ResolvedRecipient[]>([]);
  const [excludedUserIds, setExcludedUserIds] = useState<Set<string>>(new Set(notification?.target_audience?.excluded_user_ids || []));
  const [recipientsResolved, setRecipientsResolved] = useState(false);
  const [resolving, setResolving] = useState(false);
  const [recipientSearch, setRecipientSearch] = useState('');

  // Stats (edit mode)
  const [stats, setStats] = useState<NotificationStats | null>(null);

  // Tenants list for multi-select
  const [tenants, setTenants] = useState<Array<{ tenant: string; company_name: string }>>([]);

  // UI state
  const [saving, setSaving] = useState(false);
  const [saveError, setSaveError] = useState<string | null>(null);
  const [showDeleteConfirm, setShowDeleteConfirm] = useState(false);

  // Fetch tenants on mount
  useEffect(() => {
    const fetchTenants = async () => {
      try {
        const result = await proxyApiCall<any>('/api/v1/tenant-management/tenants');
        const data = result?.data || result;
        if (Array.isArray(data)) {
          setTenants(data.map((t: any) => ({ tenant: t.tenant, company_name: t.company_name || t.tenant })));
        }
      } catch { /* ignore */ }
    };
    fetchTenants();
  }, []);

  // Fetch stats in edit mode
  useEffect(() => {
    if (!isEdit || !notification) return;
    const fetchStats = async () => {
      const result = await callNotificationApi<NotificationStats>(`/${notification.notification_id}/stats`);
      if (result.success && result.data) setStats(result.data);
    };
    fetchStats();
  }, [isEdit, notification]);

  const handleResolveRecipients = async () => {
    setResolving(true);
    const filters: Record<string, unknown> = {};
    if (filterRoles.length > 0) filters.roles = filterRoles;
    if (filterTenantIds.length > 0) filters.tenant_ids = filterTenantIds;
    if (filterUserTypes.length > 0) filters.user_types = filterUserTypes;
    if (filterSubStatuses.length > 0) filters.subscription_statuses = filterSubStatuses;
    if (filterProductNames.length > 0) filters.product_names = filterProductNames;

    const result = await callNotificationApi<ResolvedRecipient[]>('/resolve-recipients', {
      method: 'POST',
      body: JSON.stringify({ filters, email_search: emailSearch || undefined }),
    });

    if (result.success && result.data) {
      setRecipients(result.data);
      setRecipientsResolved(true);
      // Preserve existing exclusions, remove any that are no longer in the resolved list
      const resolvedIds = new Set(result.data.map(r => r.user_id));
      setExcludedUserIds(prev => {
        const next = new Set<string>();
        prev.forEach(id => { if (resolvedIds.has(id)) next.add(id); });
        return next;
      });
    }
    setResolving(false);
  };

  const handleSave = async () => {
    if (!recipientsResolved) {
      setSaveError('Please resolve recipients before saving.');
      return;
    }

    setSaving(true);
    setSaveError(null);

    const targetAudience = {
      filters: {
        ...(filterRoles.length > 0 && { roles: filterRoles }),
        ...(filterTenantIds.length > 0 && { tenant_ids: filterTenantIds }),
        ...(filterUserTypes.length > 0 && { user_types: filterUserTypes }),
        ...(filterSubStatuses.length > 0 && { subscription_statuses: filterSubStatuses }),
        ...(filterProductNames.length > 0 && { product_names: filterProductNames }),
        ...(emailSearch.trim() && { email_search: emailSearch.trim() }),
      },
      excluded_user_ids: Array.from(excludedUserIds),
      resolved_user_count: recipients.length - excludedUserIds.size,
    };

    // Send the full materialized recipient list with exclusion flags
    const recipientList = recipients.map(r => ({
      user_id: r.user_id,
      tenant: r.tenant,
      excluded: excludedUserIds.has(r.user_id),
    }));

    const body: Record<string, unknown> = {
      title,
      banner_content: bannerContent,
      detail_content: detailContent,
      target_audience: targetAudience,
      variant,
      recipients: recipientList,
      ...(startsAt && { starts_at: new Date(startsAt).toISOString() }),
      ...(expiresAt && { expires_at: new Date(expiresAt).toISOString() }),
    };

    if (isEdit) {
      body.is_active = isActive;
    }

    const result = isEdit
      ? await callNotificationApi(`/${notification!.notification_id}`, { method: 'PUT', body: JSON.stringify(body) })
      : await callNotificationApi('', { method: 'POST', body: JSON.stringify(body) });

    if (result.success) {
      onBack();
    } else {
      setSaveError(result.error || 'Failed to save notification');
    }
    setSaving(false);
  };

  const handleDelete = async () => {
    const result = await callNotificationApi(`/${notification!.notification_id}`, { method: 'DELETE' });
    if (result.success) {
      onBack();
    } else {
      setSaveError(result.error || 'Failed to delete notification');
    }
    setShowDeleteConfirm(false);
  };

  const addRole = () => {
    const r = roleInput.trim();
    if (r && !filterRoles.includes(r)) {
      setFilterRoles([...filterRoles, r]);
    }
    setRoleInput('');
  };

  const selectedCount = recipientsResolved ? recipients.length - excludedUserIds.size : null;
  const allSelected = recipientsResolved && excludedUserIds.size === 0;

  const filteredRecipients = recipientSearch
    ? recipients.filter(r =>
        `${r.first_name} ${r.last_name} ${r.email} ${r.tenant_name}`.toLowerCase().includes(recipientSearch.toLowerCase())
      )
    : recipients;

  const variantOptions: SelectOption[] = [
    { value: 'info', label: 'Info (blue)' },
    { value: 'warning', label: 'Warning (amber)' },
    { value: 'destructive', label: 'Destructive (red)' },
    { value: 'success', label: 'Success (green)' },
  ];

  const userTypeOptions: SelectOption[] = [
    { value: 'internal', label: 'Internal users' },
    { value: 'client', label: 'Client portal users' },
  ];

  const tenantOptions: SelectOption[] = tenants.map(t => ({ value: t.tenant, label: t.company_name }));

  // Map DB variant to ui-kit Alert tone
  const variantToTone: Record<string, 'info' | 'success' | 'warning' | 'danger'> = {
    info: 'info',
    warning: 'warning',
    destructive: 'danger',
    success: 'success',
    default: 'info',
  };

  return (
    <div style={{ padding: '1rem' }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem', marginBottom: '1rem' }}>
        <Button size="sm" variant="outline" onClick={onBack}>← Back</Button>
        <h3 style={{ margin: 0, fontSize: '1.1rem', fontWeight: 600 }}>{isEdit ? 'Edit Notification' : 'Create Notification'}</h3>
        {isEdit && (
          <Button size="sm" variant="destructive" onClick={() => setShowDeleteConfirm(true)} style={{ marginLeft: 'auto' }}>
            Delete
          </Button>
        )}
      </div>

      {saveError && <Alert tone="danger" style={{ marginBottom: '1rem' }}>{saveError}</Alert>}

      {/* ── Section 1: Content Editor (split pane) ── */}
      <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '1.5rem', marginBottom: '1.5rem' }}>
        {/* Left: Editor */}
        <Card style={{ padding: '1rem' }}>
          <h4 style={{ margin: '0 0 1rem', fontSize: '0.95rem', fontWeight: 600 }}>Content</h4>

          <div style={{ marginBottom: '0.75rem' }}>
            <Label>Title *</Label>
            <Input value={title} onChange={(e) => setTitle(e.target.value)} placeholder="Notification title" />
          </div>

          <div style={{ marginBottom: '0.75rem' }}>
            <Label>Banner Content * (short HTML for the alert banner)</Label>
            <TextArea value={bannerContent} onChange={(e) => setBannerContent(e.target.value)} rows={3} placeholder="<p>Short announcement text shown in the banner...</p>" />
          </div>

          <div style={{ marginBottom: '0.75rem' }}>
            <Label>Detail Content * (full HTML for the learn-more page)</Label>
            <TextArea value={detailContent} onChange={(e) => setDetailContent(e.target.value)} rows={10} placeholder="<h2>Full announcement details...</h2><p>Detailed information here.</p>" style={{ fontFamily: 'monospace', fontSize: '0.85rem' }} />
          </div>

          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0.75rem', marginBottom: '0.75rem' }}>
            <div>
              <Label>Variant</Label>
              <CustomSelect options={variantOptions} value={variant} onValueChange={(value) => setVariant(value as PlatformNotification['variant'])} />
            </div>
            {isEdit && (
              <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem', paddingTop: '1.5rem' }}>
                <Switch checked={isActive} onCheckedChange={setIsActive} />
                <Label>Active</Label>
              </div>
            )}
          </div>

          <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0.75rem' }}>
            <div>
              <Label>Starts At</Label>
              <Input type="datetime-local" value={startsAt} onChange={(e) => setStartsAt(e.target.value)} />
            </div>
            <div>
              <Label>Expires At (optional)</Label>
              <Input type="datetime-local" value={expiresAt} onChange={(e) => setExpiresAt(e.target.value)} />
            </div>
          </div>
        </Card>

        {/* Right: Live Preview */}
        <Card style={{ padding: '1rem' }}>
          <h4 style={{ margin: '0 0 1rem', fontSize: '0.95rem', fontWeight: 600 }}>Live Preview</h4>

          <div style={{ marginBottom: '1rem' }}>
            <Label style={{ marginBottom: '0.5rem', display: 'block' }}>Banner Preview</Label>
            <Alert tone={variantToTone[variant] || 'info'}>
              <div style={{ display: 'flex', alignItems: 'center', gap: '0.75rem' }}>
                <div style={{ flex: 1, fontSize: '0.875rem' }} dangerouslySetInnerHTML={{ __html: bannerContent || '<em>Banner content preview...</em>' }} />
                <button style={{ padding: '0.25rem 0.75rem', borderRadius: '0.25rem', border: '1px solid #ccc', background: 'white', fontSize: '0.75rem', cursor: 'pointer' }}>Learn More</button>
                <button style={{ padding: '0.25rem 0.5rem', borderRadius: '0.25rem', border: 'none', background: 'transparent', fontSize: '0.75rem', cursor: 'pointer', color: '#666' }}>✕</button>
              </div>
            </Alert>
          </div>

          <Separator />

          <div style={{ marginTop: '1rem' }}>
            <Label style={{ marginBottom: '0.5rem', display: 'block' }}>Detail Page Preview</Label>
            <div style={{
              padding: '1rem',
              borderRadius: '0.5rem',
              border: '1px solid var(--alga-muted, #e2e8f0)',
              backgroundColor: 'var(--alga-card-bg, white)',
              maxHeight: '400px',
              overflow: 'auto',
              fontSize: '0.875rem',
              lineHeight: 1.6,
            }}>
              {title && <h2 style={{ margin: '0 0 0.75rem', fontSize: '1.25rem' }}>{title}</h2>}
              <div dangerouslySetInnerHTML={{ __html: detailContent || '<em>Detail content preview...</em>' }} />
            </div>
          </div>
        </Card>
      </div>

      {/* ── Section 2: Audience Targeting ── */}
      <Card style={{ padding: '1rem', marginBottom: '1.5rem' }}>
        <h4 style={{ margin: '0 0 1rem', fontSize: '0.95rem', fontWeight: 600 }}>Audience Targeting</h4>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr 1fr', gap: '0.75rem', marginBottom: '1rem' }}>
          {/* Roles */}
          <div>
            <Label>Roles (leave empty for all)</Label>
            <div style={{ display: 'flex', gap: '0.25rem' }}>
              <Input value={roleInput} onChange={(e) => setRoleInput(e.target.value)} placeholder="e.g. admin" onKeyDown={(e) => { if (e.key === 'Enter') { e.preventDefault(); addRole(); } }} />
              <Button size="sm" variant="outline" onClick={addRole}>Add</Button>
            </div>
            {filterRoles.length > 0 && (
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.25rem', marginTop: '0.5rem' }}>
                {filterRoles.map(r => (
                  <Badge key={r} tone="info">
                    {r} <span style={{ cursor: 'pointer', marginLeft: '0.25rem' }} onClick={() => setFilterRoles(filterRoles.filter(x => x !== r))}>✕</span>
                  </Badge>
                ))}
              </div>
            )}
          </div>

          {/* Tenants */}
          <div>
            <Label>Tenants (leave empty for all)</Label>
            <CustomSelect
              options={tenantOptions}
              value=""
              onValueChange={(v) => { if (v && !filterTenantIds.includes(v)) setFilterTenantIds([...filterTenantIds, v]); }}
              placeholder="Select tenant..."
            />
            {filterTenantIds.length > 0 && (
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.25rem', marginTop: '0.5rem' }}>
                {filterTenantIds.map(id => {
                  const name = tenants.find(t => t.tenant === id)?.company_name || id.slice(0, 8);
                  return (
                    <Badge key={id} tone="info">
                      {name} <span style={{ cursor: 'pointer', marginLeft: '0.25rem' }} onClick={() => setFilterTenantIds(filterTenantIds.filter(x => x !== id))}>✕</span>
                    </Badge>
                  );
                })}
              </div>
            )}
          </div>

          {/* User Types */}
          <div>
            <Label>User Types</Label>
            <div style={{ display: 'flex', gap: '0.75rem', paddingTop: '0.25rem' }}>
              {userTypeOptions.map(opt => (
                <Checkbox
                  key={opt.value}
                  label={opt.label}
                  checked={filterUserTypes.includes(opt.value)}
                  onChange={(e) => {
                    if (e.target.checked) setFilterUserTypes([...filterUserTypes, opt.value]);
                    else setFilterUserTypes(filterUserTypes.filter(t => t !== opt.value));
                  }}
                />
              ))}
            </div>
          </div>
        </div>

        <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: '0.75rem', marginBottom: '1rem' }}>
          {/* Subscription Status */}
          <div>
            <Label>Subscription Status (leave empty for all)</Label>
            <div style={{ display: 'flex', gap: '0.75rem', paddingTop: '0.25rem', flexWrap: 'wrap' }}>
              {[
                { value: 'active', label: 'Active' },
                { value: 'trialing', label: 'Trialing' },
                { value: 'past_due', label: 'Past Due' },
                { value: 'canceled', label: 'Canceled' },
              ].map(opt => (
                <Checkbox
                  key={opt.value}
                  id={`notif-filter-sub-status-${opt.value}`}
                  label={opt.label}
                  checked={filterSubStatuses.includes(opt.value)}
                  onChange={(e) => {
                    if (e.target.checked) setFilterSubStatuses([...filterSubStatuses, opt.value]);
                    else setFilterSubStatuses(filterSubStatuses.filter(s => s !== opt.value));
                  }}
                />
              ))}
            </div>
          </div>

          {/* Product/Plan Name */}
          <div>
            <Label>Plan / Product Name (leave empty for all)</Label>
            <div style={{ display: 'flex', gap: '0.25rem' }}>
              <Input
                id="notif-filter-product-name-input"
                value={productNameInput}
                onChange={(e) => setProductNameInput(e.target.value)}
                placeholder="e.g. Pro, Enterprise"
                onKeyDown={(e) => {
                  if (e.key === 'Enter') {
                    e.preventDefault();
                    const val = productNameInput.trim();
                    if (val && !filterProductNames.includes(val)) {
                      setFilterProductNames([...filterProductNames, val]);
                    }
                    setProductNameInput('');
                  }
                }}
              />
              <Button id="notif-filter-product-name-add" size="sm" variant="outline" onClick={() => {
                const val = productNameInput.trim();
                if (val && !filterProductNames.includes(val)) {
                  setFilterProductNames([...filterProductNames, val]);
                }
                setProductNameInput('');
              }}>Add</Button>
            </div>
            {filterProductNames.length > 0 && (
              <div style={{ display: 'flex', flexWrap: 'wrap', gap: '0.25rem', marginTop: '0.5rem' }}>
                {filterProductNames.map(name => (
                  <Badge key={name} tone="info">
                    {name} <span style={{ cursor: 'pointer', marginLeft: '0.25rem' }} onClick={() => setFilterProductNames(filterProductNames.filter(x => x !== name))}>✕</span>
                  </Badge>
                ))}
              </div>
            )}
          </div>
        </div>

        {/* Email search */}
        <div style={{ display: 'flex', gap: '0.5rem', marginBottom: '1rem' }}>
          <Input value={emailSearch} onChange={(e) => setEmailSearch(e.target.value)} placeholder="Search by email..." style={{ flex: 1 }} />
          <Button size="sm" onClick={handleResolveRecipients} disabled={resolving}>
            {resolving ? 'Resolving...' : 'Resolve Recipients'}
          </Button>
        </div>

        {/* Recipient list */}
        {recipientsResolved && (
          <div>
            <div style={{ display: 'flex', justifyContent: 'space-between', alignItems: 'center', marginBottom: '0.5rem' }}>
              <div style={{ display: 'flex', alignItems: 'center', gap: '0.5rem' }}>
                <Checkbox
                  label="Select All"
                  checked={allSelected}
                  onChange={(e) => {
                    if (e.target.checked) setExcludedUserIds(new Set());
                    else setExcludedUserIds(new Set(recipients.map(r => r.user_id)));
                  }}
                  style={{ fontWeight: 600 }}
                />
                <Text tone="muted">{selectedCount} of {recipients.length} users selected</Text>
              </div>
              <Input
                value={recipientSearch}
                onChange={(e) => setRecipientSearch(e.target.value)}
                placeholder="Filter recipients..."
                style={{ width: '250px' }}
              />
            </div>

            <div style={{ maxHeight: '300px', overflow: 'auto', border: '1px solid var(--alga-muted, #e2e8f0)', borderRadius: '0.375rem' }}>
              <table style={{ width: '100%', borderCollapse: 'collapse', fontSize: '0.8rem' }}>
                <thead>
                  <tr style={{ borderBottom: '1px solid var(--alga-muted, #e2e8f0)', background: 'var(--alga-muted, #f8fafc)' }}>
                    <th style={{ padding: '0.5rem', textAlign: 'left', width: '40px' }}></th>
                    <th style={{ padding: '0.5rem', textAlign: 'left' }}>Name</th>
                    <th style={{ padding: '0.5rem', textAlign: 'left' }}>Email</th>
                    <th style={{ padding: '0.5rem', textAlign: 'left' }}>Tenant</th>
                    <th style={{ padding: '0.5rem', textAlign: 'left' }}>Plan</th>
                    <th style={{ padding: '0.5rem', textAlign: 'left' }}>Subscription</th>
                    <th style={{ padding: '0.5rem', textAlign: 'left' }}>Roles</th>
                  </tr>
                </thead>
                <tbody>
                  {filteredRecipients.map(r => (
                    <tr key={r.user_id} style={{ borderBottom: '1px solid var(--alga-muted, #e2e8f0)' }}>
                      <td style={{ padding: '0.4rem 0.5rem' }}>
                        <Checkbox
                          checked={!excludedUserIds.has(r.user_id)}
                          onChange={(e) => {
                            const next = new Set(excludedUserIds);
                            if (e.target.checked) next.delete(r.user_id);
                            else next.add(r.user_id);
                            setExcludedUserIds(next);
                          }}
                        />
                      </td>
                      <td style={{ padding: '0.4rem 0.5rem' }}>{r.first_name} {r.last_name}</td>
                      <td style={{ padding: '0.4rem 0.5rem' }}>{r.email}</td>
                      <td style={{ padding: '0.4rem 0.5rem' }}>{r.tenant_name || r.tenant.slice(0, 8)}</td>
                      <td style={{ padding: '0.4rem 0.5rem' }}>{r.product_name || '—'}</td>
                      <td style={{ padding: '0.4rem 0.5rem' }}>
                        {r.subscription_status
                          ? <Badge tone={r.subscription_status === 'active' ? 'success' : r.subscription_status === 'trialing' ? 'info' : r.subscription_status === 'past_due' ? 'warning' : 'default'}>
                              {r.subscription_status}
                            </Badge>
                          : '—'}
                      </td>
                      <td style={{ padding: '0.4rem 0.5rem' }}>{r.roles.join(', ') || '—'}</td>
                    </tr>
                  ))}
                  {filteredRecipients.length === 0 && (
                    <tr><td colSpan={7} style={{ padding: '1rem', textAlign: 'center', color: '#666' }}>No matching recipients</td></tr>
                  )}
                </tbody>
              </table>
            </div>
          </div>
        )}
      </Card>

      {/* ── Section 3: Stats (edit mode) ── */}
      {isEdit && stats && (
        <Card style={{ padding: '1rem', marginBottom: '1.5rem' }}>
          <h4 style={{ margin: '0 0 1rem', fontSize: '0.95rem', fontWeight: 600 }}>Read Statistics</h4>
          <div style={{ display: 'flex', gap: '2rem', marginBottom: '1rem' }}>
            <div>
              <Text tone="muted">Dismissed (banner)</Text>
              <div style={{ fontSize: '1.5rem', fontWeight: 700 }}>{stats.total_dismissed}</div>
            </div>
            <div>
              <Text tone="muted">Viewed details</Text>
              <div style={{ fontSize: '1.5rem', fontWeight: 700 }}>{stats.total_detail_viewed}</div>
            </div>
          </div>
          {stats.reads_by_tenant.length > 0 && (
            <DataTable
              columns={[
                { key: 'tenant_name', header: 'Tenant', render: (row) => row.tenant_name || row.tenant.slice(0, 8) },
                { key: 'dismissed', header: 'Dismissed' },
                { key: 'detail_viewed', header: 'Detail Viewed' },
              ] as Column<(typeof stats.reads_by_tenant)[0]>[]}
              data={stats.reads_by_tenant}
            />
          )}
        </Card>
      )}

      {/* ── Save button ── */}
      <div style={{ display: 'flex', gap: '0.5rem' }}>
        <Button onClick={handleSave} disabled={saving || !title || !bannerContent || !detailContent || !recipientsResolved}>
          {saving ? 'Saving...' : (isEdit ? 'Update Notification' : 'Create Notification')}
        </Button>
        <Button variant="outline" onClick={onBack}>Cancel</Button>
      </div>

      {showDeleteConfirm && (
        <ConfirmDialog
          isOpen={true}
          title="Delete Notification"
          message="This will deactivate the notification. It will no longer be shown to any users."
          onConfirm={handleDelete}
          onCancel={() => setShowDeleteConfirm(false)}
        />
      )}
    </div>
  );
}

type View = 'execute' | 'reports' | 'tenants' | 'feature-flags' | 'notifications' | 'audit';

function App() {
  const [currentView, setCurrentView] = useState<View>('execute');

  // Log extension access on mount (via proxy)
  useEffect(() => {
    const logAccess = async () => {
      try {
        await proxyApiCall('/api/v1/platform-reports/access', {
          method: 'POST',
          body: {
            details: {
              source: 'iframe',
              userAgent: navigator.userAgent,
            },
          },
        });
      } catch (error) {
        // Silently fail - access logging shouldn't break the app
        console.debug('[nineminds-control-panel] Failed to log access:', error);
      }
    };
    logAccess();
  }, []);

  const tabItems: TabItem[] = [
    { key: 'execute', label: 'Execute', content: <ExecuteReport /> },
    { key: 'reports', label: 'Reports', content: <ReportsList /> },
    { key: 'tenants', label: 'Tenant Management', content: <TenantManagementView /> },
    { key: 'feature-flags', label: 'Feature Flags', content: <FeatureFlagsView /> },
    { key: 'notifications', label: 'Notifications', content: <NotificationsView /> },
    { key: 'audit', label: 'Audit Logs', content: <AuditLogs /> },
  ];

  return (
    <Tabs
      tabs={tabItems}
      activeKey={currentView}
      onChange={(key) => setCurrentView(key as View)}
    />
  );
}

// Mount the app
const container = document.getElementById('root');
if (container) {
  const root = createRoot(container);
  root.render(<App />);
}
