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

/// Renders the Backlog board summary panel for the FocusFlow Flutter UI.
library;

import 'dart:math' as math;

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

import '../../theme/backlog_board_visual_tokens.dart';
import '../../theme/focus_flow_tokens.dart';

/// Right-side Backlog summary panel driven by board summary read models.
class BacklogSummaryPanel extends StatefulWidget {
  /// Creates a Backlog summary panel.
  const BacklogSummaryPanel({required this.summary, super.key});

  /// Summary read model to display.
  final BacklogBoardSummaryReadModel summary;

  /// Creates the mutable state object used by this stateful widget.
  /// Flutter calls this once for each mounted widget instance before lifecycle callbacks and builds begin.
  @override
  State<BacklogSummaryPanel> createState() => _BacklogSummaryPanelState();
}

/// State for the Backlog summary panel collapse control.
class _BacklogSummaryPanelState extends State<BacklogSummaryPanel> {
  /// Whether summary body sections are visible.
  var _expanded = true;

  /// 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),
        boxShadow: [
          BoxShadow(
            color: Colors.black.withValues(alpha: 0.18),
            blurRadius: 28,
            offset: const Offset(0, 10),
          ),
        ],
      ),
      child: Padding(
        padding: const EdgeInsets.all(18),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: [
            _SummaryHeader(
              expanded: _expanded,
              onToggle: () {
                setState(() {
                  _expanded = !_expanded;
                });
              },
            ),
            if (_expanded) ...[
              const SizedBox(height: 22),
              Expanded(
                child: SingleChildScrollView(
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.stretch,
                    children: [
                      _SummaryTotals(summary: widget.summary),
                      const SizedBox(height: 22),
                      _PriorityDistribution(
                        distribution: widget.summary.priorityDistribution,
                      ),
                      const SizedBox(height: 18),
                      _ProjectDistribution(
                        distribution: widget.summary.projectDistribution,
                      ),
                      const SizedBox(height: 18),
                      _DurationDistribution(
                        distribution: widget.summary.durationDistribution,
                      ),
                      const SizedBox(height: 18),
                      _PlanningTip(text: widget.summary.planningTip),
                    ],
                  ),
                ),
              ),
            ],
          ],
        ),
      ),
    );
  }
}

/// Header row for the summary panel.
class _SummaryHeader extends StatelessWidget {
  /// Creates a summary header.
  const _SummaryHeader({required this.expanded, required this.onToggle});

  /// Whether body sections are visible.
  final bool expanded;

  /// Callback invoked by the collapse button.
  final VoidCallback onToggle;

  /// 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(
      children: [
        const Icon(Icons.auto_awesome, color: FocusFlowTokens.accentMagenta),
        const SizedBox(width: 10),
        const Expanded(
          child: Text(
            'Backlog summary',
            style: TextStyle(
              color: FocusFlowTokens.textPrimary,
              fontSize: 18,
              fontWeight: FontWeight.w800,
            ),
          ),
        ),
        IconButton(
          key: const ValueKey('backlog-summary-collapse-button'),
          tooltip: expanded ? 'Collapse summary' : 'Expand summary',
          onPressed: onToggle,
          icon: Icon(expanded ? Icons.expand_less : Icons.expand_more),
          color: FocusFlowTokens.textMuted,
          visualDensity: VisualDensity.compact,
        ),
      ],
    );
  }
}

/// Total task and estimated-time metrics.
class _SummaryTotals extends StatelessWidget {
  /// Creates summary totals.
  const _SummaryTotals({required this.summary});

  /// Summary data.
  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 Row(
      children: [
        Expanded(
          child: _SummaryMetric(
            value: '${summary.totalTaskCount}',
            label: 'Total tasks',
          ),
        ),
        Expanded(
          child: _SummaryMetric(
            value: _estimatedTimeText(summary.totalEstimatedMinutes),
            label: 'Total estimated time',
          ),
        ),
      ],
    );
  }
}

/// One numeric metric in the summary panel.
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: 11.5,
          ),
        ),
      ],
    );
  }
}

