import { ArrowPathIcon } from "@heroicons/react/20/solid";
import { useEffect, useRef, useState } from "react";
import { RunsIcon } from "~/assets/icons/RunsIcon";
import { LogLevelTooltipInfo } from "~/components/LogLevelTooltipInfo";
import { Button, LinkButton } from "~/components/primitives/Buttons";
import { useEnvironment } from "~/hooks/useEnvironment";
import { useOrganization } from "~/hooks/useOrganizations";
import { useProject } from "~/hooks/useProject";
import type { LogEntry } from "~/presenters/v3/LogsListPresenter.server";
import { cn } from "~/utils/cn";
import { highlightSearchText } from "~/utils/logUtils";
import { v3RunSpanPath } from "~/utils/pathBuilder";
import { DateTimeAccurate } from "../primitives/DateTime";
import { Paragraph } from "../primitives/Paragraph";
import { Spinner } from "../primitives/Spinner";
import {
  Table,
  TableBlankRow,
  TableBody,
  TableCell,
  TableCellMenu,
  TableHeader,
  TableHeaderCell,
  TableRow,
  type TableVariant,
} from "../primitives/Table";
import { LogLevel } from "./LogLevel";

type LogsTableProps = {
  logs: LogEntry[];
  searchTerm?: string;
  isLoading?: boolean;
  isLoadingMore?: boolean;
  hasMore?: boolean;
  onLoadMore?: () => void;
  onCheckForMore?: () => void;
  variant?: TableVariant;
  selectedLogId?: string;
  onLogSelect?: (logId: string) => void;
};

// Inner shadow for level highlighting (better scroll performance than border-l)
function getLevelBoxShadow(level: LogEntry["level"]): string {
  switch (level) {
    case "ERROR":
      return "inset 2px 0 0 0 rgb(239, 68, 68)";
    case "WARN":
      return "inset 2px 0 0 0 rgb(234, 179, 8)";
    case "INFO":
      return "inset 2px 0 0 0 rgb(59, 130, 246)";
    case "TRACE":
      return "inset 2px 0 0 0 rgb(168, 85, 247)";
    case "DEBUG":
    default:
      return "none";
  }
}

