import React from 'react';
import { LogProps } from './LogTypes';
import { AutoScroll } from '../AutoScroll';
import { formatUnixTimestamp } from '../../../utils/time';
import styles from './Log.module.css';

// Helper to get status badge class
const getStatusBadgeClass = (status?: string | null): string => {
  if (!status) return styles.statusBadge;
  switch (status.toLowerCase()) {
    case 'completed':
      return `${styles.statusBadge} ${styles.statusCompleted}`;
    case 'failed':
    case 'error':
      return `${styles.statusBadge} ${styles.statusFailed}`;
    case 'running':
      return `${styles.statusBadge} ${styles.statusRunning}`;
    default:
      return styles.statusBadge;
  }
};

const Log: React.FC<LogProps> = ({
  className = '',
  emptyMessage = 'No log information available',
  dashboardTree,
  onToggleOperationExpanded,
  getChildOperations
}) => {
  const formatLogTimestamp = (timestamp: number): string => {
    try {
      const formatted = formatUnixTimestamp(timestamp, undefined, {
        year: 'numeric',
        month: '2-digit',
        day: '2-digit',
        hour: '2-digit',
        minute: '2-digit',
        second: '2-digit',
        hour12: false
      });
      return formatted.time;
    } catch {
      return new Date(timestamp * 1000).toLocaleString();
    }
  };
  // Render operation node recursively
  const renderOperationNode = (operationId: string, depth: number = 0): React.ReactNode => {
    if (!dashboardTree || !getChildOperations) {
      return null;
    }

    const operation = dashboardTree.operations.get(operationId);
    if (!operation) {
      return null;
    }

    // Get logs for this operation, sorted by timestamp
    const logsArray = Array.from(operation.logs.values()).sort((a, b) => {
      const tsA = a.timestamp || 0;
      const tsB = b.timestamp || 0;
      return tsA - tsB; // Ascending order (oldest first)
    });

    // Get latest log for timestamp
    const latestLog = logsArray.length > 0 ? logsArray[logsArray.length - 1] : null;
    
    // Skip rendering if no logs yet
    if (logsArray.length === 0) {
      return null;
    }

    // Get child operations
    const childOperations = getChildOperations(operationId);
    const hasChildren = childOperations.length > 0;
    const hasLogs = logsArray.length > 0;
    const hasContentToExpand = hasChildren || hasLogs;

    // Calculate progress percentage
    let progressPercentage = 0;
    if (operation.latestProgress !== null && operation.latestProgress !== undefined) {
      progressPercentage = Math.min(Math.max(operation.latestProgress * 100, 0), 100);
    }

    // Force 100% progress when status is 'completed'
    if (operation.latestStatus === 'completed') {
      progressPercentage = 100;
    }

    // Use stable operation name (from first log) or fallback to operationId
    const operationName = operation.operationName || `Operation ${operationId}`;
    // Use latest message as status tag (updates with each poll)
    const latestMessage = operation.latestMessage || '';
    const operationStatus = operation.latestStatus || 'running';
    const operationTimestamp = latestLog?.timestamp;

    // Calculate consistent indentation per level (24px per level)
    const hasIndent = depth > 0;
    
    // Calculate log entry indentation to align with operation name
    // Operation name starts at: header padding-left (12px) + button/spacer (20px) + gap (8px) = 40px from operationContent
    // operationLogsList has margin-left: 12px (for border), so log entries are at: container marginLeft + 12px
    // We want log entries at 40px from operationContent, so: container marginLeft + 12px = 40px
    // Therefore: container marginLeft = 28px from operationContent
    // But operationNode has paddingLeft: 12px for indented nodes, 0 for root
    // So from operationNode: container marginLeft = 28px - operationNode.paddingLeft
    // Root: 28px - 0 = 28px
    // Indented: 28px - 12px = 16px
    const logIndentPx = hasIndent ? 16 : 28;
    
    // Calculate header indentation to match message indentation
    // Headers are inside operationNode which has paddingLeft: 12px (for indented)
    // Messages container has marginLeft: logIndentPx from operationNode, and list has margin-left: 12px
    // So messages start at: logIndentPx + 12px from operationNode's left edge
    // Headers start at: operationNode marginLeft + paddingLeft = headerIndentPx + 12px
    // To align: headerIndentPx + 12px = logIndentPx + 12px, so headerIndentPx = logIndentPx
    // But headers have their own padding (12px), so header content starts at headerIndentPx + 12px + 12px
    // Messages start at logIndentPx + 12px, so we need headerIndentPx = logIndentPx - 12px to align content
    // Actually, we want the header box to align with messages, so headerIndentPx should account for header padding
    const headerIndentPx = logIndentPx; // Headers and messages both use logIndentPx, paddingLeft handles alignment

    return (
      <div 
        key={operationId} 
        className={`${styles.operationNode} ${hasIndent ? styles.operationNodeIndented : ''}`}
        style={{
          marginLeft: `${headerIndentPx}px`,
          paddingLeft: hasIndent ? '12px' : '0',
          position: 'relative'
        }}
      >
        <div className={styles.operationRow}>
          {/* Operation content */}
          <div className={styles.operationContent}>
            <div className={styles.operationHeader}>
              <div className={styles.operationHeaderRow}>
                {hasContentToExpand && (
                  <button
                    className={styles.expandButton}
                    onClick={() => onToggleOperationExpanded?.(operationId)}
                    aria-label={operation.expanded ? 'Collapse' : 'Expand'}
                  >
                    <span className={`${styles.collapseIcon} ${operation.expanded ? '' : styles.collapsed}`}>
                      ▼
                    </span>
                  </button>
                )}
                {!hasContentToExpand && <span className={styles.expandButtonSpacer} />}
                
                <span className={styles.operationName}>{operationName}</span>
                
                {/* Latest status message tag (updates with each poll) */}
                {latestMessage && (
                  <span className={styles.statusMessageTag}>
                    {latestMessage}
                  </span>
                )}
                
                {operationTimestamp && (
                  <span className={styles.operationTimestamp}>
                    {formatLogTimestamp(operationTimestamp)}
                  </span>
                )}
                
                <span className={getStatusBadgeClass(operationStatus)}>
                  {operationStatus}
                </span>
                
                {progressPercentage > 0 && (
                  <span className={styles.progressPercentage}>
                    {Math.round(progressPercentage)}%
                  </span>
                )}
              </div>
              
              {progressPercentage > 0 && (
                <div className={styles.progressBarContainer}>
                  <div
                    className={`${styles.progressBar} ${progressPercentage >= 100 ? styles.progressCompleted : ''}`}
                    style={{ width: `${progressPercentage}%` }}
                  />
                </div>
              )}
            </div>
          </div>
        </div>

        {/* Show logs and children when expanded */}
        {operation.expanded && (
          <>
            {/* Log messages for this operation - show only latest log */}
            {latestLog && (
              <div 
                className={styles.operationLogsContainer}
                style={{
                  // Messages should align with header content (not header box edge)
                  // Header content starts at: operationNode paddingLeft (12px) + header padding (12px) = 24px from operationNode left
                  // Messages should start at the same position: 0 marginLeft (since operationNode already has paddingLeft)
                  marginLeft: '0px'
                }}
              >
                <div className={styles.operationLogsList}>
                  <div key={`log-${operationId}-latest`} className={styles.logEntry}>
                    <div className={styles.logEntryHeader}>
                      <span className={styles.logTimestamp}>
                        {formatLogTimestamp(latestLog.timestamp)}
                      </span>
                      <span className={styles.logEntryMessage}>
                        {latestLog.message}
                      </span>
                      {latestLog.status && (
                        <span className={getStatusBadgeClass(latestLog.status)}>
                          {latestLog.status}
                        </span>
                      )}
                      {latestLog.progress !== undefined && latestLog.progress !== null && (
                        <span className={styles.logProgress}>
                          {Math.round(latestLog.progress * 100)}%
                        </span>
                      )}
                    </div>
                  </div>
                </div>
              </div>
            )}

            {/* Child operations */}
            {hasChildren && (
              <div className={styles.operationChildren}>
                {childOperations.map((childOpId) => renderOperationNode(childOpId, depth + 1))}
              </div>
            )}
          </>
        )}
      </div>
    );
  };

  // Render dashboard tree
  const renderDashboard = (): React.ReactNode => {
    if (!dashboardTree || !getChildOperations) {
      return null;
    }

    if (dashboardTree.rootOperations.length === 0) {
      return (
        <div className={styles.emptyState}>{emptyMessage}</div>
      );
    }

    return (
      <div className={styles.dashboardContainer}>
        {dashboardTree.rootOperations.map((rootOpId) => renderOperationNode(rootOpId, 0))}
      </div>
    );
  };

  // Check if we have dashboard logs to display
  const hasDashboardLogs = dashboardTree && dashboardTree.rootOperations.length > 0;

  if (!hasDashboardLogs) {
    return (
      <div className={`${styles.logContainer} ${className}`}>
        <div className={styles.emptyState}>{emptyMessage}</div>
      </div>
    );
  }

  return (
    <div className={`${styles.logContainer} ${className}`}>
      <AutoScroll scrollDependency={dashboardTree.rootOperations.length}>
        <div className={styles.scrollableContent}>
          <div className={styles.dashboardSection}>
            {renderDashboard()}
              </div>
        </div>
      </AutoScroll>
    </div>
  );
};

export default Log;
