import 'package:flutter/material.dart';

typedef StepperCallbackFuture = Future<bool> Function(int apply, int total);

class StepperView extends StatefulWidget {
  final double height;
  final Color foregroundColor;
  final Color backgroundColor;
  final double buttonPadding;

  final int initialNumber;
  final int maxNumber;
  final int minNumber;
  final StepperCallbackFuture counterCallback;
  final Function increaseCallback;
  final Function decreaseCallback;

  StepperView({this.initialNumber = 1, this.minNumber = 1, this.maxNumber, @required this.counterCallback, this.increaseCallback, this.decreaseCallback, this.height = 25, @required this.foregroundColor, @required this.backgroundColor, this.buttonPadding = 1}){
    assert((this.initialNumber >= this.minNumber && this.initialNumber <= this.maxNumber));
  }
  @override
  _StepperViewState createState() => _StepperViewState();
}

class _StepperViewState extends State<StepperView> {
  int _currentCount;
  StepperCallbackFuture _counterCallback;
  Function _increaseCallback;
  Function _decreaseCallback;

  @override
  void initState() {
    _currentCount = widget.initialNumber ?? 1;
    _counterCallback = widget.counterCallback;
    _increaseCallback = widget.increaseCallback ?? () {};
    _decreaseCallback = widget.decreaseCallback ?? () {};
    super.initState();
  }

  bool loadingInc = false;
  bool loadingDec = false;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: EdgeInsets.all(widget.buttonPadding),
      decoration: BoxDecoration(
        borderRadius: BorderRadius.circular((widget.height/2) + (widget.buttonPadding*2)),
        color: widget.backgroundColor,
      ),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceEvenly,
        children: [
          _createDecrementButton(
            (_currentCount > widget.minNumber) ? () => _decrement() : null,
          ),
          Container(
              width: 25,
              child: Center(
                child: Text(
                    _currentCount.toString(),
                    style: TextStyle(
                      fontSize: 12,
                      fontWeight: FontWeight.normal,
                      height: 1.5,
                      color: Colors.black,
                    )
                ),
              )
          ),
          _createIncrementButton(
              (_currentCount < widget.maxNumber) ? () => _increment() : null
          ),
        ],
      ),
    );
  }

  void _increment() async{
    doInc({@required bool can}){
      if(can)
        setState(() {
          _currentCount++;
          _increaseCallback();
        });
    }

    if (_currentCount < widget.maxNumber){
      if(_counterCallback == null)
        doInc(can: true);
      else {
        setState(() => loadingInc = true);
        var result = (await _counterCallback(1,_currentCount));
        doInc(can: result);
        setState(() => loadingInc = false);
      }
    }
  }

  void _decrement() async{
    doDec({@required bool can}){
      if(can)
        setState(() {
          _currentCount--;
          _decreaseCallback();
        });
    }
    if (_currentCount > widget.minNumber) {
      if(_counterCallback == null)
        doDec(can: true);
      else {
        setState(() => loadingDec = true);
        var result = (await _counterCallback(-1,_currentCount));
        doDec(can: result);
        setState(() => loadingDec = false);
      }
    }
  }

  Widget _createIncrementButton(Function onPressed,) {
    return Stack(
      children: [
        RawMaterialButton(
          materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
          constraints: BoxConstraints(minWidth: widget.height, minHeight: widget.height),
          onPressed: onPressed,
          elevation: 2.0,
          fillColor: widget.foregroundColor,
          child:
          Icon(
            Icons.add,
            color: (_currentCount < widget.maxNumber) ? Colors.grey[700] : Colors.grey[400],
            size: 12.0,
          ),
          shape: CircleBorder(),
        ),

        if(loadingInc)
          Container(
              decoration: BoxDecoration(
                color: Colors.white.withOpacity(0.8),
                borderRadius: BorderRadius.circular(widget.height/2),
              ),
              height: widget.height,
              width: widget.height,
              child: CircularProgressIndicator(
                  strokeWidth: 3,
                  valueColor: AlwaysStoppedAnimation<Color>(Colors.green)
              )
          )
      ],
    );
  }

  Widget _createDecrementButton(Function onPressed) {
    return Stack(
      children: [
        RawMaterialButton(
          materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
          constraints: BoxConstraints(minWidth: widget.height, minHeight: widget.height),
          onPressed: onPressed,
          elevation: 2.0,
          fillColor: widget.foregroundColor,
          child: Icon(
            Icons.remove,
            color: (_currentCount > widget.minNumber) ? Colors.grey[700] : Colors.grey[400],
            size: 12.0,
          ),
          shape: CircleBorder(),
        ),

        if(loadingDec)
          Container(
              decoration: BoxDecoration(
                color: Colors.white.withOpacity(0.8),
                borderRadius: BorderRadius.circular(widget.height/2),
              ),
              height: widget.height,
              width: widget.height,
              child: CircularProgressIndicator(
                  strokeWidth: 3,
                  valueColor: AlwaysStoppedAnimation<Color>(Colors.red)
              )
          )
      ],
    );
  }
}
