import { useParams } from "react-router-dom";
import { graphql, useLazyLoadQuery, useSubscription } from "react-relay";
import { useEffect, useMemo, useState } from "react";
import type { GraphQLSubscriptionConfig } from "relay-runtime";
import type { SliceJetstreamQuery } from "../__generated__/SliceJetstreamQuery.graphql.ts";
import type { SliceJetstreamLogsQuery } from "../__generated__/SliceJetstreamLogsQuery.graphql.ts";
import type { SliceJetstreamSubscription } from "../__generated__/SliceJetstreamSubscription.graphql.ts";
import Layout from "../components/Layout.tsx";
import { Avatar } from "../components/Avatar.tsx";
import { SliceSubNav } from "../components/SliceSubNav.tsx";
import { ChevronRight } from "lucide-react";
import { useSessionContext } from "../lib/useSession.ts";
import { isSliceOwner } from "../lib/permissions.ts";

// Use the GraphQL-generated type for log entries
type LogEntry = SliceJetstreamLogsQuery["response"]["jetstreamLogs"][number];

export default function SliceJetstream() {
  const { handle, rkey } = useParams<{ handle: string; rkey: string }>();
  const { session } = useSessionContext();
  const [realtimeLogs, setRealtimeLogs] = useState<LogEntry[]>([]);
  const [expandedLogs, setExpandedLogs] = useState<Set<string>>(new Set());

  // First query to get the slice URI
  const data = useLazyLoadQuery<SliceJetstreamQuery>(
    graphql`
      query SliceJetstreamQuery($where: NetworkSlicesSliceWhereInput) {
        networkSlicesSlices(first: 1, where: $where) {
          edges {
            node {
              uri
              name
              domain
              actorHandle
              did
              networkSlicesActorProfile {
                avatar {
                  url(preset: "avatar")
                }
              }
            }
          }
        }
      }
    `,
    {
      where: {
        actorHandle: { eq: handle },
        uri: { contains: rkey },
      },
    },
  );

  const slice = data.networkSlicesSlices.edges[0]?.node;

  const isOwner = isSliceOwner(slice, session);

  // Second query for logs using the actual slice URI
  const logsData = useLazyLoadQuery<SliceJetstreamLogsQuery>(
    graphql`
      query SliceJetstreamLogsQuery($slice: String) {
        jetstreamLogs(slice: $slice, limit: 50) {
          id
          createdAt
          level
          message
          metadata
          sliceUri
        }
      }
    `,
    {
      slice: slice?.uri,
    },
    {
      fetchPolicy: "store-and-network",
    },
  );

  // Setup subscription for real-time logs
  const subscriptionConfig = useMemo<
    GraphQLSubscriptionConfig<SliceJetstreamSubscription>
  >(
    () => ({
      subscription: graphql`
        subscription SliceJetstreamSubscription($slice: String) {
          jetstreamLogsCreated(slice: $slice) {
            id
            createdAt
            level
            message
            metadata
            sliceUri
          }
        }
      `,
      variables: {
        slice: slice?.uri || "",
      },
      onNext: (response) => {
        if (response?.jetstreamLogsCreated) {
          const newLog = response.jetstreamLogsCreated;
          setRealtimeLogs((prev) => [newLog, ...prev].slice(0, 100)); // Keep last 100
        }
      },
    }),
    [slice?.uri],
  );

  useSubscription(subscriptionConfig);

  // Combine historical and real-time logs
  const allLogs = useMemo(() => {
    const historical = logsData.jetstreamLogs || [];

    // Merge and dedupe by id, real-time logs take precedence
    const logsMap = new Map<string, (typeof historical)[number]>();
    [...historical, ...realtimeLogs].filter(Boolean).forEach((log) => {
      if (log?.id) {
        logsMap.set(log.id, log);
      }
    });

    return Array.from(logsMap.values()).sort(
      (a, b) =>
        new Date(b.createdAt).getTime() - new Date(a.createdAt).getTime(),
    );
  }, [logsData.jetstreamLogs, realtimeLogs]);

  const getLevelColor = (level: string) => {
    switch (level.toLowerCase()) {
      case "error":
        return "text-red-400 bg-red-950/30";
      case "warn":
        return "text-yellow-400 bg-yellow-950/30";
      case "info":
        return "text-blue-400 bg-blue-950/30";
      default:
        return "text-zinc-400 bg-zinc-900";
    }
  };

  const formatTimestamp = (timestamp: string) => {
    const date = new Date(timestamp);
    return date.toLocaleString();
  };

  const toggleExpanded = (logId: string) => {
    setExpandedLogs((prev) => {
      const next = new Set(prev);
      if (next.has(logId)) {
        next.delete(logId);
      } else {
        next.add(logId);
      }
      return next;
    });
  };

  // Expand all logs with metadata by default
  useEffect(() => {
    const logsWithMetadata = allLogs
      .filter((log) => log.metadata)
      .map((log) => log.id);
    setExpandedLogs(new Set(logsWithMetadata));
  }, [allLogs]);

  // Highlight NSIDs in log messages
  const highlightNsid = (message: string) => {
    // Match NSID pattern (e.g., fm.teal.alpha.feed.play or app.bsky.feed.post)
    const nsidPattern = /\b([a-z]+\.[a-z0-9]+(?:\.[a-z0-9]+)+)\b/gi;
    const parts = message.split(nsidPattern);

    return parts.map((part, index) => {
      // Check if this part matches an NSID pattern
      if (index % 2 === 1) {
        return (
          <span key={index} className="text-cyan-400 font-mono">
            {part}
          </span>
        );
      }
      return part;
    });
  };

  return (
    <Layout
      subNav={
        <SliceSubNav
          handle={handle!}
          rkey={rkey!}
          sliceName={slice?.name}
          activeTab="jetstream"
          isOwner={isOwner}
        />
      }
    >
      <div className="mb-8">
        <div className="flex items-center gap-3">
          <Avatar
            src={slice?.networkSlicesActorProfile?.avatar?.url}
            alt={`${handle} avatar`}
            size="md"
          />
          <div className="flex-1">
            <div className="flex items-center gap-2 mb-2">
              <h1 className="text-2xl font-medium text-zinc-200">
                Jetstream Logs
              </h1>
              <div className="flex items-center gap-1.5 px-2 py-1 bg-zinc-900/50 rounded">
                <div className="h-2 w-2 bg-green-500 rounded-full animate-pulse">
                </div>
                <span className="text-xs text-zinc-400">Live</span>
              </div>
            </div>
            <p className="text-sm text-zinc-500">
              Real-time event streaming for {slice?.name}
            </p>
          </div>
        </div>
      </div>

      <div>
        {allLogs.length === 0
          ? (
            <div className="p-8 text-center text-zinc-500">
              No logs yet. Logs will appear here in real-time.
            </div>
          )
          : (
            allLogs.map((log) => {
              const isExpanded = expandedLogs.has(log.id);
              return (
                <div key={log.id}>
                  <div
                    className="flex items-center gap-2 py-1.5 cursor-pointer hover:bg-zinc-900/50 rounded px-2"
                    onClick={() => log.metadata && toggleExpanded(log.id)}
                  >
                    {log.metadata
                      ? (
                        <ChevronRight
                          size={14}
                          className={`text-zinc-500 transition-transform flex-shrink-0 ${
                            isExpanded ? "rotate-90" : ""
                          }`}
                        />
                      )
                      : <div className="w-3.5 flex-shrink-0" />}
                    <span
                      className={`px-2 py-0.5 text-xs font-medium rounded ${
                        getLevelColor(
                          log.level,
                        )
                      }`}
                    >
                      {log.level.toUpperCase()}
                    </span>
                    <span className="text-sm text-zinc-400 flex-1">
                      {highlightNsid(log.message)}
                    </span>
                    <span className="text-xs text-zinc-600">
                      {formatTimestamp(log.createdAt)}
                    </span>
                  </div>
                  {log.metadata && isExpanded && (
                    <div className="pl-6 pr-2 pb-2">
                      <pre className="text-xs text-zinc-400 bg-zinc-950 p-2 rounded overflow-x-auto">
                      {JSON.stringify(log.metadata, null, 2)}
                      </pre>
                    </div>
                  )}
                </div>
              );
            })
          )}
      </div>
    </Layout>
  );
}
