// SPDX-FileCopyrightText: 2026 FocusFlow contributors
// SPDX-License-Identifier: AGPL-3.0-only

/// Renders the Backlog board screen shell for the FocusFlow Flutter UI.
library;

import 'dart:async';

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

import '../../controllers/backlog_board_controller.dart';
import '../../models/backlog/backlog_board_screen_data.dart';
import '../../theme/focus_flow_tokens.dart';
import 'backlog_board_column.dart';
import 'backlog_board_controls.dart';

/// Backlog board screen backed by a public scheduler read controller.
class BacklogBoardScreen extends StatelessWidget {
  /// Creates a Backlog board screen.
  const BacklogBoardScreen({required this.controller, super.key});

  /// Controller that owns Backlog board read and selection state.
  final BacklogBoardController controller;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: controller,
      builder: (context, _) {
        return switch (controller.state) {
          BacklogBoardLoading() => _BacklogFrame(
            taskCountLabel: '...',
            controller: controller,
            body: const _BacklogLoadingBody(),
          ),
          BacklogBoardFailure(:final message) => _BacklogFrame(
            taskCountLabel: '...',
            controller: controller,
            body: _BacklogFailureBody(
              message: message,
              onRetry: controller.retry,
            ),
          ),
          BacklogBoardEmpty(:final data) => _BacklogFrame(
            taskCountLabel: '${data.summary.totalTaskCount} tasks',
            controller: controller,
            body: _BacklogReadyBody(
              data: data,
              selectedTaskId: controller.selectedTaskId,
              onTaskSelected: (taskId) {
                unawaited(controller.selectTask(taskId));
              },
              onAddTask: _handleAddTaskPlaceholder,
              isEmpty: true,
            ),
          ),
          BacklogBoardReady(:final data) => _BacklogFrame(
            taskCountLabel: '${data.summary.totalTaskCount} tasks',
            controller: controller,
            body: _BacklogReadyBody(
              data: data,
              selectedTaskId: controller.selectedTaskId,
              onTaskSelected: (taskId) {
                unawaited(controller.selectTask(taskId));
              },
              onAddTask: _handleAddTaskPlaceholder,
            ),
          ),
        };
      },
    );
  }
}

/// Handles pre-Block-8 add-task button presses without mutating scheduler data.
void _handleAddTaskPlaceholder(BacklogBoardBucket bucket) {}

/// Main Backlog frame containing header, controls, body, and overlay slot.
class _BacklogFrame extends StatelessWidget {
  /// Creates the Backlog frame.
  const _BacklogFrame({
    required this.taskCountLabel,
    required this.controller,
    required this.body,
  });

  /// Count label displayed beside the page title.
  final String taskCountLabel;

  /// Controller used by search and filter controls.
  final BacklogBoardController controller;

  /// Body rendered below the header controls.
  final Widget body;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return Stack(
      children: [
        Padding(
          padding: const EdgeInsets.fromLTRB(28, 26, 24, 28),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              _BacklogHeader(taskCountLabel: taskCountLabel),
              const SizedBox(height: 22),
              BacklogBoardTopControls(controller: controller),
              const SizedBox(height: 18),
              Expanded(child: body),
            ],
          ),
        ),
        const Positioned.fill(child: IgnorePointer(child: SizedBox.shrink())),
      ],
    );
  }
}

/// Header row for the Backlog board shell.
class _BacklogHeader extends StatelessWidget {
  /// Creates the Backlog header.
  const _BacklogHeader({required this.taskCountLabel});

  /// Count label displayed beside the page title.
  final String taskCountLabel;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Expanded(
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Wrap(
                crossAxisAlignment: WrapCrossAlignment.center,
                spacing: 12,
                runSpacing: 8,
                children: [
                  Text(
                    'Backlog',
                    style: Theme.of(context).textTheme.displaySmall?.copyWith(
                      color: FocusFlowTokens.textPrimary,
                      fontSize: 34,
                      fontWeight: FontWeight.w800,
                    ),
                  ),
                  _CountPill(label: taskCountLabel),
                ],
              ),
              const SizedBox(height: 10),
              Text(
                'Choose work that fits your current energy.',
                style: Theme.of(context).textTheme.bodyMedium?.copyWith(
                  color: FocusFlowTokens.textMuted,
                ),
              ),
            ],
          ),
        ),
        const SizedBox(width: 20),
        const BacklogModeAndSettingsControls(),
      ],
    );
  }
}

/// Body shown while the Backlog board loads.
class _BacklogLoadingBody extends StatelessWidget {
  /// Creates a loading body.
  const _BacklogLoadingBody();

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return const _BacklogStatePanel(
      icon: Icons.hourglass_top,
      title: 'Loading backlog',
      message: 'Preparing your board.',
    );
  }
}

/// Body shown when the Backlog board fails to load.
class _BacklogFailureBody extends StatelessWidget {
  /// Creates a failure body.
  const _BacklogFailureBody({required this.message, required this.onRetry});

  /// Failure message or code.
  final String message;

