import 'dart:math';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:flutter/widgets.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';

/// a triangle painter
class _TrianglePainter extends CustomPainter {
  // final double lineSize;

  // _TrianglePainter({this.lineSize = 16});
  @override
  void paint(Canvas canvas, Size size) {
    Path path = Path();
    path.moveTo(0, 0);
    path.lineTo(size.width, 0);
    path.lineTo(size.width / 2, tan(pi / 3) * size.width / 2);
    path.close();
    Paint paint = Paint();
    paint.color = const Color.fromARGB(255, 118, 165, 248);
    paint.style = PaintingStyle.fill;
    canvas.drawPath(path, paint);
  }

  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

/// The controller for the ruler picker
/// init the ruler value from the controller
/// 用于 RulerPicker 的控制器，可以在构造函数里初始化默认值
class RulerPickerController extends ValueNotifier<num> {
  RulerPickerController({num value = 0}) : super(value);
  num get value => super.value;
  set value(num newValue) {
    super.value = newValue;
  }
}

typedef void ValueChangedCallback(num value);

/// RulerPicker 标尺选择器
/// [width] 必须是具体的值，包括父级container的width，不能是 double.infinity，
/// 可以传入MediaQuery.of(context).size.width
class RulerPicker extends StatefulWidget {
  final ValueChangedCallback onValueChanged;
  final String Function(int index, num rulerScaleValue) onBuildRulerScaleText;
  final double width;
  final double height;
  final TextStyle rulerScaleTextStyle;
  final List<ScaleLineStyle> scaleLineStyleList;
  final List<RulerRange> ranges;
  final Widget? marker;
  final double rulerMarginTop;
  final Color rulerBackgroundColor;
  final RulerPickerController? controller;

  RulerPicker({
    required this.onValueChanged,
    required this.width,
    required this.height,
    required this.onBuildRulerScaleText,
    this.ranges = const [],
    this.rulerMarginTop = 0,
    this.scaleLineStyleList = const [
      ScaleLineStyle(
          scale: 0,
          color: Color.fromARGB(255, 188, 194, 203),
          width: 2,
          height: 32),
      ScaleLineStyle(
          color: Color.fromARGB(255, 188, 194, 203), width: 1, height: 20),
    ],
    this.rulerScaleTextStyle = const TextStyle(
      color: Color.fromARGB(255, 188, 194, 203),
      fontSize: 14,
    ),
    this.marker,
    this.rulerBackgroundColor = Colors.white,
    this.controller,
  });
  @override
  State<StatefulWidget> createState() {
    return RulerPickerState();
  }
}

class RulerPickerState extends State<RulerPicker> {
  double lastOffset = 0;
  bool isPosFixed = false;
  late ScrollController scrollController;
  Map<int, ScaleLineStyle> _scaleLineStyleMap = {};
  int itemCount = 0;

  // 每个刻度间距
  final double _ruleScaleInterval = 15.w;

  @override
  void initState() {
    super.initState();

    itemCount = _calculateItemCount();

    for (var element in widget.scaleLineStyleList) {
      _scaleLineStyleMap[element.scale] = element;
    }

    double initValueOffset = getPositionByValue(widget.controller?.value ?? 0);

    scrollController = ScrollController(
      initialScrollOffset: initValueOffset > 0 ? initValueOffset : 0,
    );

    scrollController.addListener(_onValueChanged);

    widget.controller?.addListener(() {
      setPositionByValue(widget.controller?.value ?? 0);
    });
  }

  int _calculateItemCount() {
    int itemCount = 0;
    for (var element in widget.ranges) {
      itemCount += ((element.end - element.begin) / element.scale).truncate();
    }
    itemCount += 1;
    return itemCount;
  }

  void _onValueChanged() {
    int currentIndex = scrollController.offset ~/ _ruleScaleInterval.toInt();
    if (currentIndex < 0) currentIndex = 0;

    num currentValue = getRulerScaleValue(currentIndex);
    var lastConfig = widget.ranges.last;
    if (currentValue > lastConfig.end) currentValue = lastConfig.end;

    widget.onValueChanged(currentValue);
  }

  void fixOffset() {
    final double rawOffset = scrollController.offset;
    final double fixedOffset =
        (rawOffset / _ruleScaleInterval).round() * _ruleScaleInterval;

    scrollController.animateTo(
      fixedOffset,
      duration: const Duration(milliseconds: 100),
      curve: Curves.easeOut,
    );

    Future.delayed(const Duration(milliseconds: 120), () {
      _onValueChanged(); // 确保最终值是准确的
    });
  }

  num getRulerScaleValue(int index) {
    num rulerScaleValue = 0;
    RulerRange? currentConfig;

    for (RulerRange config in widget.ranges) {
      currentConfig = config;
      if (currentConfig == widget.ranges.last) {
        break;
      }
      var totalCount =
      ((config.end - config.begin) / config.scale).truncate();
      if (index <= totalCount) {
        break;
      } else {
        index -= totalCount;
      }
    }

    rulerScaleValue = index * currentConfig!.scale + currentConfig.begin;
    return rulerScaleValue;
  }

