'use client';

import { useState, useMemo, useRef, useEffect, useCallback, CSSProperties } from 'react';
import { List, ListImperativeAPI } from 'react-window';
import { Search, ArrowDown, Clock, Bug } from 'lucide-react';
import { StructuredLog } from './index';

// Types
export interface LogViewerFilter {
  category: 'all' | 'scraper' | 'browser' | 'network' | 'system';
  levels: Set<string>;
  searchQuery: string;
}

export interface LogViewerProps {
  logs: StructuredLog[];
  filter: LogViewerFilter;
  onLogSelect?: (log: StructuredLog, index: number) => void;
  selectedIndices?: Set<number>;
}

type LogLevel = 'DEBUG' | 'INFO' | 'WARN' | 'ERROR' | 'FATAL';
type LogCategory = 'scraper' | 'browser' | 'network' | 'system';

// Styling constants - matching the dark theme from index.tsx
const LEVEL_BADGE_COLORS: Record<LogLevel, string> = {
  DEBUG: 'bg-gray-600 text-gray-200',
  INFO: 'bg-blue-600 text-blue-100',
  WARN: 'bg-yellow-600 text-yellow-100',
  ERROR: 'bg-red-600 text-red-100',
  FATAL: 'bg-purple-600 text-purple-100',
};

const CATEGORY_BADGE_COLORS: Record<LogCategory, string> = {
  scraper: 'bg-green-700 text-green-200',
  browser: 'bg-orange-700 text-orange-200',
  network: 'bg-cyan-700 text-cyan-200',
  system: 'bg-gray-600 text-gray-200',
};

const LEVEL_ROW_COLORS: Record<LogLevel, string> = {
  DEBUG: 'text-gray-300',
  INFO: 'text-blue-300',
  WARN: 'text-yellow-300',
  ERROR: 'text-red-300',
  FATAL: 'text-purple-300',
};

// Row height for virtualization
const ROW_HEIGHT = 36;

/**
 * Formats a timestamp as absolute time (HH:MM:SS.mmm)
 */
function formatAbsoluteTime(timestamp: string): string {
  try {
    const date = new Date(timestamp);
    return date.toLocaleTimeString('en-US', {
      hour12: false,
      hour: '2-digit',
      minute: '2-digit',
      second: '2-digit',
      fractionalSecondDigits: 3,
    });
  } catch {
    return timestamp;
  }
}

/**
 * Formats a timestamp as relative time (e.g., "2s ago", "1m ago")
 */
function formatRelativeTime(timestampMs: number, nowMs: number): string {
  const diffMs = nowMs - timestampMs;
  const diffSeconds = Math.floor(diffMs / 1000);

  if (diffSeconds < 0) {
    return 'just now';
  }

  if (diffSeconds < 60) {
    return `${diffSeconds}s ago`;
  }

  const diffMinutes = Math.floor(diffSeconds / 60);
  if (diffMinutes < 60) {
    return `${diffMinutes}m ago`;
  }

  const diffHours = Math.floor(diffMinutes / 60);
  if (diffHours < 24) {
    return `${diffHours}h ago`;
  }

  const diffDays = Math.floor(diffHours / 24);
  return `${diffDays}d ago`;
}

/**
 * Highlights matching text in a string
 */
function HighlightedText({ text, query }: { text: string; query: string }) {
  if (!query.trim()) {
    return <>{text}</>;
  }

  const regex = new RegExp(`(${query.replace(/[.*+?^${}()|[\]\\]/g, '\\$&')})`, 'gi');
  const parts = text.split(regex);

  return (
    <>
      {parts.map((part, index) => {
        const isMatch = part.toLowerCase() === query.toLowerCase();
        return isMatch ? (
          <mark
            key={index}
            className="bg-yellow-500/40 text-yellow-100 rounded px-0.5"
          >
            {part}
          </mark>
        ) : (
          <span key={index}>{part}</span>
        );
      })}
    </>
  );
}

/**
 * Individual log row component for virtualized list
 */
interface LogRowInnerProps {
  log: StructuredLog;
  originalIndex: number;
  isSelected: boolean;
  isEven: boolean;
  timestampFormat: 'relative' | 'absolute';
  nowMs: number;
  searchQuery: string;
  onClick: (e: React.MouseEvent) => void;
}