  /// Retry callback.
  final Future<void> Function() onRetry;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return _BacklogStatePanel(
      icon: Icons.refresh,
      title: 'Could not load backlog',
      message: 'Status: $message',
      action: OutlinedButton.icon(
        onPressed: () {
          unawaited(onRetry());
        },
        icon: const Icon(Icons.refresh),
        label: const Text('Retry'),
      ),
    );
  }
}

/// Ready or empty Backlog board body.
class _BacklogReadyBody extends StatelessWidget {
  /// Creates a ready body.
  const _BacklogReadyBody({
    required this.data,
    required this.selectedTaskId,
    required this.onTaskSelected,
    required this.onAddTask,
    this.isEmpty = false,
  });

  /// Backlog board data.
  final BacklogBoardScreenData data;

  /// Currently selected task id, if any.
  final String? selectedTaskId;

  /// Callback invoked when a task card is selected.
  final BacklogTaskSelected onTaskSelected;

  /// Callback invoked when a column add-task control is pressed.
  final BacklogBucketAddRequested onAddTask;

  /// Whether the board has no tasks.
  final bool isEmpty;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return Row(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        Expanded(
          child: _BacklogBoardColumns(
            columns: data.columns,
            selectedTaskId: selectedTaskId,
            onTaskSelected: onTaskSelected,
            onAddTask: onAddTask,
          ),
        ),
        const SizedBox(width: 16),
        SizedBox(
          width: 292,
          child: isEmpty
              ? const _BacklogStatePanel(
                  icon: Icons.check_circle_outline,
                  title: 'Backlog is clear',
                  message: 'New tasks will appear here.',
                )
              : _BacklogSummaryShell(summary: data.summary),
        ),
      ],
    );
  }
}

/// Horizontally scrollable set of Backlog board columns.
class _BacklogBoardColumns extends StatelessWidget {
  /// Creates a board column layout.
  const _BacklogBoardColumns({
    required this.columns,
    required this.selectedTaskId,
    required this.onTaskSelected,
    required this.onAddTask,
  });

  /// Columns to render in scheduler-provided display order.
  final List<BacklogBoardColumnReadModel> columns;

  /// Currently selected task id, if any.
  final String? selectedTaskId;

  /// Callback invoked when a task card is selected.
  final BacklogTaskSelected onTaskSelected;

  /// Callback invoked when an add-task control is pressed.
  final BacklogBucketAddRequested onAddTask;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    if (columns.isEmpty) {
      return const SizedBox.shrink();
    }
    return LayoutBuilder(
      builder: (context, constraints) {
        const columnGap = 10.0;
        const minColumnWidth = 260.0;
        const maxColumnWidth = 300.0;
        final gapWidth = columnGap * (columns.length - 1);
        final availableWidth = constraints.hasBoundedWidth
            ? constraints.maxWidth
            : maxColumnWidth * columns.length + gapWidth;
        final columnWidth = ((availableWidth - gapWidth) / columns.length)
            .clamp(minColumnWidth, maxColumnWidth)
            .toDouble();
        final boardWidth = columnWidth * columns.length + gapWidth;
        final contentWidth = boardWidth < availableWidth
            ? availableWidth
            : boardWidth;
        return SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: SizedBox(
            width: contentWidth,
            child: Row(
              crossAxisAlignment: CrossAxisAlignment.stretch,
              children: [
                for (var index = 0; index < columns.length; index += 1) ...[
                  SizedBox(
                    width: columnWidth,
                    child: BacklogBoardColumn(
                      column: columns[index],
                      selectedTaskId: selectedTaskId,
                      onTaskSelected: onTaskSelected,
                      onAddTask: onAddTask,
                    ),
                  ),
                  if (index != columns.length - 1)
                    const SizedBox(width: columnGap),
                ],
              ],
            ),
          ),
        );
      },
    );
  }
}

/// Summary panel shell for loaded board data.
class _BacklogSummaryShell extends StatelessWidget {
  /// Creates a summary shell.
  const _BacklogSummaryShell({required this.summary});