export function LogsTable({
  logs,
  searchTerm,
  isLoading = false,
  isLoadingMore = false,
  hasMore = false,
  onLoadMore,
  onCheckForMore,
  selectedLogId,
  onLogSelect,
}: LogsTableProps) {
  const organization = useOrganization();
  const project = useProject();
  const environment = useEnvironment();
  const loadMoreRef = useRef<HTMLDivElement>(null);
  const [showLoadMoreSpinner, setShowLoadMoreSpinner] = useState(false);

  // Show load more spinner only after 0.2 seconds of loading time
  useEffect(() => {
    if (!isLoadingMore) {
      setShowLoadMoreSpinner(false);
      return;
    }

    const timer = setTimeout(() => {
      setShowLoadMoreSpinner(true);
    }, 200);

    return () => clearTimeout(timer);
  }, [isLoadingMore]);

  // Intersection observer for infinite scroll
  useEffect(() => {
    if (!hasMore || isLoadingMore || !onLoadMore) return;

    const observer = new IntersectionObserver(
      (entries) => {
        if (entries[0].isIntersecting) {
          onLoadMore();
        }
      },
      { threshold: 0.1 }
    );

    const currentRef = loadMoreRef.current;
    if (currentRef) {
      observer.observe(currentRef);
    }

    return () => {
      if (currentRef) {
        observer.unobserve(currentRef);
      }
    };
  }, [hasMore, isLoadingMore, onLoadMore]);

  return (
    <div className="relative h-full overflow-auto border-t scrollbar-thin scrollbar-track-transparent scrollbar-thumb-surface-control">
      <Table variant="compact/mono" containerClassName="overflow-visible" showTopBorder={false}>
        <TableHeader className="sticky top-0 z-10">
          <TableRow>
            <TableHeaderCell className="min-w-48 whitespace-nowrap">Time</TableHeaderCell>
            <TableHeaderCell className="min-w-24 whitespace-nowrap">Run</TableHeaderCell>
            <TableHeaderCell className="min-w-32 whitespace-nowrap">Task</TableHeaderCell>
            <TableHeaderCell
              className="min-w-24 whitespace-nowrap"
              tooltip={<LogLevelTooltipInfo />}
              disableTooltipHoverableContent
            >
              Level
            </TableHeaderCell>
            <TableHeaderCell className="w-full min-w-0">Message</TableHeaderCell>
          </TableRow>
        </TableHeader>
        <TableBody>
          {logs.length === 0 ? (
            <BlankState isLoading={isLoading} onRefresh={() => window.location.reload()} />
          ) : (
            logs.map((log) => {
              const isSelected = selectedLogId === log.id;
              const runPath = v3RunSpanPath(
                organization,
                project,
                environment,
                { friendlyId: log.runId },
                { spanId: log.spanId }
              );

              const handleRowClick = () => onLogSelect?.(log.id);

              return (
                <TableRow
                  key={log.id}
                  className={cn(
                    "cursor-pointer transition-colors",
                    isSelected ? "bg-background-hover" : "hover:bg-background-dimmed"
                  )}
                  isSelected={isSelected}
                >
                  <TableCell
                    className="whitespace-nowrap tabular-nums"
                    onClick={handleRowClick}
                    hasAction
                    style={{
                      boxShadow: getLevelBoxShadow(log.level),
                    }}
                  >
                    <DateTimeAccurate date={log.triggeredTimestamp} hour12={false} />
                  </TableCell>
                  <TableCell className="min-w-24 cursor-pointer" onClick={handleRowClick}>
                    <span className="font-mono text-xs">{log.runId}</span>
                  </TableCell>
                  <TableCell className="min-w-32" onClick={handleRowClick} hasAction>
                    <span className="font-mono text-xs">{log.taskIdentifier}</span>
                  </TableCell>
                  <TableCell onClick={handleRowClick} hasAction>
                    <LogLevel level={log.level} />
                  </TableCell>
                  <TableCell className="max-w-0 truncate" onClick={handleRowClick} hasAction>
                    <span className="block truncate font-mono text-xs" title={log.message}>
                      {highlightSearchText(log.message, searchTerm)}
                    </span>
                  </TableCell>
                  <TableCellMenu
                    className="pl-32"
                    hiddenButtons={
                      <LinkButton
                        to={runPath}
                        variant="minimal/small"
                        TrailingIcon={RunsIcon}
                        trailingIconClassName="text-text-bright"
                        className="h-5.5 pl-1.5 pr-2"
                      >
                        <span className="text-[0.6875rem] text-text-bright">View run</span>
                      </LinkButton>
                    }
                  />
                </TableRow>
              );
            })
          )}
        </TableBody>
      </Table>
      {/* Infinite scroll trigger */}
      {hasMore && logs.length > 0 && (
        <div ref={loadMoreRef} className="flex items-center justify-center py-12">
          <div className={cn("flex items-center gap-2", !showLoadMoreSpinner && "invisible")}>
            <Spinner /> <span className="text-text-dimmed">Loading more…</span>
          </div>
        </div>
      )}
      {/* Show all logs message with check for more button */}
      {!hasMore && logs.length > 0 && (
        <div className="flex items-center justify-center py-12">
          <div className="flex flex-col items-center gap-3">
            <span className="text-text-dimmed">Showing all {logs.length} logs</span>
          </div>
        </div>
      )}
    </div>
  );
}

function BlankState({ isLoading, onRefresh }: { isLoading?: boolean; onRefresh?: () => void }) {
  if (isLoading) return <TableBlankRow colSpan={6}></TableBlankRow>;

  const handleRefresh = onRefresh ?? (() => window.location.reload());

  return (
    <TableBlankRow colSpan={6}>
      <div className="flex flex-col items-center justify-center gap-6">
        <Paragraph className="w-auto" variant="base/bright">
          No logs match your filters. Try refreshing or modifying your filters.
        </Paragraph>
        <div className="flex items-center gap-2">
          <Button LeadingIcon={ArrowPathIcon} variant="tertiary/medium" onClick={handleRefresh}>
            Refresh
          </Button>
        </div>
      </div>
    </TableBlankRow>
  );
}
