import { useState, useCallback } from 'react';
import { Panel } from '@/components/ui/Panel';
import { Spinner } from '@/components/ui/Spinner';

// ---------------------------------------------------------------------------
// Types
// ---------------------------------------------------------------------------

export type McpServer = 'code' | 'docs' | 'otel' | 'unified';

export interface McpResponse {
  server: string;
  tool: string;
  status: 'success' | 'error';
  timing: number;
  data: unknown;
  timestamp: Date;
}

export interface SavedQuery {
  server: McpServer;
  tool: string;
  params: string;
  label: string;
}

export interface HistoryEntry {
  server: McpServer;
  tool: string;
  params: string;
  status: 'success' | 'error';
  timing: number;
  timestamp: string;
  responseData: unknown;
}

// ---------------------------------------------------------------------------
// Constants
// ---------------------------------------------------------------------------

const SERVER_LABELS: Record<McpServer, string> = {
  code: 'Code',
  docs: 'Docs',
  otel: 'OTel',
  unified: 'Unified',
};

const SERVER_ENDPOINTS: Record<McpServer, string> = {
  code: '/mcp/code',
  docs: '/mcp/docs',
  otel: '/mcp/otel',
  unified: '/mcp/unified',
};

const SERVER_TOOLS: Record<McpServer, string[]> = {
  code: ['search_code', 'get_entity', 'get_file_context', 'list_files', 'get_dependencies'],
  docs: ['search_docs', 'get_document', 'list_documents', 'get_section'],
  otel: ['get_traces', 'get_service_health', 'get_metrics', 'get_logs', 'get_service_map'],
  unified: ['query', 'component_overview', 'incident_context', 'diff_versions', 'route_query'],
};

// ---------------------------------------------------------------------------
// Helpers
// ---------------------------------------------------------------------------

const HISTORY_KEY = 'mcp-history';
const SAVED_KEY = 'mcp-saved-queries';
const MAX_HISTORY = 50;

function loadHistory(): HistoryEntry[] {
  try {
    const raw = localStorage.getItem(HISTORY_KEY);
    return raw ? (JSON.parse(raw) as HistoryEntry[]) : [];
  } catch {
    return [];
  }
}

function saveHistory(entries: HistoryEntry[]) {
  localStorage.setItem(HISTORY_KEY, JSON.stringify(entries.slice(0, MAX_HISTORY)));
}

function loadSaved(): SavedQuery[] {
  try {
    const raw = localStorage.getItem(SAVED_KEY);
    return raw ? (JSON.parse(raw) as SavedQuery[]) : [];
  } catch {
    return [];
  }
}

function saveSavedQueries(queries: SavedQuery[]) {
  localStorage.setItem(SAVED_KEY, JSON.stringify(queries));
}

// ---------------------------------------------------------------------------
// Component
// ---------------------------------------------------------------------------

interface McpRequestBuilderProps {
  onResponse: (response: McpResponse) => void;
  onHistoryChange: () => void;
  /** Allow parent to inject values (for replay). */
  initialServer?: McpServer;
  initialTool?: string;
  initialParams?: string;
}

