import { useMemo, useState } from 'react';
import { Badge, DataTable, EmptyState, MonoText, SectionHeader } from '@cameleer/design-system';
import type { Column } from '@cameleer/design-system';
import { LiveBanner } from './LiveBanner';
import { useApplicationConfig, useUpdateApplicationConfig, useProcessorRouteMapping } from '../../../../api/queries/commands';
import type { TapDefinition } from '../../../../api/queries/commands';
import { useCatalog } from '../../../../api/queries/catalog';
import { applyTracedProcessorUpdate } from '../../../../utils/config-draft-utils';
import type { App } from '../../../../api/queries/admin/apps';
import type { Environment } from '../../../../api/queries/admin/environments';
import sectionStyles from '../../../../styles/section-card.module.css';
import appsStyles from '../../AppsTab.module.css';

interface TracedTapRow {
  id: string;
  processorId: string;
  captureMode: string | null;
  taps: TapDefinition[];
}

interface Props {
  app: App;
  environment: Environment;
}

export function TracesTapsTab({ app, environment }: Props) {
  const envSlug = environment.slug;
  const { data: agentConfig } = useApplicationConfig(app.slug, envSlug);
  const updateAgentConfig = useUpdateApplicationConfig();
  const { data: processorToRoute = {} } = useProcessorRouteMapping(app.slug, envSlug);
  const { data: catalog } = useCatalog(envSlug);

  // Local draft — each change is immediately flushed to live agents
  const [tracedDraft, setTracedDraft] = useState<Record<string, string> | null>(null);

  // Use draft if in-flight, otherwise reflect server state
  const effectiveTraced = tracedDraft ?? agentConfig?.tracedProcessors ?? {};

  async function updateTracedProcessor(processorId: string, mode: string) {
    if (!agentConfig) return;
    const next = applyTracedProcessorUpdate(effectiveTraced, processorId, mode);
    setTracedDraft(next);
    try {
      await updateAgentConfig.mutateAsync({
        config: { ...agentConfig, tracedProcessors: next },
        environment: envSlug,
        apply: 'live',
      });
    } finally {
      setTracedDraft(null);
    }
  }

  const tracedTapRows: TracedTapRow[] = useMemo(() => {
    const taps = agentConfig?.taps ?? [];
    const pids = new Set<string>([
      ...Object.keys(effectiveTraced),
      ...taps.map((t) => t.processorId),
    ]);
    return Array.from(pids)
      .sort()
      .map((pid) => ({
        id: pid,
        processorId: pid,
        captureMode: effectiveTraced[pid] ?? null,
        taps: taps.filter((t) => t.processorId === pid),
      }));
  // eslint-disable-next-line react-hooks/exhaustive-deps
  }, [effectiveTraced, agentConfig?.taps]);

  const tracedCount = Object.keys(effectiveTraced).length;
  const tapCount = agentConfig?.taps?.length ?? 0;

  const tracedTapColumns: Column<TracedTapRow>[] = useMemo(
    () => [
      {
        key: 'route' as any,
        header: 'Route',
        render: (_v: unknown, row: TracedTapRow) => {
          const routeId = processorToRoute[row.processorId];
          return routeId ? (
            <span className={appsStyles.routeLabel}>{routeId}</span>
          ) : (
            <span className={appsStyles.hint}>&mdash;</span>
          );
        },
      },
      {
        key: 'processorId',
        header: 'Processor',
        render: (_v: unknown, row: TracedTapRow) => (
          <MonoText size="xs">{row.processorId}</MonoText>
        ),
      },
      {
        key: 'captureMode',
        header: 'Capture',
        render: (_v: unknown, row: TracedTapRow) => {
          if (row.captureMode === null) return <span className={appsStyles.hint}>&mdash;</span>;
          return (
            <select
              className={appsStyles.nativeSelect}
              value={row.captureMode}
              onChange={(e) => updateTracedProcessor(row.processorId, e.target.value)}
              disabled={updateAgentConfig.isPending}
            >
              <option value="NONE">None</option>
              <option value="INPUT">Input</option>
              <option value="OUTPUT">Output</option>
              <option value="BOTH">Both</option>
            </select>
          );
        },
      },
      {
        key: 'taps',
        header: 'Taps',
        render: (_v: unknown, row: TracedTapRow) =>
          row.taps.length === 0 ? (
            <span className={appsStyles.hint}>&mdash;</span>
          ) : (
            <div className={appsStyles.tapBadges}>
              {row.taps.map((t) => (
                <button
                  key={t.tapId}
                  className={appsStyles.tapBadgeLink}
                  title="Manage tap on route page"
                >
                  <Badge
                    label={t.attributeName}
                    color={t.enabled ? 'success' : 'auto'}
                    variant="filled"
                  />
                </button>
              ))}
            </div>
          ),
      },
      {
        key: '_remove' as const,
        header: '',
        width: '36px',
        render: (_v: unknown, row: TracedTapRow) =>
          row.captureMode === null ? null : (
            <button
              className={appsStyles.removeBtn}
              title="Remove"
              onClick={() => updateTracedProcessor(row.processorId, 'REMOVE')}
              disabled={updateAgentConfig.isPending}
            >
              &times;
            </button>
          ),
      },
    ],
    // eslint-disable-next-line react-hooks/exhaustive-deps
    [processorToRoute, updateAgentConfig.isPending, effectiveTraced],
  );

  // catalog is needed only to satisfy the import (keeps the same data shape as legacy ConfigSubTab)
  void catalog;

  return (
    <div>
      <LiveBanner />
      <div className={sectionStyles.section}>
        <SectionHeader>Traces &amp; Taps</SectionHeader>
        <span className={appsStyles.sectionSummary}>
          {tracedCount} traced &middot; {tapCount} taps
        </span>
        {tracedTapRows.length > 0 ? (
          <DataTable<TracedTapRow>
            columns={tracedTapColumns}
            data={tracedTapRows}
            pageSize={20}
            flush
          />
        ) : (
          <EmptyState
            title="No traces or taps"
            description="No processor traces or taps configured."
          />
        )}
      </div>
    </div>
  );
}