  /// Summary read model.
  final BacklogBoardSummaryReadModel summary;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return DecoratedBox(
      decoration: BoxDecoration(
        color: FocusFlowTokens.panelBackground,
        borderRadius: BorderRadius.circular(8),
        border: Border.all(color: FocusFlowTokens.subtleBorder),
      ),
      child: Padding(
        padding: const EdgeInsets.all(18),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Row(
              children: [
                Icon(Icons.auto_awesome, color: FocusFlowTokens.accentMagenta),
                SizedBox(width: 10),
                Expanded(
                  child: Text(
                    'Backlog summary',
                    style: TextStyle(
                      color: FocusFlowTokens.textPrimary,
                      fontSize: 18,
                      fontWeight: FontWeight.w800,
                    ),
                  ),
                ),
                Icon(Icons.expand_less, color: FocusFlowTokens.textMuted),
              ],
            ),
            const SizedBox(height: 24),
            Row(
              children: [
                Expanded(
                  child: _SummaryMetric(
                    value: '${summary.totalTaskCount}',
                    label: 'Total tasks',
                  ),
                ),
                Expanded(
                  child: _SummaryMetric(
                    value: _estimatedTimeText(summary.totalEstimatedMinutes),
                    label: 'Estimated time',
                  ),
                ),
              ],
            ),
            const SizedBox(height: 26),
            _SummaryDistribution(distribution: summary.priorityDistribution),
            const SizedBox(height: 20),
            _SummaryDistribution(distribution: summary.projectDistribution),
            const Spacer(),
            DecoratedBox(
              decoration: BoxDecoration(
                color: FocusFlowTokens.elevatedPanel,
                borderRadius: BorderRadius.circular(8),
              ),
              child: Padding(
                padding: const EdgeInsets.all(14),
                child: Text(
                  summary.planningTip,
                  style: const TextStyle(
                    color: FocusFlowTokens.textMuted,
                    height: 1.4,
                  ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }

  /// Formats [minutes] as compact hour/minute text.
  String _estimatedTimeText(int minutes) {
    final hours = minutes ~/ 60;
    final remainder = minutes % 60;
    if (hours == 0) {
      return '${remainder}m';
    }
    if (remainder == 0) {
      return '${hours}h';
    }
    return '${hours}h ${remainder}m';
  }
}

/// One numeric metric in the summary shell.
class _SummaryMetric extends StatelessWidget {
  /// Creates a summary metric.
  const _SummaryMetric({required this.value, required this.label});

  /// Metric value.
  final String value;

  /// Metric label.
  final String label;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          value,
          style: const TextStyle(
            color: FocusFlowTokens.textPrimary,
            fontSize: 24,
            fontWeight: FontWeight.w800,
          ),
        ),
        const SizedBox(height: 4),
        Text(
          label,
          style: const TextStyle(
            color: FocusFlowTokens.textFaint,
            fontSize: 12,
          ),
        ),
      ],
    );
  }
}

/// Compact list form of a summary distribution.
class _SummaryDistribution extends StatelessWidget {
  /// Creates a summary distribution.
  const _SummaryDistribution({required this.distribution});

  /// Distribution read model.
  final BacklogDistributionReadModel distribution;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(
          distribution.title,
          style: const TextStyle(
            color: FocusFlowTokens.textPrimary,
            fontWeight: FontWeight.w700,
          ),
        ),
        const SizedBox(height: 10),
        for (final entry in distribution.entries.take(5))
          Padding(
            padding: const EdgeInsets.only(bottom: 8),
            child: Row(
              children: [
                Expanded(
                  child: Text(
                    entry.label,
                    maxLines: 1,
                    overflow: TextOverflow.ellipsis,
                    style: const TextStyle(color: FocusFlowTokens.textMuted),
                  ),
                ),
                Text(
                  '${entry.count}',
                  style: const TextStyle(color: FocusFlowTokens.textPrimary),
                ),
              ],
            ),
          ),
      ],
    );
  }
}

/// Reusable centered state panel.
class _BacklogStatePanel extends StatelessWidget {
  /// Creates a state panel.
  const _BacklogStatePanel({
    required this.icon,
    required this.title,
    required this.message,
    this.action,
  });

  /// Leading icon.
  final IconData icon;

  /// Panel title.
  final String title;

  /// Panel message.
  final String message;

  /// Optional action widget.
  final Widget? action;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    return Center(
      child: ConstrainedBox(
        constraints: const BoxConstraints(maxWidth: 360),
        child: DecoratedBox(
          decoration: BoxDecoration(
            color: FocusFlowTokens.panelBackground,
            borderRadius: BorderRadius.circular(8),
            border: Border.all(color: FocusFlowTokens.subtleBorder),
          ),
          child: Padding(
            padding: const EdgeInsets.all(24),
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                Icon(icon, color: FocusFlowTokens.accentMagenta, size: 28),
                const SizedBox(height: 14),
                Text(
                  title,
                  textAlign: TextAlign.center,
                  style: const TextStyle(
                    color: FocusFlowTokens.textPrimary,
                    fontSize: 18,
                    fontWeight: FontWeight.w800,
                  ),
                ),
                const SizedBox(height: 8),
                Text(
                  message,
                  textAlign: TextAlign.center,
                  style: const TextStyle(color: FocusFlowTokens.textMuted),
                ),
                if (action != null) ...[const SizedBox(height: 18), action!],
              ],
            ),
          ),
        ),
      ),
    );
  }
}

/// Small count pill used by headers.
class _CountPill extends StatelessWidget {
  /// Creates a count pill.
  const _CountPill({required this.label});

  /// Pill label.
  final String label;

  /// Builds the widget subtree for this component.
  /// The method translates the current widget configuration and state into Flutter UI without mutating scheduler domain data.
  @override
  Widget build(BuildContext context) {
    const accent = FocusFlowTokens.textMuted;
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 5),
      decoration: BoxDecoration(
        color: accent.withValues(alpha: 0.16),
        borderRadius: BorderRadius.circular(8),
      ),
      child: Text(
        label,
        style: const TextStyle(
          color: FocusFlowTokens.textPrimary,
          fontSize: 12,
          fontWeight: FontWeight.w800,
        ),
      ),
    );
  }
}
