"use client";

import { format, formatDistanceToNow } from "date-fns";
import {
  Activity,
  AlertTriangle,
  ArrowRight,
  Bot,
  Camera,
  CheckCircle,
  Eye,
  Hand,
  MessageSquare,
  Pause,
  Play,
  Settings,
  User,
  Volume2,
  XCircle,
} from "lucide-react";
import { useCallback, useEffect, useRef, useState } from "react";
import { Badge } from "~/components/ui/badge";
import { Button } from "~/components/ui/button";
import { ScrollArea } from "~/components/ui/scroll-area";
import { api } from "~/trpc/react";
import type { WebSocketMessage } from "~/hooks/useWebSocket";

interface EventsLogProps {
  trialId: string;
  refreshKey: number;
  isLive: boolean;
  maxEvents?: number;
  realtimeEvents?: WebSocketMessage[];
  isWebSocketConnected?: boolean;
}

interface TrialEvent {
  id: string;
  trialId: string;
  eventType: string;
  timestamp: Date;
  data: Record<string, unknown> | null;
  notes: string | null;
  createdAt: Date;
}

const eventTypeConfig = {
  trial_started: {
    label: "Trial Started",
    icon: Play,
    color: "text-green-600",
    bgColor: "bg-green-100",
    importance: "high",
  },
  trial_completed: {
    label: "Trial Completed",
    icon: CheckCircle,
    color: "text-blue-600",
    bgColor: "bg-blue-100",
    importance: "high",
  },
  trial_aborted: {
    label: "Trial Aborted",
    icon: XCircle,
    color: "text-red-600",
    bgColor: "bg-red-100",
    importance: "high",
  },
  step_transition: {
    label: "Step Change",
    icon: ArrowRight,
    color: "text-purple-600",
    bgColor: "bg-purple-100",
    importance: "medium",
  },
  wizard_action: {
    label: "Wizard Action",
    icon: User,
    color: "text-blue-600",
    bgColor: "bg-blue-100",
    importance: "medium",
  },
  robot_action: {
    label: "Robot Action",
    icon: Bot,
    color: "text-green-600",
    bgColor: "bg-green-100",
    importance: "medium",
  },
  wizard_intervention: {
    label: "Intervention",
    icon: Hand,
    color: "text-orange-600",
    bgColor: "bg-orange-100",
    importance: "high",
  },
  manual_intervention: {
    label: "Manual Control",
    icon: Hand,
    color: "text-orange-600",
    bgColor: "bg-orange-100",
    importance: "high",
  },
  emergency_action: {
    label: "Emergency",
    icon: AlertTriangle,
    color: "text-red-600",
    bgColor: "bg-red-100",
    importance: "critical",
  },
  emergency_stop: {
    label: "Emergency Stop",
    icon: AlertTriangle,
    color: "text-red-600",
    bgColor: "bg-red-100",
    importance: "critical",
  },
  recording_control: {
    label: "Recording",
    icon: Camera,
    color: "text-indigo-600",
    bgColor: "bg-indigo-100",
    importance: "low",
  },
  video_control: {
    label: "Video Control",
    icon: Camera,
    color: "text-indigo-600",
    bgColor: "bg-indigo-100",
    importance: "low",
  },
  audio_control: {
    label: "Audio Control",
    icon: Volume2,
    color: "text-indigo-600",
    bgColor: "bg-indigo-100",
    importance: "low",
  },
  pause_interaction: {
    label: "Paused",
    icon: Pause,
    color: "text-yellow-600",
    bgColor: "bg-yellow-100",
    importance: "medium",
  },
  participant_response: {
    label: "Participant",
    icon: MessageSquare,
    color: "text-slate-600",
    bgColor: "bg-slate-100",
    importance: "medium",
  },
  system_event: {
    label: "System",
    icon: Settings,
    color: "text-slate-600",
    bgColor: "bg-slate-100",
    importance: "low",
  },
  annotation: {
    label: "Annotation",
    icon: MessageSquare,
    color: "text-blue-600",
    bgColor: "bg-blue-100",
    importance: "medium",
  },
  default: {
    label: "Event",
    icon: Activity,
    color: "text-slate-600",
    bgColor: "bg-slate-100",
    importance: "low",
  },
};

