import { useEffect, useRef, useState, useCallback } from 'react';
import {
  connectLiveLogs,
  connectSecurityLogs,
  LiveLogEntry,
  LiveLogFilter,
  SecurityLogEntry,
  SecurityLogFilter,
} from '../api/logs';
import { Button } from './ui/Button';
import { Pause, Play, Trash2, Filter, Shield, Globe } from 'lucide-react';

/**
 * Log viewing mode: application logs vs security access logs
 */
export type LogMode = 'application' | 'security';

interface LiveLogViewerProps {
  /** Filters for application log mode */
  filters?: LiveLogFilter;
  /** Filters for security log mode */
  securityFilters?: SecurityLogFilter;
  /** Initial log viewing mode */
  mode?: LogMode;
  /** Maximum number of log entries to retain */
  maxLogs?: number;
  /** Additional CSS classes */
  className?: string;
}

/**
 * Unified display entry for both application and security logs
 */
interface DisplayLogEntry {
  timestamp: string;
  level: string;
  source: string;
  message: string;
  blocked?: boolean;
  blockReason?: string;
  clientIP?: string;
  method?: string;
  host?: string;
  uri?: string;
  status?: number;
  duration?: number;
  userAgent?: string;
  details?: Record<string, unknown>;
}

/**
 * Convert a LiveLogEntry to unified display format
 */
const toDisplayFromLive = (entry: LiveLogEntry): DisplayLogEntry => ({
  timestamp: entry.timestamp,
  level: entry.level,
  source: entry.source || 'app',
  message: entry.message,
  details: entry.data,
});

/**
 * Convert a SecurityLogEntry to unified display format
 */
const toDisplayFromSecurity = (entry: SecurityLogEntry): DisplayLogEntry => ({
  timestamp: entry.timestamp,
  level: entry.level,
  source: entry.source,
  message: entry.blocked
    ? `🚫 BLOCKED: ${entry.block_reason || 'Access denied'}`
    : `${entry.method} ${entry.uri} → ${entry.status}`,
  blocked: entry.blocked,
  blockReason: entry.block_reason,
  clientIP: entry.client_ip,
  method: entry.method,
  host: entry.host,
  uri: entry.uri,
  status: entry.status,
  duration: entry.duration,
  userAgent: entry.user_agent,
  details: entry.details,
});

/**
 * Get background/text styling based on log entry properties
 */
const getEntryStyle = (log: DisplayLogEntry): string => {
  if (log.blocked) {
    return 'bg-red-900/30 border-l-2 border-red-500';
  }
  const level = log.level.toLowerCase();
  if (level.includes('error') || level.includes('fatal')) return 'text-red-400';
  if (level.includes('warn')) return 'text-yellow-400';
  return '';
};

/**
 * Get badge color for security source
 */
const getSourceBadgeColor = (source: string): string => {
  const colors: Record<string, string> = {
    waf: 'bg-orange-600',
    crowdsec: 'bg-purple-600',
    ratelimit: 'bg-blue-600',
    acl: 'bg-green-600',
    normal: 'bg-gray-600',
    cerberus: 'bg-indigo-600',
    app: 'bg-gray-500',
  };
  return colors[source.toLowerCase()] || 'bg-gray-500';
};

/**
 * Format timestamp for display
 */
const formatTimestamp = (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' });
  } catch {
    return timestamp;
  }
};

/**
 * Get level color for application logs
 */
const getLevelColor = (level: string): string => {
  const normalized = level.toLowerCase();
  if (normalized.includes('error') || normalized.includes('fatal')) return 'text-red-400';
  if (normalized.includes('warn')) return 'text-yellow-400';
  if (normalized.includes('info')) return 'text-blue-400';
  if (normalized.includes('debug')) return 'text-gray-400';
  return 'text-gray-300';
};

// Stable default filter objects to prevent useEffect re-triggers on parent re-render
const EMPTY_LIVE_FILTER: LiveLogFilter = {};
const EMPTY_SECURITY_FILTER: SecurityLogFilter = {};

