import 'package:flutter/material.dart';

import '../../domain/bracket.dart';
import 'round_column.dart';

/// Renders a single-elimination bracket as a horizontal scrolling tree.
///
/// Geometry rules:
///   * Each round is a [RoundColumn] of width [_columnWidth] (220px card area
///     + 20px right gap = 240px).
///   * Round 1 matches are evenly distributed across the available height.
///   * Each subsequent round's match N is centered between matches 2N and
///     2N+1 of the previous round.
///   * Connector lines are drawn behind the cards by [_ConnectorsPainter]:
///     a horizontal stub leaves each match's right edge, then a vertical
///     segment joins to the horizontal stub entering the next round's match.
class BracketTreeWidget extends StatelessWidget {
  const BracketTreeWidget({super.key, required this.bracket});

  final Bracket bracket;

  // Layout constants.
  static const double _cardWidth = 200;
  static const double _cardHeight = 80;
  static const double _columnGap = 40;
  static const double _columnWidth = _cardWidth + _columnGap; // 240
  static const double _matchSlotHeight = 120; // card + status line + spacing
  static const double _verticalPadding = 24;
  static const double _labelHeight = RoundColumn.labelHeight;

  @override
  Widget build(BuildContext context) {
    final rounds = bracket.rounds;
    if (rounds.isEmpty) {
      return Center(
        child: Text(
          'This bracket has no rounds yet.',
          style: Theme.of(context).textTheme.bodyMedium,
        ),
      );
    }

    final firstRoundMatches = rounds.first.matches.length.clamp(1, 1024);

    // Total drawable height inside the column body (below the round label).
    final bodyHeight = _matchSlotHeight * firstRoundMatches;
    final columnHeight = bodyHeight + _labelHeight + _verticalPadding * 2;
    final totalWidth = rounds.length * _columnWidth;

    // Compute card centers per round, in local column-body coordinates
    // (i.e. y measured from the top of the Stack that holds the cards).
    final centersByRound = <List<double>>[];
    for (var r = 0; r < rounds.length; r++) {
      final matchCount = rounds[r].matches.length;
      if (r == 0) {
        // Evenly distribute round 1.
        final slot = bodyHeight / matchCount;
        centersByRound.add([
          for (var i = 0; i < matchCount; i++)
            _verticalPadding + slot * (i + 0.5),
        ]);
      } else {
        // Each match centered between its two feeders from previous round.
        final prev = centersByRound[r - 1];
        final centers = <double>[];
        for (var i = 0; i < matchCount; i++) {
          final a = i * 2;
          final b = a + 1;
          if (b < prev.length) {
            centers.add((prev[a] + prev[b]) / 2);
          } else if (a < prev.length) {
            centers.add(prev[a]);
          } else {
            centers.add(_verticalPadding + bodyHeight / 2);
          }
        }
        centersByRound.add(centers);
      }
    }

    final connectorColor = Theme.of(context).colorScheme.outlineVariant;

    return SingleChildScrollView(
      scrollDirection: Axis.horizontal,
      padding: const EdgeInsets.symmetric(horizontal: 16),
      child: SizedBox(
        width: totalWidth,
        height: columnHeight,
        child: Stack(
          children: [
            // Connector lines drawn first so they sit behind the cards.
            Positioned.fill(
              child: IgnorePointer(
                child: CustomPaint(
                  painter: _ConnectorsPainter(
                    rounds: rounds,
                    centersByRound: centersByRound,
                    columnWidth: _columnWidth,
                    cardWidth: _cardWidth,
                    labelHeight: _labelHeight,
                    color: connectorColor,
                  ),
                ),
              ),
            ),
            Row(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                for (var r = 0; r < rounds.length; r++)
                  RoundColumn(
                    round: rounds[r],
                    cardCenters: centersByRound[r],
                    columnWidth: _columnWidth,
                    cardWidth: _cardWidth,
                    cardHeight: _cardHeight,
                    columnHeight: columnHeight,
                  ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class _ConnectorsPainter extends CustomPainter {
  _ConnectorsPainter({
    required this.rounds,
    required this.centersByRound,
    required this.columnWidth,
    required this.cardWidth,
    required this.labelHeight,
    required this.color,
  });

  final List<BracketRound> rounds;
  final List<List<double>> centersByRound;
  final double columnWidth;
  final double cardWidth;
  final double labelHeight;
  final Color color;

  @override
  void paint(Canvas canvas, Size size) {
    final paint = Paint()
      ..color = color
      ..strokeWidth = 1.5
      ..style = PaintingStyle.stroke;

    // For each pair of adjacent rounds, draw connectors from every match in
    // the earlier round into its corresponding match in the later round.
    for (var r = 0; r < rounds.length - 1; r++) {
      final left = centersByRound[r];
      final right = centersByRound[r + 1];

      // Card horizontal bounds for this column.
      final colLeftX = r * columnWidth;
      final cardRightX = colLeftX + (columnWidth + cardWidth) / 2;

      final nextColLeftX = (r + 1) * columnWidth;
      final nextCardLeftX = nextColLeftX + (columnWidth - cardWidth) / 2;

      final midX = (cardRightX + nextCardLeftX) / 2;

      for (var i = 0; i < left.length; i++) {
        // Pair index in next round.
        final next = i ~/ 2;
        if (next >= right.length) continue;

        final fromY = left[i] + labelHeight;
        final toY = right[next] + labelHeight;

        // Right stub from card.
        canvas.drawLine(Offset(cardRightX, fromY), Offset(midX, fromY), paint);
        // Vertical segment connecting siblings.
        canvas.drawLine(Offset(midX, fromY), Offset(midX, toY), paint);
        // Left stub into next round's card.
        canvas.drawLine(
          Offset(midX, toY),
          Offset(nextCardLeftX, toY),
          paint,
        );
      }
    }
  }

  @override
  bool shouldRepaint(covariant _ConnectorsPainter old) {
    return old.rounds != rounds ||
        old.centersByRound != centersByRound ||
        old.color != color ||
        old.columnWidth != columnWidth ||
        old.cardWidth != cardWidth ||
        old.labelHeight != labelHeight;
  }
}
