import 'package:flutter/material.dart';
import 'oto_console_contract.dart';

class OtoExecutionsSurface extends StatelessWidget {
  final OtoSurfaceSnapshot<List<OtoExecutionViewModel>> snapshot;
  final String? expandedExecutionID;
  final Map<String, OtoActionViewState>? actionStates;
  final OtoSurfaceSnapshot<List<OtoLogEntryViewModel>>? logsSnapshot;
  final OtoSurfaceSnapshot<List<OtoArtifactViewModel>>? artifactsSnapshot;
  final ValueChanged<String?>? onExpandExecution;
  final VoidCallback? onViewArtifactsSection;
  final ValueChanged<OtoExecutionCancelDraft>? onCancelExecution;
  final ValueChanged<OtoExecutionReportDraft>? onReportExecution;
  final ValueChanged<OtoExecutionLogDraft>? onAppendLog;
  final ValueChanged<OtoExecutionArtifactDraft>? onAppendArtifact;
  final OtoConsoleThemeAdapter? themeAdapter;

  const OtoExecutionsSurface({
    super.key,
    required this.snapshot,
    this.expandedExecutionID,
    this.actionStates,
    this.logsSnapshot,
    this.artifactsSnapshot,
    this.onExpandExecution,
    this.onViewArtifactsSection,
    this.onCancelExecution,
    this.onReportExecution,
    this.onAppendLog,
    this.onAppendArtifact,
    this.themeAdapter,
  });