export function EventsLog({
  trialId,
  refreshKey,
  isLive,
  maxEvents = 100,
  realtimeEvents = [],
  isWebSocketConnected = false,
}: EventsLogProps) {
  const [events, setEvents] = useState<TrialEvent[]>([]);
  const [isAutoScrollEnabled, setIsAutoScrollEnabled] = useState(true);
  const [filter, setFilter] = useState<string>("all");
  const scrollAreaRef = useRef<HTMLDivElement>(null);
  const bottomRef = useRef<HTMLDivElement>(null);

  // Fetch trial events (less frequent when WebSocket is connected)
  const { data: eventsData, isLoading } = api.trials.getEvents.useQuery(
    {
      trialId,
      limit: maxEvents,
      type:
        filter === "all"
          ? undefined
          : (filter as
              | "error"
              | "custom"
              | "trial_start"
              | "trial_end"
              | "step_start"
              | "step_end"
              | "wizard_intervention"),
    },
    {
      refetchInterval: isLive && !isWebSocketConnected ? 2000 : 10000, // Less frequent polling when WebSocket is active
      refetchOnWindowFocus: false,
      enabled: !isWebSocketConnected || !isLive, // Reduce API calls when WebSocket is connected
    },
  );

  // Convert WebSocket events to trial events format (type-safe)
  const convertWebSocketEvent = useCallback(
    (wsEvent: WebSocketMessage): TrialEvent => {
      const eventType =
        wsEvent.type === "trial_action_executed"
          ? "wizard_action"
          : wsEvent.type === "intervention_logged"
            ? "wizard_intervention"
            : wsEvent.type === "step_changed"
              ? "step_transition"
              : wsEvent.type || "system_event";

      const rawData = wsEvent.data;
      const isRecord = (v: unknown): v is Record<string, unknown> =>
        typeof v === "object" && v !== null;

      const data: Record<string, unknown> | null = isRecord(rawData)
        ? rawData
        : null;

      const ts =
        isRecord(rawData) && typeof rawData.timestamp === "number"
          ? rawData.timestamp
          : Date.now();

      const notes =
        isRecord(rawData) && typeof rawData.notes === "string"
          ? rawData.notes
          : null;

      return {
        id: `ws-${Date.now()}-${Math.random()}`,
        trialId,
        eventType,
        timestamp: new Date(ts),
        data,
        notes,
        createdAt: new Date(ts),
      };
    },
    [trialId],
  );

  // Update events when data changes (prioritize WebSocket events)
  useEffect(() => {
    let newEvents: TrialEvent[] = [];

    // Add database events
    if (eventsData) {
      type ApiTrialEvent = {
        id: string;
        trialId: string;
        eventType: string;
        timestamp: string | Date;
        data: unknown;
      };

      const apiEvents = (eventsData as unknown as ApiTrialEvent[]) ?? [];
      newEvents = apiEvents.map((event) => ({
        id: event.id,
        trialId: event.trialId,
        eventType: event.eventType,
        timestamp: new Date(event.timestamp),
        data:
          typeof event.data === "object" && event.data !== null
            ? (event.data as Record<string, unknown>)
            : null,
        notes: null,
        createdAt: new Date(event.timestamp),
      }));
    }

    // Add real-time WebSocket events
    if (realtimeEvents.length > 0) {
      const wsEvents = realtimeEvents.map(convertWebSocketEvent);
      newEvents = [...newEvents, ...wsEvents];
    }

    // Sort by timestamp and remove duplicates
    const uniqueEvents = newEvents
      .sort((a, b) => a.timestamp.getTime() - b.timestamp.getTime())
      .filter(
        (event, index, arr) =>
          index ===
          arr.findIndex(
            (e) =>
              e.eventType === event.eventType &&
              Math.abs(e.timestamp.getTime() - event.timestamp.getTime()) <
                1000,
          ),
      )
      .slice(-maxEvents); // Keep only the most recent events

    setEvents(uniqueEvents);
  }, [
    eventsData,
    refreshKey,
    realtimeEvents,
    trialId,
    maxEvents,
    convertWebSocketEvent,
  ]);

  // Auto-scroll to bottom when new events arrive
  useEffect(() => {
    if (isAutoScrollEnabled && bottomRef.current) {
      bottomRef.current.scrollIntoView({ behavior: "smooth" });
    }
  }, [events, isAutoScrollEnabled]);

  const getEventConfig = (eventType: string) => {
    return (
      eventTypeConfig[eventType as keyof typeof eventTypeConfig] ||
      eventTypeConfig.default
    );
  };

  const formatEventData = (
    eventType: string,
    data: Record<string, unknown> | null,
  ): string | null => {
    if (!data) return null;

    const str = (k: string): string | undefined => {
      const v = data[k];
      return typeof v === "string" ? v : undefined;
    };
    const num = (k: string): number | undefined => {
      const v = data[k];
      return typeof v === "number" ? v : undefined;
    };

    switch (eventType) {
      case "step_transition": {
        const fromIdx = num("from_step");
        const toIdx = num("to_step");
        const stepName = str("step_name");
        if (typeof toIdx === "number") {
          const fromLabel =
            typeof fromIdx === "number" ? `${fromIdx + 1} → ` : "";
          const nameLabel = stepName ? `: ${stepName}` : "";
          return `Step ${fromLabel}${toIdx + 1}${nameLabel}`;
        }
        return "Step changed";
      }

      case "wizard_action": {
        const actionType = str("action_type");
        const stepName = str("step_name");
        const actionLabel = actionType
          ? actionType.replace(/_/g, " ")
          : "Action executed";
        const inStep = stepName ? ` in ${stepName}` : "";
        return `${actionLabel}${inStep}`;
      }

      case "robot_action": {
        const actionName = str("action_name") ?? "Robot action";
        const hasParams =
          typeof data.parameters !== "undefined" && data.parameters !== null;
        return `${actionName}${hasParams ? " with parameters" : ""}`;
      }

      case "emergency_action": {
        const emergency = str("emergency_type");
        return `Emergency: ${
          emergency ? emergency.replace(/_/g, " ") : "Unknown"
        }`;
      }

      case "recording_control": {
        const action = str("action");
        return `Recording ${action === "start_recording" ? "started" : "stopped"}`;
      }

      case "video_control": {
        const action = str("action");
        return `Video ${action === "video_on" ? "enabled" : "disabled"}`;
      }

      case "audio_control": {
        const action = str("action");
        return `Audio ${action === "audio_on" ? "enabled" : "disabled"}`;
      }

      case "wizard_intervention": {
        return (
          str("content") ?? str("intervention_type") ?? "Intervention recorded"
        );
      }

      default: {
        const message = str("message");
        if (message) return message;
        const description = str("description");
        if (description) return description;
        return null;
      }
    }
  };

  const getEventImportanceOrder = (importance: string) => {
    const order = { critical: 0, high: 1, medium: 2, low: 3 };
    return order[importance as keyof typeof order] || 4;
  };

  // Group events by time proximity (within 30 seconds)
  const groupedEvents = events.reduce(
    (groups: TrialEvent[][], event, index) => {
      if (
        index === 0 ||
        Math.abs(
          event.timestamp.getTime() -
            (events[index - 1]?.timestamp.getTime() ?? 0),
        ) > 30000
      ) {
        groups.push([event]);
      } else {
        groups[groups.length - 1]?.push(event);
      }
      return groups;
    },
    [],
  );

  // uniqueEventTypes removed (unused)

  if (isLoading) {
    return (
      <div className="flex h-full flex-col">
        <div className="border-b border-slate-200 p-4">
          <h3 className="flex items-center space-x-2 font-medium text-slate-900">
            <Activity className="h-4 w-4" />
            <span>Events Log</span>
          </h3>
        </div>
        <div className="flex flex-1 items-center justify-center">
          <div className="text-center">
            <Activity className="mx-auto mb-2 h-6 w-6 animate-pulse text-slate-400" />
            <p className="text-sm text-slate-500">Loading events...</p>
          </div>
        </div>
      </div>
    );
  }

  return (
    <div className="flex h-full flex-col">
      {/* Header */}
      <div className="border-b border-slate-200 p-4">
        <div className="mb-3 flex items-center justify-between">
          <h3 className="flex items-center space-x-2 font-medium text-slate-900">
            <Activity className="h-4 w-4" />
            <span>Events Log</span>
            {isLive && (
              <div className="flex items-center space-x-1">
                <div
                  className={`h-2 w-2 animate-pulse rounded-full ${
                    isWebSocketConnected ? "bg-green-500" : "bg-red-500"
                  }`}
                ></div>
                <span
                  className={`text-xs ${
                    isWebSocketConnected ? "text-green-600" : "text-red-600"
                  }`}
                >
                  {isWebSocketConnected ? "REAL-TIME" : "LIVE"}
                </span>
              </div>
            )}
          </h3>
          <div className="flex items-center space-x-2">
            <Badge variant="outline" className="text-xs">
              {events.length} events
            </Badge>
            {isWebSocketConnected && (
              <Badge className="bg-green-100 text-xs text-green-800">
                Real-time
              </Badge>
            )}
          </div>
        </div>

        {/* Filter Controls */}
        <div className="flex items-center space-x-2">
          <Button
            variant={filter === "all" ? "default" : "outline"}
            size="sm"
            onClick={() => setFilter("all")}
            className="h-7 text-xs"
          >
            All
          </Button>
          <Button
            variant={filter === "wizard_action" ? "default" : "outline"}
            size="sm"
            onClick={() => setFilter("wizard_action")}
            className="h-7 text-xs"
          >
            Wizard
          </Button>
          <Button
            variant={filter === "robot_action" ? "default" : "outline"}
            size="sm"
            onClick={() => setFilter("robot_action")}
            className="h-7 text-xs"
          >
            Robot
          </Button>
          <Button
            variant={filter === "emergency_action" ? "default" : "outline"}
            size="sm"
            onClick={() => setFilter("emergency_action")}
            className="h-7 text-xs"
          >
            Emergency
          </Button>
        </div>
      </div>

      {/* Events List */}
      <ScrollArea className="flex-1" ref={scrollAreaRef}>
        <div className="space-y-4 p-4">
          {events.length === 0 ? (
            <div className="py-8 text-center">
              <Activity className="mx-auto mb-2 h-8 w-8 text-slate-300" />
              <p className="text-sm text-slate-500">No events yet</p>
              <p className="mt-1 text-xs text-slate-400">
                Events will appear here as the trial progresses
              </p>
            </div>
          ) : (
            groupedEvents.map((group, groupIndex) => (
              <div key={groupIndex} className="space-y-2">
                {/* Time Header */}
                <div className="flex items-center space-x-2">
                  <div className="text-xs font-medium text-slate-500">
                    {group[0] ? format(group[0].timestamp, "HH:mm:ss") : ""}
                  </div>
                  <div className="h-px flex-1 bg-slate-200"></div>
                  <div className="text-xs text-slate-400">
                    {group[0]
                      ? formatDistanceToNow(group[0].timestamp, {
                          addSuffix: true,
                        })
                      : ""}
                  </div>
                </div>

                {/* Events in Group */}
                {group
                  .sort(
                    (a, b) =>
                      getEventImportanceOrder(
                        getEventConfig(a.eventType).importance,
                      ) -
                      getEventImportanceOrder(
                        getEventConfig(b.eventType).importance,
                      ),
                  )
                  .map((event) => {
                    const config = getEventConfig(event.eventType);
                    const EventIcon = config.icon;
                    const eventData = formatEventData(
                      event.eventType,
                      event.data,
                    );

                    return (
                      <div
                        key={event.id}
                        className={`flex items-start space-x-3 rounded-lg border p-3 transition-colors ${
                          config.importance === "critical"
                            ? "border-red-200 bg-red-50"
                            : config.importance === "high"
                              ? "border-amber-200 bg-amber-50"
                              : "border-slate-200 bg-slate-50 hover:bg-slate-100"
                        }`}
                      >
                        <div
                          className={`flex h-6 w-6 flex-shrink-0 items-center justify-center rounded-full ${config.bgColor}`}
                        >
                          <EventIcon className={`h-3 w-3 ${config.color}`} />
                        </div>

                        <div className="min-w-0 flex-1">
                          <div className="flex items-center space-x-2">
                            <span className="text-sm font-medium text-slate-900">
                              {config.label}
                            </span>
                            {config.importance === "critical" && (
                              <Badge variant="destructive" className="text-xs">
                                CRITICAL
                              </Badge>
                            )}
                            {config.importance === "high" && (
                              <Badge
                                variant="outline"
                                className="border-amber-300 text-xs text-amber-600"
                              >
                                HIGH
                              </Badge>
                            )}
                          </div>

                          {eventData && (
                            <p className="mt-1 text-sm break-words text-slate-600">
                              {eventData}
                            </p>
                          )}

                          {event.notes && (
                            <p className="mt-1 text-xs text-slate-500 italic">
                              {event.notes}
                            </p>
                          )}

                          {event.data &&
                            typeof event.data === "object" &&
                            Object.keys(event.data).length > 0 && (
                              <details className="mt-2">
                                <summary className="cursor-pointer text-xs text-blue-600 hover:text-blue-800">
                                  View details
                                </summary>
                                <pre className="mt-1 overflow-x-auto rounded border bg-white p-2 text-xs text-slate-600">
                                  {JSON.stringify(event.data, null, 2)}
                                </pre>
                              </details>
                            )}
                        </div>

                        <div className="flex-shrink-0 text-xs text-slate-400">
                          {format(event.timestamp, "HH:mm")}
                        </div>
                      </div>
                    );
                  })}
              </div>
            ))
          )}

          <div ref={bottomRef} />
        </div>
      </ScrollArea>

      {/* Auto-scroll Control */}
      {events.length > 0 && (
        <div className="border-t border-slate-200 p-2">
          <Button
            variant="ghost"
            size="sm"
            onClick={() => setIsAutoScrollEnabled(!isAutoScrollEnabled)}
            className="w-full text-xs"
          >
            <Eye className="mr-1 h-3 w-3" />
            Auto-scroll: {isAutoScrollEnabled ? "ON" : "OFF"}
          </Button>
        </div>
      )}
    </div>
  );
}