/// Priority distribution section.
class _PriorityDistribution extends StatelessWidget {
  /// Creates a priority distribution section.
  const _PriorityDistribution({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 _DistributionSection(
      title: 'By priority',
      children: [
        for (final entry in distribution.entries)
          _DistributionRow(
            leading: Icon(
              Icons.flag,
              color: BacklogBoardVisualTokens.priorityColorToken(
                entry.colorToken,
              ),
              size: 15,
            ),
            label: entry.label,
            count: entry.count,
          ),
      ],
    );
  }
}

/// Project distribution section.
class _ProjectDistribution extends StatelessWidget {
  /// Creates a project distribution section.
  const _ProjectDistribution({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 _DistributionSection(
      title: 'By project',
      children: [
        for (final entry in distribution.entries)
          _DistributionRow(
            leading: _ColorDot(
              color: BacklogBoardVisualTokens.projectColor(
                entry.colorToken ?? entry.id,
              ),
            ),
            label: entry.label,
            count: entry.count,
          ),
      ],
    );
  }
}

/// Shared distribution section shell.
class _DistributionSection extends StatelessWidget {
  /// Creates a distribution section.
  const _DistributionSection({required this.title, required this.children});

  /// Section title.
  final String title;

  /// Distribution row widgets.
  final List<Widget> children;

  /// 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.stretch,
      children: [
        Text(
          title,
          style: const TextStyle(
            color: FocusFlowTokens.textPrimary,
            fontWeight: FontWeight.w800,
          ),
        ),
        const SizedBox(height: 9),
        if (children.isEmpty)
          const Text(
            'No tasks',
            style: TextStyle(color: FocusFlowTokens.textFaint, fontSize: 12),
          )
        else
          ...children,
      ],
    );
  }
}

/// One compact distribution row.
class _DistributionRow extends StatelessWidget {
  /// Creates a distribution row.
  const _DistributionRow({
    required this.leading,
    required this.label,
    required this.count,
  });

  /// Leading icon or dot.
  final Widget leading;

  /// Row label.
  final String label;

  /// Row count.
  final int count;

  /// 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 Padding(
      padding: const EdgeInsets.only(bottom: 8),
      child: Row(
        children: [
          SizedBox(width: 18, child: Center(child: leading)),
          const SizedBox(width: 8),
          Expanded(
            child: Text(
              label,
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
              style: const TextStyle(
                color: FocusFlowTokens.textMuted,
                fontSize: 13,
              ),
            ),
          ),
          Text(
            '$count',
            style: const TextStyle(
              color: FocusFlowTokens.textPrimary,
              fontWeight: FontWeight.w700,
            ),
          ),
        ],
      ),
    );
  }
}

/// Colored project dot.
class _ColorDot extends StatelessWidget {
  /// Creates a color dot.
  const _ColorDot({required this.color});

  /// Dot color.
  final Color color;

  /// 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 Container(
      width: 9,
      height: 9,
      decoration: BoxDecoration(color: color, shape: BoxShape.circle),
    );
  }
}

/// Duration donut chart and legend section.
class _DurationDistribution extends StatelessWidget {
  /// Creates a duration distribution section.
  const _DurationDistribution({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) {
    final entries = _durationEntries(distribution);
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        const Text(
          'Duration distribution',
          style: TextStyle(
            color: FocusFlowTokens.textPrimary,
            fontWeight: FontWeight.w800,
          ),
        ),
        const SizedBox(height: 2),
        const Text(
          'Estimated time',
          style: TextStyle(color: FocusFlowTokens.textFaint, fontSize: 11.5),
        ),
        const SizedBox(height: 12),
        Row(
          children: [
            SizedBox(
              width: 88,
              height: 88,
              child: CustomPaint(
                painter: _DurationDonutPainter(entries: entries),
              ),
            ),
            const SizedBox(width: 14),
            Expanded(
              child: Column(
                children: [
                  for (final entry in entries) _DurationLegendRow(entry: entry),
                ],
              ),
            ),
          ],
        ),
      ],
    );
  }
}

/// One normalized duration chart entry.
class _DurationChartEntry {
  /// Creates a duration chart entry.
  const _DurationChartEntry({
    required this.id,
    required this.label,
    required this.count,
    required this.percentage,
    required this.color,
  });

  /// Stable entry id.
  final String id;

  /// Display label.
  final String label;

  /// Task count in this duration bucket.
  final int count;

  /// Share of total distribution.
  final double percentage;

  /// Chart color.
  final Color color;
}

/// Legend row for one duration chart entry.
class _DurationLegendRow extends StatelessWidget {
  /// Creates a duration legend row.
  const _DurationLegendRow({required this.entry});

  /// Chart entry to render.
  final _DurationChartEntry entry;

