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

class OtoRunnersSurface extends StatefulWidget {
  final OtoSurfaceSnapshot<List<OtoRunnerViewModel>> snapshot;
  final OtoConsoleThemeAdapter? themeAdapter;
  final Map<String, OtoRunnerActionState> actionStates;
  final ValueChanged<OtoRunnerSelfUpdateDraft>? onSelfUpdateRunner;

  const OtoRunnersSurface({
    super.key,
    required this.snapshot,
    this.themeAdapter,
    this.actionStates = const {},
    this.onSelfUpdateRunner,
  });

  @override
  State<OtoRunnersSurface> createState() => _OtoRunnersSurfaceState();
}

class _OtoRunnersSurfaceState extends State<OtoRunnersSurface> {
  final Map<String, TextEditingController> _versionControllers = {};
  final Map<String, TextEditingController> _urlControllers = {};

  @override
  void dispose() {
    for (final c in _versionControllers.values) {
      c.dispose();
    }
    for (final c in _urlControllers.values) {
      c.dispose();
    }
    super.dispose();
  }

  TextEditingController _versionFor(String runnerID) =>
      _versionControllers.putIfAbsent(runnerID, TextEditingController.new);

  TextEditingController _urlFor(String runnerID) =>
      _urlControllers.putIfAbsent(runnerID, TextEditingController.new);