  double getPositionByValue(num value) {
    double offsetValue = 0;
    for (RulerRange config in widget.ranges) {
      if (config.begin <= value && config.end >= value) {
        offsetValue +=
            ((value - config.begin) / config.scale) * _ruleScaleInterval;
        break;
      } else if (value >= config.begin) {
        var totalCount =
        ((config.end - config.begin) / config.scale).truncate();
        offsetValue += totalCount * _ruleScaleInterval;
      }
    }
    return offsetValue;
  }

  void setPositionByValue(num value) {
    double offsetValue = getPositionByValue(value);
    scrollController.jumpTo(offsetValue);
    fixOffset();
  }

  Widget _buildRulerScaleLine(int index) {
    bool isMajorScale = index % 5 == 0;
    return Container(
      width: 8.w,
      height: isMajorScale ? 48.w : 24.w,
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular(40.w),
        color: const Color(0xffd0d1d6),
      ),
    );
  }

  Widget _buildRulerScale(BuildContext context, int index) {
    return Container(
      width: _ruleScaleInterval,
      child: Stack(
        clipBehavior: Clip.none,
        children: [
          Align(
            alignment: Alignment.topCenter,
            child: _buildRulerScaleLine(index),
          ),
          Positioned(
            bottom: 5,
            width: 100,
            left: -50 + _ruleScaleInterval / 2,
            child: index % 10 == 0
                ? Container(
              alignment: Alignment.center,
              child: Text(
                widget.onBuildRulerScaleText(
                    index, getRulerScaleValue(index)),
                style: widget.rulerScaleTextStyle,
              ),
            )
                : const SizedBox(),
          ),
        ],
      ),
    );
  }

  Widget _buildMark() {
    Widget triangle() {
      return SizedBox(
        width: 15,
        height: 15,
        child: CustomPaint(
          painter: _TrianglePainter(),
        ),
      );
    }

    return SizedBox(
      width: _ruleScaleInterval * 2,
      height: 45,
      child: Stack(
        children: [
          Align(alignment: Alignment.topCenter, child: triangle()),
          Align(
            child: Container(
              width: 3,
              height: 34,
              color: const Color.fromARGB(255, 118, 165, 248),
            ),
          ),
        ],
      ),
    );
  }

  bool isRangesChanged(RulerPicker oldWidget) {
    if (oldWidget.ranges.length != widget.ranges.length) {
      return true;
    }
    for (int i = 0; i < widget.ranges.length; i++) {
      RulerRange oldRange = oldWidget.ranges[i];
      RulerRange range = widget.ranges[i];
      if (oldRange.begin != range.begin ||
          oldRange.end != range.end ||
          oldRange.scale != range.scale) {
        return true;
      }
    }
    return false;
  }

  @override
  void didUpdateWidget(RulerPicker oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (mounted && isRangesChanged(oldWidget)) {
      Future.delayed(Duration.zero, () {
        setState(() {
          itemCount = _calculateItemCount();
        });
        _onValueChanged();
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Container(
      width: widget.width,
      height: widget.height + widget.rulerMarginTop,
      child: Stack(
        children: [
          Align(
            alignment: Alignment.bottomCenter,
            child: Padding(padding: EdgeInsets.only(top: widget.rulerMarginTop),child: Listener(
              onPointerDown: (_) {
                FocusScope.of(context).unfocus();
                isPosFixed = false;
              },
              child: NotificationListener<ScrollNotification>(
                onNotification: (scrollNotification) {
                  if (scrollNotification is ScrollStartNotification) {
                    isPosFixed = false;
                  } else if (scrollNotification is ScrollEndNotification) {
                    if (!isPosFixed) {
                      isPosFixed = true;
                      fixOffset();
                    }
                  }
                  return true;
                },
                child: ListView.builder(
                  padding: EdgeInsets.symmetric(
                    horizontal: (widget.width - _ruleScaleInterval) / 2,
                  ),
                  itemExtent: _ruleScaleInterval,
                  itemCount: itemCount,
                  controller: scrollController,
                  scrollDirection: Axis.horizontal,
                  itemBuilder: _buildRulerScale,
                ),
              ),
            ),)
          ),
          Align(
            alignment: Alignment.topCenter,
            child: widget.marker ?? _buildMark(),
          ),
        ],
      ),
    );
  }

  @override
  void dispose() {
    scrollController.dispose();
    super.dispose();
  }
}


class ScaleLineStyle {
  final int scale;
  final Color color;
  final double width;
  final double height;

  const ScaleLineStyle({
    this.scale = -1,
    required this.color,
    required this.width,
    required this.height,
  });
}

class RulerRange {
  final double scale;
  final int begin;
  final int end;
  const RulerRange({
    required this.begin,
    required this.end,
    this.scale = 1,
  });
}