  /// 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 Padding(
      padding: const EdgeInsets.only(bottom: 7),
      child: Row(
        children: [
          _ColorDot(color: entry.color),
          const SizedBox(width: 7),
          Expanded(
            child: Text(
              entry.label,
              maxLines: 1,
              overflow: TextOverflow.ellipsis,
              style: const TextStyle(
                color: FocusFlowTokens.textMuted,
                fontSize: 11.5,
              ),
            ),
          ),
          Text(
            '${entry.count} (${_percentageLabel(entry.percentage)})',
            style: const TextStyle(
              color: FocusFlowTokens.textPrimary,
              fontSize: 11.5,
              fontWeight: FontWeight.w700,
            ),
          ),
        ],
      ),
    );
  }
}

/// Painter for the duration donut chart.
class _DurationDonutPainter extends CustomPainter {
  /// Creates a duration donut painter.
  const _DurationDonutPainter({required this.entries});

  /// Entries to paint.
  final List<_DurationChartEntry> entries;

  /// Performs the paint behavior for this scheduler component.
  /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
  @override
  void paint(Canvas canvas, Size size) {
    final strokeWidth = size.shortestSide * 0.18;
    final rect = Offset.zero & size;
    final arcRect = rect.deflate(strokeWidth / 2);
    final basePaint = Paint()
      ..color = FocusFlowTokens.subtleBorder.withValues(alpha: 0.62)
      ..style = PaintingStyle.stroke
      ..strokeWidth = strokeWidth;
    final radius = math.min(arcRect.width, arcRect.height) / 2;
    canvas.drawCircle(rect.center, radius, basePaint);

    final total = entries.fold<int>(0, (sum, entry) => sum + entry.count);
    if (total == 0) {
      return;
    }

    var startAngle = -math.pi / 2;
    for (final entry in entries) {
      if (entry.count == 0) {
        continue;
      }
      final sweep = math.pi * 2 * entry.percentage;
      final paint = Paint()
        ..color = entry.color
        ..style = PaintingStyle.stroke
        ..strokeWidth = strokeWidth
        ..strokeCap = StrokeCap.butt;
      canvas.drawArc(arcRect, startAngle, sweep, false, paint);
      startAngle += sweep;
    }
  }

  /// Performs the shouldRepaint behavior for this scheduler component.
  /// The method provides a named entry point for this operation so callers do not need to know the lower-level state or persistence steps involved.
  @override
  bool shouldRepaint(covariant _DurationDonutPainter oldDelegate) {
    return oldDelegate.entries != entries;
  }
}

/// Planning tip card.
class _PlanningTip extends StatelessWidget {
  /// Creates a planning tip card.
  const _PlanningTip({required this.text});

  /// Tip body text.
  final String text;

  /// 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.elevatedPanel,
        borderRadius: BorderRadius.circular(8),
        border: Border.all(
          color: FocusFlowTokens.subtleBorder.withValues(alpha: 0.38),
        ),
      ),
      child: Padding(
        padding: const EdgeInsets.all(14),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            const Row(
              children: [
                Icon(
                  Icons.auto_awesome,
                  color: FocusFlowTokens.accentMagenta,
                  size: 18,
                ),
                SizedBox(width: 8),
                Text(
                  'Planning tip',
                  style: TextStyle(
                    color: FocusFlowTokens.accentMagenta,
                    fontWeight: FontWeight.w800,
                  ),
                ),
              ],
            ),
            const SizedBox(height: 10),
            Text(
              text,
              style: const TextStyle(
                color: FocusFlowTokens.textMuted,
                height: 1.38,
              ),
            ),
          ],
        ),
      ),
    );
  }
}

/// Builds normalized duration chart entries from [distribution].
List<_DurationChartEntry> _durationEntries(
  BacklogDistributionReadModel distribution,
) {
  final byId = {for (final entry in distribution.entries) entry.id: entry};
  return [
    for (final id in const ['0-30', '30-60', '60-120', '120+'])
      _DurationChartEntry(
        id: id,
        label: _durationLabel(id, byId[id]?.label ?? id),
        count: byId[id]?.count ?? 0,
        percentage: byId[id]?.percentage ?? 0,
        color: BacklogBoardVisualTokens.durationColor(id),
      ),
  ];
}

/// Resolves a display label for a duration distribution [id].
String _durationLabel(String id, String fallback) {
  return switch (id) {
    '0-30' => '0-30 min',
    '30-60' => '30-60 min',
    '60-120' => '60-120 min',
    '120+' => '120+ min',
    _ => fallback,
  };
}

/// 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';
}

/// Formats [percentage] for legend display.
String _percentageLabel(double percentage) {
  return '${(percentage * 100).round()}%';
}
