import 'dart:math';

import 'package:flutter/cupertino.dart';
import 'package:flutter/material.dart';
import 'package:gobang/ai/Ai.dart';
import 'package:gobang/factory/ThemeFactory.dart';
import 'package:gobang/flyweight/Chess.dart';
import 'package:gobang/memorandum/Checkerboard.dart';
import 'package:gobang/utils/TipsDialog.dart';
import 'package:gobang/viewModel/GameViewModel.dart';

import '../bridge/CircleShape.dart';
import '../factory/BlackThemeFactory.dart';
import '../factory/BlueThemeFactory.dart';
import '../flyweight/Position.dart';

var width = 0.0;

/// Description: home page
/// Time       : 02/20/2024 Tuesday
/// Author     : liuyuqi.gov@msn.cn
class HomePage extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => HomePageState();
}

class HomePageState extends State<HomePage> {
  ThemeFactory? _themeFactory;
  GameViewModel _viewModel = GameViewModel.getInstance();
  Checkerboard _originator = Checkerboard.getInstance();
  Icon lightOn = Icon(Icons.lightbulb, color: Colors.amberAccent);
  Icon lightOff = Icon(Icons.lightbulb_outline_rounded);
  Icon circle = Icon(Icons.circle_outlined);
  Icon rect = Icon(Icons.crop_square);
  Icon? currentLight, currentShape;

  @override
  void initState() {
    currentLight = lightOn;
    _themeFactory = BlueThemeFactory();
    currentShape = circle;
    super.initState();
  }