function LogRowInner({
  log,
  isSelected,
  isEven,
  timestampFormat,
  nowMs,
  searchQuery,
  onClick,
}: LogRowInnerProps) {
  const timestamp =
    timestampFormat === 'absolute'
      ? formatAbsoluteTime(log.timestamp)
      : formatRelativeTime(log.timestamp_ms, nowMs);

  const levelBadgeClass = LEVEL_BADGE_COLORS[log.level] || LEVEL_BADGE_COLORS.INFO;
  const categoryBadgeClass = CATEGORY_BADGE_COLORS[log.category] || CATEGORY_BADGE_COLORS.system;
  const messageColor = LEVEL_ROW_COLORS[log.level] || LEVEL_ROW_COLORS.INFO;

  const rowBgClass = isSelected
    ? 'bg-blue-900/50 border-l-2 border-blue-500'
    : isEven
    ? 'bg-gray-900/30'
    : 'bg-gray-800/30';

  return (
    <div
      className={`flex items-center gap-2 px-3 h-full cursor-pointer hover:bg-gray-700/50 transition-colors ${rowBgClass}`}
      onClick={onClick}
    >
      {/* Timestamp */}
      <span className="text-gray-500 text-xs font-mono whitespace-nowrap w-[80px] flex-shrink-0">
        {timestamp}
      </span>

      {/* Level badge */}
      <span
        className={`px-1.5 py-0.5 text-xs font-semibold rounded ${levelBadgeClass} whitespace-nowrap flex-shrink-0 w-[50px] text-center`}
      >
        {log.level}
      </span>

      {/* Category badge */}
      <span
        className={`px-1.5 py-0.5 text-xs font-medium rounded ${categoryBadgeClass} whitespace-nowrap flex-shrink-0 w-[60px] text-center`}
      >
        {log.category}
      </span>

      {/* Message */}
      <span
        className={`flex-1 font-mono text-sm truncate ${messageColor}`}
        title={log.message}
      >
        <HighlightedText text={log.message} query={searchQuery} />
      </span>
    </div>
  );
}

// Type for row data passed via rowProps (merged with component props)
interface LogRowProps {
  filteredLogs: Array<{ log: StructuredLog; originalIndex: number }>;
  selectedIndices: Set<number>;
  timestampFormat: 'relative' | 'absolute';
  nowMs: number;
  searchQuery: string;
  handleLogClick: (
    e: React.MouseEvent,
    filteredIndex: number,
    originalIndex: number,
    log: StructuredLog
  ) => void;
}

// Row component for react-window v2 - receives index, style, ariaAttributes + rowProps
function LogRow({
  index,
  style,
  filteredLogs,
  selectedIndices,
  timestampFormat,
  nowMs,
  searchQuery,
  handleLogClick,
}: LogRowProps & {
  index: number;
  style: CSSProperties;
  ariaAttributes: {
    'aria-posinset': number;
    'aria-setsize': number;
    role: 'listitem';
  };
}) {
  const item = filteredLogs[index];
  if (!item) return null;

  const { log, originalIndex } = item;
  const isSelected = selectedIndices.has(originalIndex);

  return (
    <div style={style}>
      <LogRowInner
        log={log}
        originalIndex={originalIndex}
        isSelected={isSelected}
        isEven={index % 2 === 0}
        timestampFormat={timestampFormat}
        nowMs={nowMs}
        searchQuery={searchQuery}
        onClick={(e) => handleLogClick(e, index, originalIndex, log)}
      />
    </div>
  );
}

/**
 * LogViewer - A virtualized log viewer component using react-window
 *
 * Features:
 * - Virtualized list for performance with large log sets
 * - Search filtering with highlighted matches
 * - Auto-scroll toggle for following new logs
 * - Timestamp format toggle (relative vs absolute)
 * - Click to select, shift+click for range selection
 */