  @override
  Widget build(BuildContext context) {
    final theme = widget.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.precision_manufacturing_outlined,
                    color: theme.primaryColor,
                    size: 24,
                  ),
                  const SizedBox(width: 12),
                  Expanded(
                    child: Text(
                      'Runners',
                      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 (widget.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 runners = widget.snapshot.data ?? [];
        if (runners.isEmpty) {
          return _buildEmptyState(theme);
        }
        return _buildRunnersList(context, theme, runners);
    }
  }

  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.precision_manufacturing_outlined,
                color: theme.primaryColor,
                size: 32,
              ),
              const SizedBox(width: 16),
              Expanded(
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'No runners connected',
                      style: TextStyle(
                        color: theme.textColor,
                        fontSize: 18,
                        fontWeight: FontWeight.w800,
                      ),
                    ),
                    const SizedBox(height: 4),
                    Text(
                      'Runner registry 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 runners',
                      style: TextStyle(
                        color: theme.textColor,
                        fontSize: 18,
                        fontWeight: FontWeight.w800,
                      ),
                    ),
                    const SizedBox(height: 4),
                    Text(
                      widget.snapshot.errorMessage ?? 'An unknown error occurred.',
                      style: TextStyle(color: theme.textSecondaryColor),
                    ),
                  ],
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }

  Widget _buildRunnersList(
    BuildContext context,
    OtoConsoleThemeAdapter theme,
    List<OtoRunnerViewModel> runners,
  ) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        _NodesTableHeader(theme: theme),
        const SizedBox(height: 8),
        Expanded(
          child: ListView.separated(
            itemCount: runners.length,
            separatorBuilder: (context, index) => const SizedBox(height: 12),
            itemBuilder: (context, index) {
              final runner = runners[index];
              return _buildRunnerRow(context, theme, runner);
            },
          ),
        ),
      ],
    );
  }

  Widget _buildRunnerRow(
    BuildContext context,
    OtoConsoleThemeAdapter theme,
    OtoRunnerViewModel runner,
  ) {
    final actionState = widget.actionStates[runner.runnerID];
    final versionCtrl = _versionFor(runner.runnerID);
    final urlCtrl = _urlFor(runner.runnerID);

    return StatefulBuilder(
      builder: (context, setRowState) {
        final isSubmitting = actionState?.isSubmitting ?? false;
        final urlIsHttps = urlCtrl.text.startsWith('https://');
        final canSubmit = !isSubmitting &&
            versionCtrl.text.trim().isNotEmpty &&
            urlIsHttps &&
            widget.onSelfUpdateRunner != null;

        return _NodeTableRow(
          runnerID: runner.runnerID,
          alias: runner.alias,
          status: _StatusBadge(status: runner.status, theme: theme),
          currentJobID: runner.currentJobID,
          currentExecutionID: runner.currentExecutionID,
          message: runner.message,
          theme: theme,
          actionPanel: widget.onSelfUpdateRunner == null
              ? null
              : _buildSelfUpdateForm(
                  context,
                  theme,
                  runner,
                  versionCtrl,
                  urlCtrl,
                  canSubmit,
                  isSubmitting,
                  actionState,
                  setRowState,
                ),
        );
      },
    );
  }

  Widget _buildSelfUpdateForm(
    BuildContext context,
    OtoConsoleThemeAdapter theme,
    OtoRunnerViewModel runner,
    TextEditingController versionCtrl,
    TextEditingController urlCtrl,
    bool canSubmit,
    bool isSubmitting,
    OtoRunnerActionState? actionState,
    StateSetter setRowState,
  ) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Text(
          'Self Update',
          style: TextStyle(
            color: theme.primaryColor,
            fontSize: 13,
            fontWeight: FontWeight.bold,
          ),
        ),
        const SizedBox(height: 8),
        Row(
          children: [
            SizedBox(
              width: 120,
              child: TextField(
                controller: versionCtrl,
                enabled: !isSubmitting,
                decoration: const InputDecoration(
                  labelText: 'Version',
                  border: OutlineInputBorder(),
                  contentPadding: EdgeInsets.symmetric(
                    horizontal: 10,
                    vertical: 6,
                  ),
                  floatingLabelBehavior: FloatingLabelBehavior.never,
                ),
                style: const TextStyle(fontSize: 13),
                onChanged: (_) => setRowState(() {}),
              ),
            ),
            const SizedBox(width: 8),
            Expanded(
              child: TextField(
                controller: urlCtrl,
                enabled: !isSubmitting,
                decoration: const InputDecoration(
                  labelText: 'Download URL (https://)',
                  border: OutlineInputBorder(),
                  contentPadding: EdgeInsets.symmetric(
                    horizontal: 10,
                    vertical: 6,
                  ),
                  floatingLabelBehavior: FloatingLabelBehavior.never,
                ),
                style: const TextStyle(fontSize: 13),
                onChanged: (_) => setRowState(() {}),
              ),
            ),
            const SizedBox(width: 8),
            ElevatedButton(
              onPressed: canSubmit
                  ? () {
                      widget.onSelfUpdateRunner!(
                        OtoRunnerSelfUpdateDraft(
                          runnerID: runner.runnerID,
                          version: versionCtrl.text.trim(),
                          downloadUrl: urlCtrl.text.trim(),
                        ),
                      );
                    }
                  : null,
              style: ElevatedButton.styleFrom(
                backgroundColor: theme.primaryColor,
                foregroundColor: theme.backgroundColor,
                padding: const EdgeInsets.symmetric(
                  horizontal: 16,
                  vertical: 8,
                ),
              ),
              child: isSubmitting
                  ? const SizedBox(
                      width: 16,
                      height: 16,
                      child: CircularProgressIndicator(strokeWidth: 2),
                    )
                  : const Text('Update', style: TextStyle(fontSize: 13)),
            ),
          ],
        ),
        if (actionState != null &&
            (actionState.isSuccess ||
                actionState.isDeferred ||
                actionState.isFailed)) ...[
          const SizedBox(height: 6),
          Container(
            padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 6),
            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.3)
                    : theme.primaryColor.withValues(alpha: 0.3),
              ),
            ),
            child: Text(
              actionState.isDeferred
                  ? 'Deferred: ${actionState.message ?? "Update scheduled"}'
                  : actionState.message ??
                      (actionState.isSuccess ? 'Update accepted' : 'Update failed'),
              style: TextStyle(
                color: actionState.isFailed ? Colors.red : theme.primaryColor,
                fontSize: 12,
              ),
            ),
          ),
        ],
      ],
    );
  }
}

/// Jenkins Nodes/Agents-style table header for the runners list.
class _NodesTableHeader extends StatelessWidget {
  final OtoConsoleThemeAdapter theme;