export function McpRequestBuilder({
  onResponse,
  onHistoryChange,
  initialServer,
  initialTool,
  initialParams,
}: McpRequestBuilderProps) {
  const [server, setServer] = useState<McpServer>(initialServer ?? 'unified');
  const [tool, setTool] = useState(initialTool ?? SERVER_TOOLS.unified[0] ?? '');
  const [params, setParams] = useState(initialParams ?? '{ "query": "..." }');
  const [jsonError, setJsonError] = useState(false);
  const [loading, setLoading] = useState(false);

  // Sync when parent changes initial values (replay)
  // We use key-based remount from parent instead of useEffect to keep it simple.

  const handleServerChange = useCallback(
    (s: McpServer) => {
      setServer(s);
      const tools = SERVER_TOOLS[s];
      setTool(tools[0] ?? '');
    },
    [],
  );

  const validateJson = useCallback((value: string) => {
    try {
      JSON.parse(value);
      setJsonError(false);
    } catch {
      setJsonError(true);
    }
  }, []);

  const handleExecute = useCallback(async () => {
    let parsed: unknown;
    try {
      parsed = JSON.parse(params);
      setJsonError(false);
    } catch {
      setJsonError(true);
      return;
    }

    setLoading(true);
    const start = performance.now();

    try {
      const res = await fetch(SERVER_ENDPOINTS[server], {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          Accept: 'application/json, text/event-stream',
        },
        body: JSON.stringify({
          jsonrpc: '2.0',
          id: 1,
          method: 'tools/call',
          params: { name: tool, arguments: parsed },
        }),
      });

      const timing = Math.round(performance.now() - start);
      const body = (await res.json()) as Record<string, unknown>;

      const isError = !res.ok || body.error != null;
      const mcpResponse: McpResponse = {
        server: SERVER_LABELS[server],
        tool,
        status: isError ? 'error' : 'success',
        timing,
        data: body.error ?? body.result ?? body,
        timestamp: new Date(),
      };

      onResponse(mcpResponse);

      // Persist to history
      const entry: HistoryEntry = {
        server,
        tool,
        params,
        status: mcpResponse.status,
        timing,
        timestamp: new Date().toISOString(),
        responseData: mcpResponse.data,
      };
      const history = loadHistory();
      history.unshift(entry);
      saveHistory(history);
      onHistoryChange();
    } catch (err) {
      const timing = Math.round(performance.now() - start);
      const mcpResponse: McpResponse = {
        server: SERVER_LABELS[server],
        tool,
        status: 'error',
        timing,
        data: { message: err instanceof Error ? err.message : 'Network error' },
        timestamp: new Date(),
      };
      onResponse(mcpResponse);

      const entry: HistoryEntry = {
        server,
        tool,
        params,
        status: 'error',
        timing,
        timestamp: new Date().toISOString(),
        responseData: mcpResponse.data,
      };
      const history = loadHistory();
      history.unshift(entry);
      saveHistory(history);
      onHistoryChange();
    } finally {
      setLoading(false);
    }
  }, [server, tool, params, onResponse, onHistoryChange]);

  const handleSave = useCallback(() => {
    const label = `${SERVER_LABELS[server]} / ${tool}`;
    const saved = loadSaved();
    saved.push({ server, tool, params, label });
    saveSavedQueries(saved);
  }, [server, tool, params]);

  return (
    <Panel title="Request Builder">
      {/* Server Toggle Buttons */}
      <div className="flex gap-2 mb-4">
        {(Object.keys(SERVER_LABELS) as McpServer[]).map((s) => (
          <button
            key={s}
            onClick={() => handleServerChange(s)}
            className={`px-3 py-1.5 text-xs font-medium rounded-md transition-colors ${
              server === s
                ? 'bg-accent-blue text-white'
                : 'bg-surface border border-border text-text-secondary hover:text-text-primary'
            }`}
          >
            {SERVER_LABELS[s]}
          </button>
        ))}
      </div>

      {/* Tool Dropdown */}
      <div className="mb-4">
        <label className="block text-xs text-text-secondary mb-1">Tool</label>
        <select
          value={tool}
          onChange={(e) => setTool(e.target.value)}
          className="w-full px-3 py-2 text-sm bg-surface border border-border rounded-md text-text-primary focus:outline-none focus:border-accent-blue"
        >
          {SERVER_TOOLS[server].map((t) => (
            <option key={t} value={t}>
              {t}
            </option>
          ))}
        </select>
      </div>

      {/* JSON Parameter Editor */}
      <div className="mb-4">
        <label className="block text-xs text-text-secondary mb-1">Parameters (JSON)</label>
        <textarea
          value={params}
          onChange={(e) => setParams(e.target.value)}
          onBlur={() => validateJson(params)}
          rows={6}
          className={`w-full px-3 py-2 text-sm font-mono bg-surface border rounded-md text-text-primary placeholder:text-text-muted focus:outline-none resize-y ${
            jsonError ? 'border-accent-red' : 'border-border focus:border-accent-blue'
          }`}
          placeholder='{ "query": "..." }'
        />
        {jsonError && <p className="text-xs text-accent-red mt-1">Invalid JSON</p>}
      </div>

      {/* Action Buttons */}
      <div className="flex items-center gap-3">
        <button
          onClick={() => void handleExecute()}
          disabled={loading}
          className="flex items-center gap-2 px-4 py-2 text-sm font-medium bg-accent-blue text-white rounded-md hover:opacity-90 transition-opacity disabled:opacity-50"
        >
          {loading && <Spinner size="sm" />}
          Execute
        </button>
        <button
          onClick={handleSave}
          className="px-4 py-2 text-sm text-text-secondary border border-border rounded-md hover:text-text-primary hover:border-text-muted transition-colors"
        >
          Save
        </button>
      </div>
    </Panel>
  );
}