export default function LogViewer({
  logs,
  filter,
  onLogSelect,
  selectedIndices = new Set(),
}: LogViewerProps) {
  const [autoScroll, setAutoScroll] = useState(true);
  const [timestampFormat, setTimestampFormat] = useState<'relative' | 'absolute'>('absolute');
  const [localSearchQuery, setLocalSearchQuery] = useState(filter.searchQuery);
  const [nowMs, setNowMs] = useState(Date.now());
  const [lastSelectedIndex, setLastSelectedIndex] = useState<number | null>(null);

  const listRef = useRef<ListImperativeAPI>(null);
  const containerRef = useRef<HTMLDivElement>(null);

  // Update "now" for relative timestamps every second
  useEffect(() => {
    if (timestampFormat === 'relative') {
      const interval = setInterval(() => setNowMs(Date.now()), 1000);
      return () => clearInterval(interval);
    }
  }, [timestampFormat]);

  // Filter logs based on category, levels, and search query
  const filteredLogs = useMemo(() => {
    const searchLower = localSearchQuery.toLowerCase();

    return logs
      .map((log, originalIndex) => ({ log, originalIndex }))
      .filter(({ log }) => {
        // Category filter
        if (filter.category !== 'all' && log.category !== filter.category) {
          return false;
        }

        // Level filter
        if (!filter.levels.has(log.level)) {
          return false;
        }

        // Search filter
        if (searchLower && !log.message.toLowerCase().includes(searchLower)) {
          return false;
        }

        return true;
      });
  }, [logs, filter.category, filter.levels, localSearchQuery]);

  // Auto-scroll to bottom when new logs arrive
  useEffect(() => {
    if (autoScroll && listRef.current && filteredLogs.length > 0) {
      listRef.current.scrollToRow({ index: filteredLogs.length - 1, align: 'end' });
    }
  }, [filteredLogs.length, autoScroll, listRef]);

  // Handle log selection with shift+click support
  const handleLogClick = useCallback(
    (e: React.MouseEvent, filteredIndex: number, originalIndex: number, log: StructuredLog) => {
      if (e.shiftKey && lastSelectedIndex !== null && onLogSelect) {
        // Range selection
        const start = Math.min(lastSelectedIndex, filteredIndex);
        const end = Math.max(lastSelectedIndex, filteredIndex);

        for (let i = start; i <= end; i++) {
          const item = filteredLogs[i];
          if (item) {
            onLogSelect(item.log, item.originalIndex);
          }
        }
      } else {
        // Single selection
        onLogSelect?.(log, originalIndex);
        setLastSelectedIndex(filteredIndex);
      }
    },
    [lastSelectedIndex, onLogSelect, filteredLogs]
  );

  // Row data passed via rowProps
  const rowData: LogRowProps = useMemo(
    () => ({
      filteredLogs,
      selectedIndices,
      timestampFormat,
      nowMs,
      searchQuery: localSearchQuery,
      handleLogClick,
    }),
    [filteredLogs, selectedIndices, timestampFormat, nowMs, localSearchQuery, handleLogClick]
  );

  // Handle scroll for auto-scroll detection
  const handleScrollToBottom = useCallback(() => {
    if (listRef.current && filteredLogs.length > 0) {
      listRef.current.scrollToRow({ index: filteredLogs.length - 1, align: 'end' });
    }
  }, [listRef, filteredLogs.length]);

  return (
    <div className="flex flex-col h-full bg-gray-900 rounded-lg border border-gray-700 overflow-hidden">
      {/* Toolbar */}
      <div className="flex items-center gap-3 px-3 py-2 bg-gray-800 border-b border-gray-700">
        {/* Search input */}
        <div className="relative flex-1 max-w-md">
          <Search className="absolute left-2.5 top-1/2 -translate-y-1/2 w-4 h-4 text-gray-500" />
          <input
            type="text"
            placeholder="Search logs..."
            value={localSearchQuery}
            onChange={(e) => setLocalSearchQuery(e.target.value)}
            className="w-full pl-9 pr-3 py-1.5 bg-gray-700 border border-gray-600 rounded-md text-sm text-gray-200 placeholder-gray-500 focus:outline-none focus:border-blue-500 focus:ring-1 focus:ring-blue-500"
          />
        </div>

        {/* Log count */}
        <span className="text-sm text-gray-400 whitespace-nowrap">
          {filteredLogs.length} of {logs.length} logs
        </span>

        {/* Timestamp format toggle */}
        <button
          onClick={() => setTimestampFormat((prev) => (prev === 'absolute' ? 'relative' : 'absolute'))}
          className={`flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium rounded-md transition-colors ${
            timestampFormat === 'relative'
              ? 'bg-blue-600 text-blue-100'
              : 'bg-gray-700 text-gray-300 hover:bg-gray-600'
          }`}
          title={`Show ${timestampFormat === 'absolute' ? 'relative' : 'absolute'} time`}
        >
          <Clock className="w-3.5 h-3.5" />
          {timestampFormat === 'absolute' ? 'Absolute' : 'Relative'}
        </button>

        {/* Auto-scroll toggle */}
        <button
          onClick={() => {
            const newAutoScroll = !autoScroll;
            setAutoScroll(newAutoScroll);
            if (newAutoScroll) {
              handleScrollToBottom();
            }
          }}
          className={`flex items-center gap-1.5 px-2.5 py-1.5 text-xs font-medium rounded-md transition-colors ${
            autoScroll
              ? 'bg-green-600 text-green-100'
              : 'bg-gray-700 text-gray-300 hover:bg-gray-600'
          }`}
          title={autoScroll ? 'Auto-scroll enabled' : 'Auto-scroll disabled'}
        >
          <ArrowDown className="w-3.5 h-3.5" />
          Auto-scroll
        </button>
      </div>

      {/* Virtualized log list */}
      <div ref={containerRef} className="flex-1 min-h-[200px]" style={{ height: 300 }}>
        {filteredLogs.length === 0 ? (
          <div className="flex items-center justify-center h-full text-gray-500">
            <div className="text-center">
              <Bug className="w-8 h-8 mx-auto mb-2 opacity-50" />
              <p>No logs match your filters</p>
              {localSearchQuery && (
                <p className="text-xs mt-1">
                  Try adjusting your search query
                </p>
              )}
            </div>
          </div>
        ) : (
          <List
            listRef={listRef}
            defaultHeight={300}
            rowCount={filteredLogs.length}
            rowHeight={ROW_HEIGHT}
            rowComponent={LogRow}
            rowProps={rowData}
            className="scrollbar-thin scrollbar-thumb-gray-600 scrollbar-track-gray-800"
          />
        )}
      </div>

      {/* Footer with selection info */}
      {selectedIndices.size > 0 && (
        <div className="px-3 py-2 bg-gray-800 border-t border-gray-700 text-xs text-gray-400">
          {selectedIndices.size} log{selectedIndices.size !== 1 ? 's' : ''} selected
          <span className="ml-2 text-gray-500">
            (Shift+click to select range)
          </span>
        </div>
      )}
    </div>
  );
}

// Export types for external use
export type { LogLevel, LogCategory };