  @override
  Widget build(BuildContext context) {
    final theme = themeAdapter ?? const OtoConsoleThemeAdapter();
    return Container(
      color: theme.backgroundColor,
      padding: const EdgeInsets.all(24),
      child: Center(
        child: ConstrainedBox(
          constraints: const BoxConstraints(maxWidth: 820),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Row(
                children: [
                  Icon(
                    Icons.play_circle_outline,
                    color: theme.primaryColor,
                    size: 24,
                  ),
                  const SizedBox(width: 12),
                  Expanded(
                    child: Text(
                      'Executions',
                      style: TextStyle(
                        color: theme.textColor,
                        fontSize: 24,
                        fontWeight: FontWeight.w800,
                      ),
                    ),
                  ),
                ],
              ),
              const SizedBox(height: 20),
              Expanded(child: _buildContent(context, theme)),
            ],
          ),
        ),
      ),
    );
  }

  Widget _buildContent(BuildContext context, OtoConsoleThemeAdapter theme) {
    switch (snapshot.state) {
      case OtoSurfaceLoadState.loading:
        return const Center(child: CircularProgressIndicator());
      case OtoSurfaceLoadState.empty:
        return _buildEmptyState(theme);
      case OtoSurfaceLoadState.error:
        return _buildErrorState(theme);
      case OtoSurfaceLoadState.data:
        final executions = snapshot.data ?? [];
        if (executions.isEmpty) {
          return _buildEmptyState(theme);
        }
        return _buildExecutionsList(context, theme, executions);
    }
  }

  Widget _buildEmptyState(OtoConsoleThemeAdapter theme) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Container(
          padding: const EdgeInsets.all(20),
          decoration: BoxDecoration(
            color: theme.railBackgroundColor,
            borderRadius: BorderRadius.circular(8),
            border: Border.all(color: theme.borderColor),
          ),
          child: Row(
            children: [
              Icon(
                Icons.play_circle_outline,
                color: theme.primaryColor,
                size: 32,
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'No executions',
                      style: TextStyle(
                        color: theme.textColor,
                        fontSize: 18,
                        fontWeight: FontWeight.w800,
                      ),
                    ),
                    const SizedBox(height: 4),
                    Text(
                      'Execution history is empty.',
                      style: TextStyle(color: theme.textSecondaryColor),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }

  Widget _buildErrorState(OtoConsoleThemeAdapter theme) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Container(
          padding: const EdgeInsets.all(20),
          decoration: BoxDecoration(
            color: Colors.red.withValues(alpha: 0.1),
            borderRadius: BorderRadius.circular(8),
            border: Border.all(color: Colors.red.withValues(alpha: 0.5)),
          ),
          child: Row(
            children: [
              const Icon(Icons.error_outline, color: Colors.red, size: 32),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'Error loading executions',
                      style: TextStyle(
                        color: theme.textColor,
                        fontSize: 18,
                        fontWeight: FontWeight.w800,
                      ),
                    ),
                    const SizedBox(height: 4),
                    Text(
                      snapshot.errorMessage ?? 'An unknown error occurred.',
                      style: TextStyle(color: theme.textSecondaryColor),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }

  Widget _buildExecutionsList(
    BuildContext context,
    OtoConsoleThemeAdapter theme,
    List<OtoExecutionViewModel> executions,
  ) {
    return ListView.separated(
      itemCount: executions.length,
      separatorBuilder: (context, index) => const SizedBox(height: 12),
      itemBuilder: (context, index) {
        final exec = executions[index];
        final isExpanded = expandedExecutionID == exec.executionID;

        return Container(
          decoration: BoxDecoration(
            color: theme.railBackgroundColor,
            borderRadius: BorderRadius.circular(8),
            border: Border.all(color: theme.borderColor),
          ),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              InkWell(
                onTap: () {
                  if (isExpanded) {
                    onExpandExecution?.call(null);
                  } else {
                    onExpandExecution?.call(exec.executionID);
                  }
                },
                borderRadius: BorderRadius.circular(8),
                child: Padding(
                  padding: const EdgeInsets.all(16),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Expanded(
                            child: Text(
                              'Exec ID: ${exec.executionID}',
                              style: TextStyle(
                                color: theme.textColor,
                                fontSize: 16,
                                fontWeight: FontWeight.bold,
                              ),
                              overflow: TextOverflow.ellipsis,
                            ),
                          ),
                          const SizedBox(width: 8),
                          _StatusBadge(state: exec.state, theme: theme),
                        ],
                      ),
                      const SizedBox(height: 8),
                      Text(
                        'Job ID: ${exec.jobID}',
                        style: TextStyle(
                          color: theme.textSecondaryColor,
                          fontSize: 13,
                        ),
                      ),
                      if (exec.runnerID.isNotEmpty) ...[
                        const SizedBox(height: 4),
                        Text(
                          'Runner ID: ${exec.runnerID}',
                          style: TextStyle(
                            color: theme.textSecondaryColor,
                            fontSize: 13,
                          ),
                        ),
                      ],
                      const SizedBox(height: 8),
                      Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Expanded(
                            child: Text(
                              'Created: ${exec.createdAt}',
                              style: TextStyle(
                                color: theme.textSecondaryColor,
                                fontSize: 12,
                              ),
                              overflow: TextOverflow.ellipsis,
                            ),
                          ),
                          Icon(
                            isExpanded
                                ? Icons.expand_less
                                : Icons.expand_more,
                            color: theme.textColor,
                          ),
                        ],
                      ),
                    ],
                  ),
                ),
              ),
              if (isExpanded) ...[
                const Divider(height: 1, thickness: 1),
                Padding(
                  padding: const EdgeInsets.all(16),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      _buildActionsSection(context, theme, exec),
                      const SizedBox(height: 16),
                      _buildLogsSection(theme),
                      const SizedBox(height: 16),
                      _buildArtifactsSection(theme),
                    ],
                  ),
                ),
              ],
            ],
          ),
        );
      },
    );
  }

  Widget _buildActionsSection(BuildContext ctx, OtoConsoleThemeAdapter theme, OtoExecutionViewModel exec) {
    final actionState = actionStates?[exec.executionID];
    final canAct = exec.runnerID.isNotEmpty && !exec.state.toLowerCase().contains('cancel');
    final isSubmitting = actionState?.isSubmitting ?? false;

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          'Actions',
          style: TextStyle(
            color: theme.textColor,
            fontSize: 14,
            fontWeight: FontWeight.bold,
          ),
        ),
        const SizedBox(height: 8),
        Wrap(
          spacing: 8,
          runSpacing: 8,
          children: [
            _ActionButton(
              label: 'Cancel',
              icon: Icons.stop_circle,
              color: Colors.orange,
              enabled: canAct && !isSubmitting,
              state: actionState,
              type: ActionButtonType.cancel,
              themeAdapter: theme,
              onTap: canAct && !isSubmitting
                  ? () {
                      _showCancelConfirmation(ctx, exec);
                    }
                  : null,
            ),
            _ActionButton(
              label: 'Report',
              icon: Icons.check_circle,
              color: theme.primaryColor,
              enabled: canAct && !isSubmitting,
              state: actionState,
              type: ActionButtonType.report,
              themeAdapter: theme,
              onTap: canAct && !isSubmitting
                  ? () {
                      onReportExecution?.call(
                        OtoExecutionReportDraft(
                          executionID: exec.executionID,
                          runnerID: exec.runnerID,
                          success: true,
                        ),
                      );
                    }
                  : null,
            ),
            _ActionButton(
              label: 'Log',
              icon: Icons.bug_report,
              color: theme.accentColor,
              enabled: canAct && !isSubmitting,
              state: actionState,
              type: ActionButtonType.log,
              themeAdapter: theme,
              onTap: canAct && !isSubmitting
                  ? () {
                      onAppendLog?.call(
                        OtoExecutionLogDraft(
                          executionID: exec.executionID,
                          runnerID: exec.runnerID,
                          line: '[manual] Log entry appended from UI',
                        ),
                      );
                    }
                  : null,
            ),
            _ActionButton(
              label: 'Artifact',
              icon: Icons.insert_drive_file,
              color: theme.primaryColor,
              enabled: canAct && !isSubmitting,
              state: actionState,
              type: ActionButtonType.artifact,
              themeAdapter: theme,
              onTap: canAct && !isSubmitting
                  ? () {
                      onAppendArtifact?.call(
                        OtoExecutionArtifactDraft(
                          executionID: exec.executionID,
                          runnerID: exec.runnerID,
                          name: 'manual_artifact.txt',
                          path: '/tmp/manual_artifact.txt',
                        ),
                      );
                    }
                  : null,
            ),
          ],
        ),
        if (actionState != null && (actionState.isSuccess || actionState.isFailed)) ...[
          const SizedBox(height: 8),
          Container(
            padding: const EdgeInsets.all(8),
            decoration: BoxDecoration(
              color: actionState.isFailed
                  ? Colors.red.withValues(alpha: 0.1)
                  : theme.primaryColor.withValues(alpha: 0.1),
              borderRadius: BorderRadius.circular(4),
              border: Border.all(
                color: actionState.isFailed
                    ? Colors.red.withValues(alpha: 0.5)
                    : theme.primaryColor.withValues(alpha: 0.5),
              ),
            ),
            child: Text(
              actionState.message ?? (actionState.isSuccess ? 'Succeeded' : 'Failed'),
              style: TextStyle(
                color: actionState.isFailed ? Colors.red : theme.primaryColor,
                fontSize: 12,
                fontWeight: FontWeight.w600,
              ),
            ),
          ),
        ],
      ],
    );
  }

  void _showCancelConfirmation(BuildContext context, OtoExecutionViewModel exec) {
    showDialog(
      context: context,
      builder: (context) {
        return AlertDialog(
          title: const Text('Cancel Execution'),
          content: Text('Are you sure you want to cancel execution "${exec.executionID}"?'),
          actions: [
            TextButton(
              onPressed: () => Navigator.of(context).pop(),
              child: const Text('No'),
            ),
            ElevatedButton(
              onPressed: () {
                Navigator.of(context).pop();
                onCancelExecution?.call(
                  OtoExecutionCancelDraft(
                    executionID: exec.executionID,
                    runnerID: exec.runnerID,
                    reason: 'User initiated from UI',
                  ),
                );
              },
              style: ElevatedButton.styleFrom(backgroundColor: Colors.red),
              child: const Text('Cancel'),
            ),
          ],
        );
      },
    );
  }

  Widget _buildLogsSection(OtoConsoleThemeAdapter theme) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(
              'Logs Preview',
              style: TextStyle(
                color: theme.textColor,
                fontSize: 14,
                fontWeight: FontWeight.bold,
              ),
            ),
          ],
        ),
        const SizedBox(height: 8),
        Container(
          width: double.infinity,
          padding: const EdgeInsets.all(12),
          decoration: BoxDecoration(
            color: Colors.black,
            borderRadius: BorderRadius.circular(6),
            border: Border.all(color: theme.borderColor),
          ),
          constraints: const BoxConstraints(maxHeight: 180),
          child: _buildLogsContent(theme),
        ),
      ],
    );
  }

  Widget _buildLogsContent(OtoConsoleThemeAdapter theme) {
    if (logsSnapshot == null) {
      return Text(
        'No logs loaded.',
        style: TextStyle(color: theme.textSecondaryColor, fontFamily: 'monospace'),
      );
    }
    switch (logsSnapshot!.state) {
      case OtoSurfaceLoadState.loading:
        return const Center(child: CircularProgressIndicator());
      case OtoSurfaceLoadState.empty:
        return Text(
          'Log is empty.',
          style: TextStyle(color: theme.textSecondaryColor, fontFamily: 'monospace'),
        );
      case OtoSurfaceLoadState.error:
        return Text(
          'Error loading logs: ${logsSnapshot!.errorMessage}',
          style: const TextStyle(color: Colors.red, fontFamily: 'monospace'),
        );
      case OtoSurfaceLoadState.data:
        final logs = logsSnapshot!.data ?? [];
        if (logs.isEmpty) {
          return Text(
            'Log is empty.',
            style: TextStyle(color: theme.textSecondaryColor, fontFamily: 'monospace'),
          );
        }
        return SingleChildScrollView(
          child: Text(
            logs.map((e) => '[${e.timestamp}] ${e.line}').join('\n'),
            style: TextStyle(
              color: theme.textColor,
              fontFamily: 'monospace',
              fontSize: 12,
            ),
          ),
        );
    }
  }

  Widget _buildArtifactsSection(OtoConsoleThemeAdapter theme) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(
              'Artifacts',
              style: TextStyle(
                color: theme.textColor,
                fontSize: 14,
                fontWeight: FontWeight.bold,
              ),
            ),
            if (onViewArtifactsSection != null)
              TextButton.icon(
                onPressed: onViewArtifactsSection,
                icon: const Icon(Icons.arrow_forward, size: 14),
                label: const Text('View Artifacts Tab'),
                style: TextButton.styleFrom(
                  foregroundColor: theme.primaryColor,
                  padding: EdgeInsets.zero,
                  visualDensity: VisualDensity.compact,
                ),
              ),
          ],
        ),
        const SizedBox(height: 8),
        _buildArtifactsContent(theme),
      ],
    );
  }

  Widget _buildArtifactsContent(OtoConsoleThemeAdapter theme) {
    if (artifactsSnapshot == null) {
      return Text(
        'No artifacts loaded.',
        style: TextStyle(color: theme.textSecondaryColor, fontSize: 13),
      );
    }
    switch (artifactsSnapshot!.state) {
      case OtoSurfaceLoadState.loading:
        return const Center(child: CircularProgressIndicator());
      case OtoSurfaceLoadState.empty:
        return Text(
          'No artifacts produced.',
          style: TextStyle(color: theme.textSecondaryColor, fontSize: 13),
        );
      case OtoSurfaceLoadState.error:
        return Text(
          'Error loading artifacts: ${artifactsSnapshot!.errorMessage}',
          style: const TextStyle(color: Colors.red, fontSize: 13),
        );
      case OtoSurfaceLoadState.data:
        final artifacts = artifactsSnapshot!.data ?? [];
        if (artifacts.isEmpty) {
          return Text(
            'No artifacts produced.',
            style: TextStyle(color: theme.textSecondaryColor, fontSize: 13),
          );
        }
        return Column(
          children: artifacts.map((artifact) {
            return Card(
              color: theme.backgroundColor,
              margin: const EdgeInsets.only(bottom: 6),
              shape: RoundedRectangleBorder(
                borderRadius: BorderRadius.circular(4),
                side: BorderSide(color: theme.borderColor),
              ),
              child: ListTile(
                dense: true,
                leading: Icon(Icons.insert_drive_file, color: theme.primaryColor, size: 16),
                title: Text(
                  artifact.name,
                  style: TextStyle(color: theme.textColor, fontSize: 13, fontWeight: FontWeight.bold),
                ),
                subtitle: Text(
                  artifact.path,
                  style: TextStyle(color: theme.textSecondaryColor, fontSize: 11),
                ),
              ),
            );
          }).toList(),
        );
    }
  }
}

