import React, { useState, useEffect, useRef } from 'react';
import {
  Paper,
  Button,
  Group,
  Stack,
  Text,
  Textarea,
  Switch,
  Alert,
  Badge,
  Divider,
  JsonInput,
  Loader,
  ActionIcon,
  Tooltip,
  Title,
  ScrollArea,
  Box,
} from '@mantine/core';
import { IconPlayerPlay, IconPlayerStop, IconRefresh, IconCopy, IconX } from '@tabler/icons-react';
import { notifications } from '@mantine/notifications';
import { functionApi, executionApi } from '../services/apiService';
import { FunctionDefinition, ExecuteFunctionResponse, FunctionExecution } from '../types';

interface ExecutionSidebarProps {
  opened: boolean;
  onClose: () => void;
  function: FunctionDefinition | null;
}

export const ExecutionSidebar: React.FC<ExecutionSidebarProps> = ({
  opened,
  onClose,
  function: func,
}) => {
  const [input, setInput] = useState('{}');
  const [async, setAsync] = useState(false);
  const [executing, setExecuting] = useState(false);
  const [result, setResult] = useState<ExecuteFunctionResponse | null>(null);
  const [execution, setExecution] = useState<FunctionExecution | null>(null);
  const [logs, setLogs] = useState<string[]>([]);
  const [loadingLogs, setLoadingLogs] = useState(false);
  const [autoRefreshLogs, setAutoRefreshLogs] = useState(false);
  const pollIntervalRef = useRef<NodeJS.Timeout | null>(null);
  const logsPollIntervalRef = useRef<NodeJS.Timeout | null>(null);

  const stopLogsAutoRefresh = () => {
    if (logsPollIntervalRef.current) {
      clearInterval(logsPollIntervalRef.current);
      logsPollIntervalRef.current = null;
    }
    setAutoRefreshLogs(false);
  };

  // Cleanup intervals on unmount or when sidebar closes
  useEffect(() => {
    if (!opened) {
      // Stop auto-refresh when sidebar closes
      stopLogsAutoRefresh();
      if (pollIntervalRef.current) {
        clearTimeout(pollIntervalRef.current);
      }
    }
  }, [opened]);

  // Cleanup intervals on unmount
  useEffect(() => {
    return () => {
      if (pollIntervalRef.current) {
        clearTimeout(pollIntervalRef.current);
      }
      if (logsPollIntervalRef.current) {
        clearInterval(logsPollIntervalRef.current);
      }
    };
  }, []);

  if (!func) return null;

  const handleExecute = async () => {
    try {
      setExecuting(true);
      setResult(null);
      setExecution(null);
      setLogs([]);

      let parsedInput;
      try {
        parsedInput = input.trim() ? JSON.parse(input) : undefined;
      } catch (e) {
        notifications.show({
          title: 'Error',
          message: 'Invalid JSON input',
          color: 'red',
        });
        return;
      }

      const response = await functionApi.execute(func.id, {
        input: parsedInput,
        async,
      });

      setResult(response.data);

      if (async) {
        // Poll for execution status and start auto-refreshing logs
        pollExecution(response.data.execution_id);
      } else {
        // For synchronous executions, load logs immediately
        if (response.data.execution_id) {
          loadLogs(response.data.execution_id);
        }
      }

      notifications.show({
        title: 'Success',
        message: `Function ${async ? 'invoked' : 'executed'} successfully`,
        color: 'green',
      });
    } catch (error) {
      console.error('Execution error:', error);
      notifications.show({
        title: 'Error',
        message: 'Failed to execute function',
        color: 'red',
      });
    } finally {
      setExecuting(false);
    }
  };

  const pollExecution = async (executionId: string) => {
    // Start auto-refreshing logs immediately for async executions
    startLogsAutoRefresh(executionId);

    const poll = async () => {
      try {
        const response = await executionApi.getById(executionId);
        setExecution(response.data);

        if (response.data.status === 'running' || response.data.status === 'pending') {
          pollIntervalRef.current = setTimeout(poll, 2000); // Poll every 2 seconds
        } else {
          // Execution completed, stop auto-refresh and load final logs
          stopLogsAutoRefresh();
          loadLogs(executionId);
        }
      } catch (error) {
        console.error('Error polling execution:', error);
        stopLogsAutoRefresh();
      }
    };

    poll();
  };

  const loadLogs = async (executionId: string) => {
    try {
      console.debug(`[ExecutionSidebar] Loading logs for execution ${executionId}`);
      setLoadingLogs(true);
      const response = await executionApi.getLogs(executionId);
      console.debug(`[ExecutionSidebar] Loaded logs for execution ${executionId}:`, {
        logCount: response.data.logs?.length || 0,
        logs: response.data.logs
      });
      setLogs(response.data.logs || []);
    } catch (error) {
      console.error(`[ExecutionSidebar] Error loading logs for execution ${executionId}:`, error);
    } finally {
      setLoadingLogs(false);
    }
  };

  const startLogsAutoRefresh = (executionId: string) => {
    console.debug(`[ExecutionSidebar] Starting auto-refresh for execution ${executionId}`);
    
    // Clear any existing interval
    if (logsPollIntervalRef.current) {
      clearInterval(logsPollIntervalRef.current);
    }

    setAutoRefreshLogs(true);
    
    // Load logs immediately
    loadLogs(executionId);
    
    // Set up auto-refresh every 2 seconds
    logsPollIntervalRef.current = setInterval(async () => {
      try {
        console.debug(`[ExecutionSidebar] Auto-refreshing logs for execution ${executionId}`);
        const response = await executionApi.getLogs(executionId);
        console.debug(`[ExecutionSidebar] Auto-refresh got logs for execution ${executionId}:`, {
          logCount: response.data.logs?.length || 0,
          logs: response.data.logs
        });
        setLogs(response.data.logs || []);
      } catch (error) {
        console.error(`[ExecutionSidebar] Error auto-refreshing logs for execution ${executionId}:`, error);
      }
    }, 2000);
  };

  const handleCancel = async () => {
    if (result && async) {
      try {
        await executionApi.cancel(result.execution_id);
        notifications.show({
          title: 'Success',
          message: 'Execution canceled',
          color: 'orange',
        });
        // Refresh execution status
        if (result.execution_id) {
          const response = await executionApi.getById(result.execution_id);
          setExecution(response.data);
        }
      } catch (error) {
        notifications.show({
          title: 'Error',
          message: 'Failed to cancel execution',
          color: 'red',
        });
      }
    }
  };

  const getStatusColor = (status: string) => {
    switch (status) {
      case 'completed': return 'green';
      case 'failed': return 'red';
      case 'running': return 'blue';
      case 'pending': return 'yellow';
      case 'canceled': return 'orange';
      case 'timeout': return 'red';
      default: return 'gray';
    }
  };

  const copyToClipboard = (text: string) => {
    navigator.clipboard.writeText(text);
    notifications.show({
      title: 'Copied',
      message: 'Copied to clipboard',
      color: 'green',
    });
  };

  return (
    <Paper
      style={{
        position: 'fixed',
        top: 60, // Below header
        right: opened ? 0 : '-600px',
        bottom: 0,
        width: '600px',
        zIndex: 1000,
        borderRadius: 0,
        display: 'flex',
        flexDirection: 'column',
        borderLeft: '1px solid var(--mantine-color-gray-3)',
        backgroundColor: 'var(--mantine-color-body)',
        transition: 'right 0.3s ease',
      }}
    >
      {/* Header */}
      <Group justify="space-between" p="md" style={{ borderBottom: '1px solid var(--mantine-color-gray-3)' }}>
        <Title order={4}>
          Execute Function: {func.name}
        </Title>
        <ActionIcon
          variant="subtle"
          color="gray"
          onClick={onClose}
        >
          <IconX size={18} />
        </ActionIcon>
      </Group>

      {/* Content */}
      <ScrollArea style={{ flex: 1 }}>
        <Box p="md">
          <Stack gap="md">
            {/* Function Info */}
            <Paper withBorder p="sm" bg="gray.0">
              <Group justify="space-between">
                <div>
                  <Text size="sm" fw={500}>{func.name}</Text>
                  <Text size="xs" c="dimmed">{func.runtime} • {func.memory}MB • {func.timeout}</Text>
                </div>
                <Badge variant="light">
                  {func.runtime}
                </Badge>
              </Group>
            </Paper>

            {/* Input */}
            <JsonInput
              label="Function Input (JSON)"
              placeholder='{"key": "value"}'
              value={input}
              onChange={setInput}
              minRows={4}
              maxRows={8}
              validationError="Invalid JSON"
            />

            {/* Execution Options */}
            <Group justify="space-between">
              <Switch
                label="Asynchronous execution"
                description="Execute in background"
                checked={async}
                onChange={(event) => setAsync(event.currentTarget.checked)}
              />
              <Group>
                <Button
                  leftSection={<IconPlayerPlay size={16} />}
                  onClick={handleExecute}
                  loading={executing}
                  disabled={executing}
                >
                  {async ? 'Invoke' : 'Execute'}
                </Button>
                {result && async && execution?.status === 'running' && (
                  <Button
                    leftSection={<IconPlayerStop size={16} />}
                    color="orange"
                    variant="light"
                    onClick={handleCancel}
                  >
                    Cancel
                  </Button>
                )}
              </Group>
            </Group>

            {/* Results */}
            {result && (
              <>
                <Divider label="Execution Result" labelPosition="center" />
                
                <Paper withBorder p="md">
                  <Group justify="space-between" mb="sm">
                    <Text fw={500}>Execution #{result.execution_id.slice(0, 8)}...</Text>
                    <Group gap="xs">
                      <Badge color={getStatusColor(execution?.status || result.status)}>
                        {execution?.status || result.status}
                      </Badge>
                      {result.duration && (
                        <Badge variant="light">
                          {result.duration}ms
                        </Badge>
                      )}
                      {result.memory_used && (
                        <Badge variant="light">
                          {result.memory_used}MB
                        </Badge>
                      )}
                    </Group>
                  </Group>

                  {/* Output */}
                  {(result.output || execution?.output) && (
                    <div>
                      <Group justify="space-between" mb="xs">
                        <Text size="sm" fw={500}>Output:</Text>
                        <Tooltip label="Copy output">
                          <ActionIcon
                            variant="light"
                            size="sm"
                            onClick={() => copyToClipboard(JSON.stringify(result.output || execution?.output, null, 2))}
                          >
                            <IconCopy size={14} />
                          </ActionIcon>
                        </Tooltip>
                      </Group>
                      <Paper bg="gray.1" p="sm">
                        <Text size="sm" component="pre" style={{ whiteSpace: 'pre-wrap' }}>
                          {JSON.stringify(result.output || execution?.output, null, 2)}
                        </Text>
                      </Paper>
                    </div>
                  )}

                  {/* Error */}
                  {(result.error || execution?.error) && (
                    <Alert color="red" mt="sm">
                      <Text size="sm">{result.error || execution?.error}</Text>
                    </Alert>
                  )}

                  {/* Logs */}
                  <div style={{ marginTop: '1rem' }}>
                    <Group justify="space-between" mb="xs">
                      <Group gap="xs">
                        <Text size="sm" fw={500}>Logs:</Text>
                        {autoRefreshLogs && (
                          <Badge size="xs" color="blue" variant="light">
                            Auto-refreshing
                          </Badge>
                        )}
                      </Group>
                      <Group gap="xs">
                        {result.execution_id && (
                          <Button
                            size="xs"
                            variant={autoRefreshLogs ? "filled" : "light"}
                            color={autoRefreshLogs ? "red" : "blue"}
                            leftSection={<IconRefresh size={12} />}
                            onClick={() => {
                              if (autoRefreshLogs) {
                                stopLogsAutoRefresh();
                              } else {
                                startLogsAutoRefresh(result.execution_id);
                              }
                            }}
                          >
                            {autoRefreshLogs ? 'Stop Auto-refresh' : 'Auto-refresh'}
                          </Button>
                        )}
                        <Button
                          size="xs"
                          variant="light"
                          leftSection={<IconRefresh size={12} />}
                          onClick={() => result.execution_id && loadLogs(result.execution_id)}
                          loading={loadingLogs}
                          disabled={autoRefreshLogs}
                        >
                          Manual Refresh
                        </Button>
                      </Group>
                    </Group>
                    <Paper bg="gray.9" p="sm" mah={200} style={{ overflow: 'auto' }}>
                      {loadingLogs ? (
                        <Group justify="center">
                          <Loader size="sm" />
                        </Group>
                      ) : (logs.length > 0 || (execution?.logs && execution.logs.length > 0)) ? (
                        <Text size="xs" c="white" component="pre">
                          {(execution?.logs || logs).join('\n')}
                        </Text>
                      ) : (
                        <Text size="xs" c="gray.5">No logs available</Text>
                      )}
                    </Paper>
                  </div>
                </Paper>
              </>
            )}
          </Stack>
        </Box>
      </ScrollArea>
    </Paper>
  );
};