  @override
  Widget build(BuildContext context) {
    width = MediaQuery.of(context).size.width * 0.8;

    return Scaffold(
      appBar: AppBar(
        elevation: 0,
        backgroundColor: _themeFactory!.getTheme().getThemeColor(),
        title: Text("南瓜五子棋"),
        actions: [
          IconButton(
              onPressed: () {
                setState(() {
                  if (_themeFactory is BlackThemeFactory) {
                    currentLight = lightOn;
                    _themeFactory = BlueThemeFactory();
                  } else {
                    currentLight = lightOff;
                    _themeFactory = BlackThemeFactory();
                  }
                });
              },
              icon: currentLight!),
          IconButton(
              onPressed: () {
                setState(() {
                  if (currentShape == circle) {
                    currentShape = rect;
                  } else {
                    currentShape = circle;
                  }
                });
              },
              icon: currentShape!),
        ],
      ),
      body: Container(
        decoration: BoxDecoration(
            gradient: LinearGradient(
                colors: [
              _themeFactory!.getTheme().getThemeColor(),
              Colors.white,
            ],
                stops: [
              0.0,
              1
            ],
                begin: FractionalOffset.topCenter,
                end: FractionalOffset.bottomCenter,
                tileMode: TileMode.repeated)),
        child: Center(
          child: Column(
              mainAxisAlignment: MainAxisAlignment.center,
              crossAxisAlignment: CrossAxisAlignment.center,
              mainAxisSize: MainAxisSize.max,
              children: <Widget>[
                Padding(
                  padding: EdgeInsets.only(top: 14, bottom: 30),
                  child: Text(
                    _viewModel.state,
                    style: TextStyle(color: Colors.white),
                  ),
                ),
                GestureDetector(
                    onTapDown: (topDownDetails) {
                      var position = topDownDetails.localPosition;
                      Chess chess = _viewModel.play(currentShape == circle);
                      setState(() {
                        ChessPainter._position =
                            Position(position.dx, position.dy, chess);
                      });
                    },
                    child: Stack(
                      children: [
                        CustomPaint(
                          size: Size(width, width),
                          painter: CheckerBoardPainter(),
                        ),
                        CustomPaint(
                          size: Size(width, width),
                          painter: ChessPainter(turnAi),
                        )
                      ],
                    )),
                Padding(
                  padding: const EdgeInsets.only(top: 16.0),
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.center,
                    children: [
                      IconButton(
                          onPressed: () {
                            if (_viewModel.undo()) {
                              _originator.undo();
                              Ai.getInstance().init();
                              for (Position po in _originator.state) {
                                Ai.getInstance().addChessman(
                                    po.dx ~/ (width / 15),
                                    po.dy ~/ (width / 15),
                                    po.chess is WhiteChess ? 1 : -1);
                              }
                              setState(() {});
                            } else {
                              TipsDialog.show(context, "提示", "现阶段不能悔棋");
                            }
                          },
                          icon: Icon(Icons.undo)),
                      IconButton(
                          onPressed: () {
                            if (_viewModel.surrender()) {
                              TipsDialog.showByChoose(
                                  context, "提示", "是否要投降并重新开局?", "是", "否",
                                  (value) {
                                if (value) {
                                  setState(() {
                                    ChessPainter._position = null;
                                    _originator.clean();
                                    _viewModel.reset();
                                    Ai.getInstance().init();
                                  });
                                }
                                Navigator.pop(context);
                              });
                            } else {
                              TipsDialog.show(context, "提示", "现阶段不能投降");
                            }
                          },
                          icon: Icon(
                            Icons.sports_handball,
                            color: Colors.deepPurple,
                          )),
                      IconButton(
                          onPressed: () {
                            TipsDialog.showByChoose(
                                context, "提示", "是否重新开局?", "是", "否", (value) {
                              if (value) {
                                setState(() {
                                  ChessPainter._position = null;
                                  _originator.clean();
                                  _viewModel.reset();
                                  Ai.getInstance().init();
                                });
                              }
                              Navigator.pop(context);
                            });
                          },
                          icon: Icon(
                            Icons.restart_alt,
                            color: Colors.indigo,
                          )),
                    ],
                  ),
                ),
              ]),
        ),
      ),
    );
  }

  /// Ai 下棋
  void turnAi() {
    if (ChessPainter._position!.chess is WhiteChess &&
        Ai.getInstance().isWin(ChessPainter._position!.dx ~/ (width / 15),
            ChessPainter._position!.dy ~/ (width / 15), 1)) {
      TipsDialog.show(context, "恭喜", "您打败了决策树算法");
    }
    // 获取Ai下棋地址
    Ai ai = Ai.getInstance();
    ChessPainter._position = ai.searchPosition();
    // 设置棋子外观
    ChessPainter._position!.chess.chessShape = CircleShape();
    // 加入决策中
    Ai.getInstance().addChessman(ChessPainter._position!.dx.toInt(),
        ChessPainter._position!.dy.toInt(), -1);
    if (ChessPainter._position!.chess is BlackChess &&
        Ai.getInstance().isWin(ChessPainter._position!.dx.toInt(),
            ChessPainter._position!.dy.toInt(), -1)) {
      TipsDialog.show(context, "很遗憾", "决策树算法打败了您");
    }
    setState(() {
      ChessPainter._position!.dx = ChessPainter._position!.dx * (width / 15);
      ChessPainter._position!.dy = ChessPainter._position!.dy * (width / 15);
    });
  }
}

class ChessPainter extends CustomPainter {
  static Position? _position;
  final Function _function;
  Checkerboard _originator = Checkerboard.getInstance();

  ChessPainter(Function f) : _function = f;