enum ActionButtonType { cancel, report, log, artifact }

class _ActionButton extends StatelessWidget {
  final String label;
  final IconData icon;
  final Color color;
  final bool enabled;
  final OtoActionViewState? state;
  final ActionButtonType type;
  final OtoConsoleThemeAdapter themeAdapter;
  final VoidCallback? onTap;

  const _ActionButton({
    required this.label,
    required this.icon,
    required this.color,
    required this.enabled,
    required this.state,
    required this.type,
    required this.themeAdapter,
    required this.onTap,
  });

  @override
  Widget build(BuildContext context) {
    Color successColor = themeAdapter.primaryColor;
    Color failColor = Colors.red;
    if (!enabled) {
      successColor = successColor.withValues(alpha: 0.5);
      failColor = failColor.withValues(alpha: 0.5);
    }
    return SizedBox(
      width: 80,
      height: 36,
      child: ElevatedButton(
        onPressed: onTap,
        style: ElevatedButton.styleFrom(
          backgroundColor: enabled ? color : color.withValues(alpha: 0.3),
          foregroundColor: enabled ? Colors.white : Colors.white60,
          padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
          visualDensity: VisualDensity.compact,
        ),
        child: Row(
          mainAxisSize: MainAxisSize.max,
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            Icon(icon, size: 14, color: enabled ? Colors.white : Colors.white60),
            Flexible(
              child: Text(
                label,
                style: const TextStyle(fontSize: 11, fontWeight: FontWeight.w600),
                overflow: TextOverflow.ellipsis,
              ),
            ),
            if (state != null && state!.isSubmitting) ...[
              const SizedBox(width: 4),
              const SizedBox(
                width: 8,
                height: 8,
                child: CircularProgressIndicator(strokeWidth: 1.5),
              ),
            ] else if (state != null && state!.isSuccess) ...[
              const SizedBox(width: 2),
              Icon(Icons.check, size: 12, color: successColor),
            ] else if (state != null && state!.isFailed) ...[
              const SizedBox(width: 2),
              Icon(Icons.close, size: 12, color: failColor),
            ],
          ],
        ),
      ),
    );
  }
}

class _StatusBadge extends StatelessWidget {
  final String state;
  final OtoConsoleThemeAdapter theme;

  const _StatusBadge({required this.state, required this.theme});

  @override
  Widget build(BuildContext context) {
    Color color;
    switch (state.toLowerCase()) {
      case 'queued':
        color = theme.textSecondaryColor;
        break;
      case 'running':
        color = theme.accentColor;
        break;
      case 'succeeded':
        color = theme.primaryColor;
        break;
      case 'failed':
        color = Colors.red;
        break;
      case 'canceled':
        color = Colors.orange;
        break;
      default:
        color = theme.textSecondaryColor;
        break;
    }

    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 4),
      decoration: BoxDecoration(
        color: color.withValues(alpha: 0.12),
        borderRadius: BorderRadius.circular(12),
        border: Border.all(color: color.withValues(alpha: 0.5)),
      ),
      child: Text(
        state.toUpperCase(),
        style: TextStyle(
          color: color,
          fontSize: 11,
          fontWeight: FontWeight.bold,
        ),
      ),
    );
  }
}