export function LiveLogViewer({
  filters = EMPTY_LIVE_FILTER,
  securityFilters = EMPTY_SECURITY_FILTER,
  mode = 'security',
  maxLogs = 500,
  className = '',
}: LiveLogViewerProps) {
  const [logs, setLogs] = useState<DisplayLogEntry[]>([]);
  const [isPaused, setIsPaused] = useState(false);
  const [isConnected, setIsConnected] = useState(false);
  const [connectionError, setConnectionError] = useState<string | null>(null);
  const [currentMode, setCurrentMode] = useState<LogMode>(mode);
  const [textFilter, setTextFilter] = useState('');
  const [levelFilter, setLevelFilter] = useState('');
  const [sourceFilter, setSourceFilter] = useState('');
  const [showBlockedOnly, setShowBlockedOnly] = useState(false);
  const logContainerRef = useRef<HTMLDivElement>(null);
  const closeConnectionRef = useRef<(() => void) | null>(null);
  const shouldAutoScroll = useRef(true);
  const isPausedRef = useRef(isPaused);

  // Keep ref in sync with state for use in WebSocket handlers
  useEffect(() => {
    isPausedRef.current = isPaused;
  }, [isPaused]);

  // Handle mode change - clear logs and update filters
  const handleModeChange = useCallback((newMode: LogMode) => {
    setCurrentMode(newMode);
    setLogs([]);
    setTextFilter('');
    setLevelFilter('');
    setSourceFilter('');
    setShowBlockedOnly(false);
  }, []);

  // Connection effect - reconnects when mode or external filters change
  useEffect(() => {
    // Close existing connection
    if (closeConnectionRef.current) {
      closeConnectionRef.current();
      closeConnectionRef.current = null;
    }

    const handleOpen = () => {
      console.log(`${currentMode} log viewer connected`);
      setIsConnected(true);
      setConnectionError(null);
    };

    const handleError = (error: Event) => {
      console.error(`${currentMode} log viewer error:`, error);
      setIsConnected(false);
      setConnectionError('Failed to connect to log stream. Check your authentication or try refreshing.');
    };

    const handleClose = () => {
      console.log(`${currentMode} log viewer disconnected`);
      setIsConnected(false);
    };

    if (currentMode === 'security') {
      // Connect to security logs endpoint
      const handleSecurityMessage = (entry: SecurityLogEntry) => {
        // Use ref to check paused state - avoids WebSocket reconnection when pausing
        if (isPausedRef.current) return;
        const displayEntry = toDisplayFromSecurity(entry);
        setLogs((prev) => {
          const updated = [...prev, displayEntry];
          return updated.length > maxLogs ? updated.slice(-maxLogs) : updated;
        });
      };

      // Build filters including blocked_only if selected
      const effectiveFilters: SecurityLogFilter = {
        ...securityFilters,
        blocked_only: showBlockedOnly || securityFilters.blocked_only,
      };

      closeConnectionRef.current = connectSecurityLogs(
        effectiveFilters,
        handleSecurityMessage,
        handleOpen,
        handleError,
        handleClose
      );
    } else {
      // Connect to application logs endpoint
      const handleLiveMessage = (entry: LiveLogEntry) => {
        // Use ref to check paused state - avoids WebSocket reconnection when pausing
        if (isPausedRef.current) return;
        const displayEntry = toDisplayFromLive(entry);
        setLogs((prev) => {
          const updated = [...prev, displayEntry];
          return updated.length > maxLogs ? updated.slice(-maxLogs) : updated;
        });
      };

      closeConnectionRef.current = connectLiveLogs(
        filters,
        handleLiveMessage,
        handleOpen,
        handleError,
        handleClose
      );
    }

    return () => {
      if (closeConnectionRef.current) {
        closeConnectionRef.current();
        closeConnectionRef.current = null;
      }
      setIsConnected(false);
    };
    // Note: isPaused is intentionally excluded - we use isPausedRef to avoid reconnecting when pausing
  }, [currentMode, filters, securityFilters, maxLogs, showBlockedOnly]);

  // Auto-scroll effect
  useEffect(() => {
    if (shouldAutoScroll.current && logContainerRef.current) {
      logContainerRef.current.scrollTop = logContainerRef.current.scrollHeight;
    }
  }, [logs]);

  // Track manual scrolling
  const handleScroll = () => {
    if (logContainerRef.current) {
      const { scrollTop, scrollHeight, clientHeight } = logContainerRef.current;
      // Enable auto-scroll if scrolled to bottom (within 50px threshold)
      shouldAutoScroll.current = scrollHeight - scrollTop - clientHeight < 50;
    }
  };

  const handleClear = () => {
    setLogs([]);
  };

  const handleTogglePause = () => {
    setIsPaused(!isPaused);
  };

  // Client-side filtering
  const filteredLogs = logs.filter((log) => {
    // Text filter - search in message, URI, host, IP
    if (textFilter) {
      const searchText = textFilter.toLowerCase();
      const matchFields = [
        log.message,
        log.uri,
        log.host,
        log.clientIP,
        log.blockReason,
      ].filter(Boolean).map(s => s!.toLowerCase());

      if (!matchFields.some(field => field.includes(searchText))) {
        return false;
      }
    }

    // Level filter
    if (levelFilter && log.level.toLowerCase() !== levelFilter.toLowerCase()) {
      return false;
    }

    // Source filter (security mode only)
    if (sourceFilter && log.source.toLowerCase() !== sourceFilter.toLowerCase()) {
      return false;
    }

    return true;
  });

  return (
    <div className={`bg-gray-900 rounded-lg border border-gray-700 ${className}`}>
      {/* Header with mode toggle and controls */}
      <div className="flex items-center justify-between p-3 border-b border-gray-700">
        <div className="flex items-center gap-2">
          <h3 className="text-sm font-semibold text-white">
            {currentMode === 'security' ? 'Security Access Logs' : 'Live Security Logs'}
          </h3>
          <span
            className={`inline-flex items-center px-2 py-0.5 rounded text-xs font-medium ${
              isConnected ? 'bg-green-900 text-green-300' : 'bg-red-900 text-red-300'
            }`}
          >
            {isConnected ? 'Connected' : 'Disconnected'}
          </span>
          {connectionError && (
            <div className="text-xs text-red-400 bg-red-900/20 px-2 py-1 rounded">
              {connectionError}
            </div>
          )}
        </div>
        <div className="flex items-center gap-2">
          {/* Mode toggle */}
          <div className="flex bg-gray-800 rounded-md p-0.5">
            <button
              onClick={() => handleModeChange('application')}
              className={`px-2 py-1 text-xs rounded flex items-center gap-1 transition-colors ${
                currentMode === 'application' ? 'bg-blue-600 text-white' : 'text-gray-400 hover:text-white'
              }`}
              title="Application logs"
            >
              <Globe className="w-4 h-4" />
              <span className="hidden sm:inline">App</span>
            </button>
            <button
              onClick={() => handleModeChange('security')}
              className={`px-2 py-1 text-xs rounded flex items-center gap-1 transition-colors ${
                currentMode === 'security' ? 'bg-blue-600 text-white' : 'text-gray-400 hover:text-white'
              }`}
              title="Security access logs"
            >
              <Shield className="w-4 h-4" />
              <span className="hidden sm:inline">Security</span>
            </button>
          </div>
          {/* Pause/Resume */}
          <Button
            variant="ghost"
            size="sm"
            onClick={handleTogglePause}
            className="flex items-center gap-1"
            title={isPaused ? 'Resume' : 'Pause'}
          >
            {isPaused ? <Play className="w-4 h-4" /> : <Pause className="w-4 h-4" />}
          </Button>
          {/* Clear */}
          <Button
            variant="ghost"
            size="sm"
            onClick={handleClear}
            className="flex items-center gap-1"
            title="Clear logs"
          >
            <Trash2 className="w-4 h-4" />
          </Button>
        </div>
      </div>

      {/* Filters */}
      <div className="flex flex-wrap items-center gap-2 p-2 border-b border-gray-700 bg-gray-800">
        <Filter className="w-4 h-4 text-gray-400" />
        <input
          type="text"
          placeholder="Filter by text..."
          value={textFilter}
          onChange={(e) => setTextFilter(e.target.value)}
          className="flex-1 min-w-32 px-2 py-1 text-sm bg-gray-700 border border-gray-600 rounded text-white placeholder-gray-400 focus:outline-none focus:border-blue-500"
        />
        <select
          value={levelFilter}
          onChange={(e) => setLevelFilter(e.target.value)}
          className="px-2 py-1 text-sm bg-gray-700 border border-gray-600 rounded text-white focus:outline-none focus:border-blue-500"
        >
          <option value="">All Levels</option>
          <option value="debug">Debug</option>
          <option value="info">Info</option>
          <option value="warn">Warning</option>
          <option value="error">Error</option>
          <option value="fatal">Fatal</option>
        </select>
        {/* Security mode specific filters */}
        {currentMode === 'security' && (
          <>
            <select
              value={sourceFilter}
              onChange={(e) => setSourceFilter(e.target.value)}
              className="px-2 py-1 text-sm bg-gray-700 border border-gray-600 rounded text-white focus:outline-none focus:border-blue-500"
            >
              <option value="">All Sources</option>
              <option value="waf">WAF</option>
              <option value="crowdsec">CrowdSec</option>
              <option value="ratelimit">Rate Limit</option>
              <option value="acl">ACL</option>
              <option value="normal">Normal</option>
            </select>
            <label className="flex items-center gap-1 text-xs text-gray-400 cursor-pointer">
              <input
                type="checkbox"
                checked={showBlockedOnly}
                onChange={(e) => setShowBlockedOnly(e.target.checked)}
                className="rounded border-gray-600 bg-gray-700 text-blue-500 focus:ring-blue-500"
              />
              Blocked only
            </label>
          </>
        )}
      </div>

      {/* Log display */}
      <div
        ref={logContainerRef}
        onScroll={handleScroll}
        className="h-96 overflow-y-auto p-3 font-mono text-xs bg-black"
        style={{ scrollBehavior: 'smooth' }}
      >
        {filteredLogs.length === 0 && (
          <div className="text-gray-500 text-center py-8">
            {logs.length === 0 ? 'No logs yet. Waiting for events...' : 'No logs match the current filters.'}
          </div>
        )}
        {filteredLogs.map((log, index) => (
          <div
            key={index}
            className={`mb-1 hover:bg-gray-900 px-1 -mx-1 rounded ${getEntryStyle(log)}`}
          >
            <span className="text-gray-500">{formatTimestamp(log.timestamp)}</span>

            {/* Source badge for security mode */}
            {currentMode === 'security' && (
              <span className={`ml-2 px-1 rounded text-xs text-white ${getSourceBadgeColor(log.source)}`}>
                {log.source.toUpperCase()}
              </span>
            )}

            {/* Level badge for application mode */}
            {currentMode === 'application' && (
              <span className={`ml-2 font-semibold ${getLevelColor(log.level)}`}>
                {log.level.toUpperCase()}
              </span>
            )}

            {/* Client IP for security logs */}
            {currentMode === 'security' && log.clientIP && (
              <span className="ml-2 text-cyan-400">{log.clientIP}</span>
            )}

            {/* Source tag for application logs */}
            {currentMode === 'application' && log.source && log.source !== 'app' && (
              <span className="ml-2 text-purple-400">[{log.source}]</span>
            )}

            {/* Message */}
            <span className="ml-2 text-gray-200">{log.message}</span>

            {/* Block reason badge */}
            {log.blocked && log.blockReason && (
              <span className="ml-2 text-red-400 text-xs">[{log.blockReason}]</span>
            )}

            {/* Status code for security logs */}
            {currentMode === 'security' && log.status && !log.blocked && (
              <span className={`ml-2 ${log.status >= 400 ? 'text-red-400' : log.status >= 300 ? 'text-yellow-400' : 'text-green-400'}`}>
                [{log.status}]
              </span>
            )}

            {/* Duration for security logs */}
            {currentMode === 'security' && log.duration !== undefined && (
              <span className="ml-1 text-gray-500">
                {log.duration < 1 ? `${(log.duration * 1000).toFixed(1)}ms` : `${log.duration.toFixed(2)}s`}
              </span>
            )}

            {/* Additional data */}
            {log.details && Object.keys(log.details).length > 0 && (
              <div className="ml-8 text-gray-400 text-xs">
                {JSON.stringify(log.details, null, 2)}
              </div>
            )}
          </div>
        ))}
      </div>

      {/* Footer with log count */}
      <div className="p-2 border-t border-gray-700 bg-gray-800 text-xs text-gray-400 flex items-center justify-between">
        <span>
          Showing {filteredLogs.length} of {logs.length} logs
        </span>
        {isPaused && <span className="text-yellow-400">⏸ Paused</span>}
      </div>
    </div>
  );
}