  @override
  void paint(Canvas canvas, Size size) {
    if (_position == null) {
      return;
    }
    bool add = false;
    double mWidth = size.width / 15; // 每行/列 15 个
    double mHeight = size.height / 15;
    var mPaint = Paint();
    //求两个点之间的距离,让棋子正确的显示在坐标轴上面
    var dx = _position!.dx;
    var dy = _position!.dy;
    for (int i = 0; i < CheckerBoardPainter._crossOverBeanList.length; i++) {
      var absX =
          (dx - CheckerBoardPainter._crossOverBeanList[i]._dx).abs(); //两个点的x轴距离
      var absY =
          (dy - CheckerBoardPainter._crossOverBeanList[i]._dy).abs(); //两个点的y轴距离
      var s = sqrt(absX * absX +
          absY * absY); //利用直角三角形求斜边公式(a的平方 + b的平方 = c的平方)来计算出两点间的距离
      if (s <= mWidth / 2 - 2) {
        // 触摸点到棋盘坐标坐标点距离小于等于棋子半径,那么
        //找到离触摸点最近的棋盘坐标点并记录保存下来
        _position!.dx = CheckerBoardPainter._crossOverBeanList[i]._dx;
        _position!.dy = CheckerBoardPainter._crossOverBeanList[i]._dy;
        _originator.add(_position!);
        add = true;
        if (_position!.chess is WhiteChess) {
          Ai.getInstance().addChessman(
              _position!.dx ~/ (width / 15), _position!.dy ~/ (width / 15), 1);
        }
        // flag = false; //白子下完了,该黑子下了
        break;
      }
    }

    //画子
    mPaint..style = PaintingStyle.fill;
    if (_originator.state.isNotEmpty) {
      for (int i = 0; i < _originator.state.length; i++) {
        mPaint..color = _originator.state[i].chess.color;
        if (_originator.state[i].chess.chessShape.shape == 1) {
          canvas.drawCircle(
              Offset(_originator.state[i].dx, _originator.state[i].dy),
              min(mWidth / 2, mHeight / 2) - 2,
              mPaint);
        }
        if (_originator.state[i].chess.chessShape.shape == 2) {
          Rect rect = Rect.fromCircle(
              center: Offset(_originator.state[i].dx, _originator.state[i].dy),
              radius: min(mWidth / 2, mHeight / 2) - 2);
          canvas.drawRect(rect, mPaint);
        }
      }
    }
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (add && _position!.chess is WhiteChess) {
        _function();
      }
    });
  }

  //在实际场景中正确利用此回调可以避免重绘开销,本示例我们简单的返回true
  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return true;
  }
}

class CheckerBoardPainter extends CustomPainter {
  static List<CrossOverBean> _crossOverBeanList = [];

  @override
  void paint(Canvas canvas, Size size) {
    double mWidth = size.width / 15;
    double mHeight = size.height / 15;
    var mPaint = Paint();

    _crossOverBeanList.clear();
    //重绘下整个界面的画布北京颜色
    //设置画笔,画棋盘背景
    mPaint
      ..isAntiAlias = true //抗锯齿
      ..style = PaintingStyle.fill //填充
      ..color = Color(0x77cdb175); //背景为纸黄色
    canvas.drawRect(
        Rect.fromCenter(
            center: Offset(size.width / 2, size.height / 2),
            width: size.width,
            height: size.height),
        mPaint);
    //画棋盘网格
    mPaint
      ..style = PaintingStyle.stroke
      ..color = CupertinoColors.systemGrey6
      ..strokeWidth = 1.0;
    for (var i = 0; i <= 15; i++) {
      //画横线
      canvas.drawLine(
          Offset(0, mHeight * i), Offset(size.width, mHeight * i), mPaint);
    }
    for (var i = 0; i <= 15; i++) {
      //画竖线
      canvas.drawLine(
          Offset(mWidth * i, 0), Offset(mWidth * i, size.height), mPaint);
    }
    //记录横竖线所有的交叉点
    for (int i = 0; i <= 15; i++) {
      for (int j = 0; j <= 15; j++) {
        _crossOverBeanList.add(CrossOverBean(mWidth * j, mHeight * i));
      }
    }
  }

  //在实际场景中正确利用此回调可以避免重绘开销,本示例我们简单的返回true
  @override
  bool shouldRepaint(CustomPainter oldDelegate) {
    return false;
  }
}

///记录棋盘上横竖线的交叉点
class CrossOverBean {
  double _dx;
  double _dy;

  CrossOverBean(this._dx, this._dy);
}