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

/// Renders Difficulty Bars pieces for the FocusFlow Flutter timeline.
library;

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

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

/// Five-bar effort indicator for a timeline task.
class DifficultyBars extends StatelessWidget {
  /// Creates difficulty bars for a scheduler difficulty token.
  const DifficultyBars({
    required this.difficulty,
    this.color = FocusFlowTokens.restPurple,
    this.size = const Size(54, 34),
    super.key,
  });

  /// Difficulty token that determines how many bars are filled.
  final TimelineDifficultyIconToken difficulty;

  /// Color used for filled bars.
  final Color color;

  /// Fixed paint size for the indicator.
  final Size size;

  /// Converts a timeline difficulty token to a filled bar count.
  static int fillCount(TimelineDifficultyIconToken difficulty) {
    return switch (difficulty) {
      TimelineDifficultyIconToken.notSet => 0,
      TimelineDifficultyIconToken.veryEasy => 1,
      TimelineDifficultyIconToken.easy => 2,
      TimelineDifficultyIconToken.medium => 3,
      TimelineDifficultyIconToken.hard => 4,
      TimelineDifficultyIconToken.veryHard => 5,
    };
  }

  /// Converts a domain difficulty level to a filled bar count.
  static int fillCountForLevel(DifficultyLevel difficulty) {
    return switch (difficulty) {
      DifficultyLevel.notSet => 0,
      DifficultyLevel.veryEasy => 1,
      DifficultyLevel.easy => 2,
      DifficultyLevel.medium => 3,
      DifficultyLevel.hard => 4,
      DifficultyLevel.veryHard => 5,
    };
  }

  /// 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 CustomPaint(
      size: size,
      painter: _DifficultyBarsPainter(
        filledCount: fillCount(difficulty),
        color: color,
      ),
    );
  }
}

/// Private implementation type for `_DifficultyBarsPainter` in this library.
/// It keeps supporting state and behavior scoped to the owning file so the public API stays focused on the scheduler concepts that callers use directly.
class _DifficultyBarsPainter extends CustomPainter {
  /// Creates a `_DifficultyBarsPainter` instance with the values required by its invariants.
  /// Callers should pass already-normalized scheduler data because validation and defaulting belong at the model or service boundary, not in arbitrary UI code.
  const _DifficultyBarsPainter({
    required this.filledCount,
    required this.color,
  });

  /// Stores the `filledCount` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final int filledCount;

  /// Stores the `color` value for this object.
  /// This field is part of the explicit state that downstream scheduling, persistence, or UI code reads when composing behavior.
  final Color color;

  /// 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 gap = size.width * 0.08;
    final barWidth = (size.width - gap * 4) / 5;
    final strokePaint = Paint()
      ..color = FocusFlowTokens.textFaint
      ..style = PaintingStyle.stroke
      ..strokeWidth = 1.3;
    final fillPaint = Paint()
      ..color = color
      ..style = PaintingStyle.fill;

    for (var index = 0; index < 5; index += 1) {
      final left = index * (barWidth + gap);
      final height = size.height * (0.34 + index * 0.13);
      final top = size.height - height;
      final rect = RRect.fromRectAndRadius(
        Rect.fromLTWH(left, top, barWidth, height),
        Radius.circular(barWidth / 2),
      );
      if (index < filledCount) {
        canvas.drawRRect(rect, fillPaint);
      } else {
        canvas.drawRRect(rect, strokePaint);
      }
    }
  }

  /// 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 _DifficultyBarsPainter oldDelegate) {
    return oldDelegate.filledCount != filledCount || oldDelegate.color != color;
  }
}