  const _NodesTableHeader({required this.theme});

  @override
  Widget build(BuildContext context) {
    final style = TextStyle(
      color: theme.textSecondaryColor,
      fontSize: 12,
      fontWeight: FontWeight.w800,
    );
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 10),
      decoration: BoxDecoration(
        color: theme.railBackgroundColor,
        borderRadius: BorderRadius.circular(8),
        border: Border.all(color: theme.borderColor),
      ),
      child: Row(
        children: [
          Expanded(flex: 3, child: Text('Nodes', style: style)),
          Expanded(flex: 2, child: Text('Executor', style: style)),
          Expanded(flex: 2, child: Text('Current job', style: style)),
          Expanded(flex: 2, child: Text('Current run', style: style)),
          Expanded(flex: 2, child: Text('Manage', style: style)),
        ],
      ),
    );
  }
}

/// Jenkins Nodes/Agents-style operational row: node identity, executor
/// status, current job/run context, and a manage affordance above the
/// existing Self Update panel.
class _NodeTableRow extends StatelessWidget {
  final String runnerID;
  final String alias;
  final Widget status;
  final String currentJobID;
  final String currentExecutionID;
  final String message;
  final Widget? actionPanel;
  final OtoConsoleThemeAdapter theme;

  const _NodeTableRow({
    required this.runnerID,
    required this.alias,
    required this.status,
    required this.currentJobID,
    required this.currentExecutionID,
    required this.message,
    this.actionPanel,
    required this.theme,
  });

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.all(16),
      decoration: BoxDecoration(
        color: theme.railBackgroundColor,
        borderRadius: BorderRadius.circular(8),
        border: Border.all(color: theme.borderColor),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Row(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Expanded(
                flex: 3,
                child: Column(
                  crossAxisAlignment: CrossAxisAlignment.start,
                  children: [
                    Text(
                      'ID: $runnerID',
                      style: TextStyle(
                        color: theme.textColor,
                        fontSize: 16,
                        fontWeight: FontWeight.bold,
                      ),
                      overflow: TextOverflow.ellipsis,
                    ),
                    if (alias.isNotEmpty) ...[
                      const SizedBox(height: 6),
                      Text(
                        'Alias: $alias',
                        style: TextStyle(color: theme.textColor, fontSize: 14),
                      ),
                    ],
                  ],
                ),
              ),
              Expanded(flex: 2, child: status),
              Expanded(
                flex: 2,
                child: Text(
                  'Job: ${currentJobID.isNotEmpty ? currentJobID : "None"}',
                  overflow: TextOverflow.ellipsis,
                  style: TextStyle(color: theme.textColor, fontSize: 12),
                ),
              ),
              Expanded(
                flex: 2,
                child: Text(
                  'Execution: ${currentExecutionID.isNotEmpty ? currentExecutionID : "None"}',
                  overflow: TextOverflow.ellipsis,
                  style: TextStyle(color: theme.textColor, fontSize: 12),
                ),
              ),
              Expanded(
                flex: 2,
                child: Icon(
                  Icons.build_circle_outlined,
                  color: theme.primaryColor,
                  size: 18,
                ),
              ),
            ],
          ),
          if (message.isNotEmpty) ...[
            const SizedBox(height: 10),
            Text(
              'Message: $message',
              style: TextStyle(color: theme.textSecondaryColor, fontSize: 14),
            ),
          ],
          if (actionPanel != null) ...[
            const SizedBox(height: 12),
            actionPanel!,
          ],
        ],
      ),
    );
  }
}

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

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

  @override
  Widget build(BuildContext context) {
    Color color;
    switch (status.toLowerCase()) {
      case 'active':
      case 'online':
      case 'idle':
        color = theme.primaryColor;
        break;
      case 'busy':
      case 'running':
        color = theme.accentColor;
        break;
      case 'offline':
      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(
        status.toUpperCase(),
        style: TextStyle(
          color: color,
          fontSize: 11,
          fontWeight: FontWeight.bold,
        ),
      ),
    );
  }
}
