import 'dart:async';
import 'dart:developer' as developer;
import 'dart:math';
import 'package:skillcourt/widgets/color_picker.dart';
import 'package:flutter_colorpicker/flutter_colorpicker.dart' as cp;
import 'package:event/event.dart';
import 'package:flutter/material.dart';
import 'package:flutter_nsd/flutter_nsd.dart';
import 'package:skillcourt/pad.dart';
import 'package:skillcourt/pages/pad_manager.dart';
import 'package:skillcourt/global_data.dart';
import 'package:skillcourt/game_session.dart';
import 'package:skillcourt/game_session_model.dart';
import 'package:provider/provider.dart';
import 'package:skillcourt/services/database.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'dart:convert';
import 'package:skillcourt/game_session.dart';
import 'package:skillcourt/pages/statistics.dart';

class StartGame extends StatelessWidget {
  static const routeName = 'StartGame';

  final GameSessionModel gameSessionModel;

  const StartGame({Key? key, required this.gameSessionModel}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return ChangeNotifierProvider.value(
      value: gameSessionModel,
      child: _StartGameContent(),
    );
  }
}

void _navigateToStatisticsPage(BuildContext context, GameSession gameSession) {
  Navigator.push(
    context,
    MaterialPageRoute(
      builder: (context) => StatisticsPage(gameSession: gameSession),
    ),
  );
}

class _StartGameContent extends StatefulWidget {
  static const String routeName = '/startGame';

  @override
  State<_StartGameContent> createState() => _StartGameContentState();
}

class _StartGameContentState extends State<_StartGameContent> {
  late GameSessionModel gameSessionModel;
  late List<GameSession> gameSessions;

  int sessionNumber = 1;
  Timer? timer;
  late DateTime gameStartTime;
  Duration sessionDuration = Duration.zero;

  late TextEditingController _controller;
  int _gameLen = 30;
  int _padLightUp = 1;
  int _padInterval = 2;
  bool timerOn = false;
  late String padResult;
  late Event hasResult;
  Map<NsdServiceInfo, Pad> socketMap = <NsdServiceInfo, Pad>{};
  List<NsdServiceInfo> services = <NsdServiceInfo>[];
  List<Pad> listOfPads = <Pad>[];
  PadManagerPage padManagerPage = const PadManagerPage();
  Color mycolor = Colors.green;
  double _value = 20.0;

  @override
  void initState() {
    super.initState();
    _controller = TextEditingController();
    gameSessionModel = Provider.of<GameSessionModel>(context, listen: false);
    gameSessions = gameSessionModel.gameSessions;
  }

  @override
  void dispose() {
    _controller.dispose();
    timer?.cancel();
    super.dispose();
  }

  ///This function is called when the 'Play' button is pressed. It gets the NSD service info
  ///of every available service and the map of sockets that contains the NSD service to Pad mapping.
  Future<void> startGame(BuildContext context) async {
    socketMap = padManagerPage.getMap();
    services = padManagerPage.getServices();
    //set counter of hits to 0
    padManagerPage.setHits();
    gameStartTime = DateTime.now();
    final int range = services.length;

    for (int i = 0; i < range; i++) {
      final Pad pad = socketMap[services[i]]!;
      listOfPads.add(pad);
    }
    final Random rand = Random();
    int maxNumHits = (_gameLen / (_padInterval + _padLightUp)).ceil();
    int seconds = 0;
    Timer timer;

    for (final Pad pad in listOfPads) {
      pad.send('2');
    }

    int time = _gameLen;

    void calculateSessionDuration() {
      final DateTime gameEndTime = DateTime.now();
      sessionDuration = gameEndTime
          .difference(gameStartTime); // Update the sessionDuration value
      // Update the sessionDuration value
    }

    timer = Timer.periodic(const Duration(seconds: 1), (timer) {
      timerOn = true;
      seconds = seconds + 1;
      setState(() => _gameLen--);
      if (seconds >= time) {
        timer.cancel();
        calculateSessionDuration();
      }
    });

    while (true) {
      //break out of infinite loop if time runs out
      if (_gameLen <= 0) {
        await Future.delayed(const Duration(milliseconds: 100));

        break;
      }

      if (listOfPads.isNotEmpty) {
        int padNum = rand.nextInt(listOfPads.length);
        developer.log('Lighting up pad number $padNum!');
        //wait 2 seconds then light up the pad for X number of seconds, determined by what user put in the textfield.
        await Future.delayed(Duration(seconds: _padInterval));
        listOfPads[padNum].send('3');
        await Future.delayed(Duration(seconds: _padLightUp));
        listOfPads[padNum].send('4');
      }
    }
    //clear the pads as to not add duplicate pads when running the game again (can use sets instead?).
    listOfPads.clear();
    final int numHits = padManagerPage.getHits();
    final String hits = padManagerPage.getHits().toString();
    final String misses = (maxNumHits - numHits).toString();
    final data = Provider.of<GlobalData>(context, listen: false);

    final gameSessionModel = context.read<GameSessionModel>();
    final session = GameSession(
      sessionNumber: gameSessionModel.gameSessions.length + 1,
      sessionDate: DateTime.now(),
      sessionId: 'id',
      sessionDuration: sessionDuration,
      hits: numHits,
      misses: maxNumHits - numHits,
    );
    gameSessionModel.addGameSession(session);

    Navigator.pushReplacementNamed(context, StatisticsPage.routeName);

    data.updateHits(numHits);
    data.updateMisses(maxNumHits - numHits);

    displayDialog(
        context, 'Game completed!', 'You got $hits hits and $misses misses!');

    sessionNumber++;
  }

  void displayDialog(
          BuildContext context, String title, String text) =>
      showDialog(
          context: context,
          builder: (context) =>
              AlertDialog(title: Text(title), content: Text(text)));

  final ButtonStyle style =
      ElevatedButton.styleFrom(textStyle: const TextStyle(fontSize: 20));

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        title: const Text('Game Settings'),
      ),
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        mainAxisAlignment: MainAxisAlignment.center,
        children: [
          if (timerOn)
            Text('$_gameLen',
                textAlign: TextAlign.center,
                style: const TextStyle(
                  fontWeight: FontWeight.bold,
                  height: 2,
                  color: Colors.green,
                  fontSize: 45,
                ))
          else
            const Text(' '),
          TextField(
              onSubmitted: (value) {
                _gameLen = int.parse(value);
              },
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Game length',
              )),
          const SizedBox(height: 20), //spacing size between each text field
          TextField(
              onSubmitted: (value) {
                _padLightUp = int.parse(value);
              },
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Pad light up time',
              )),
          const SizedBox(height: 20), //spacing size between each text field
          TextField(
              onSubmitted: (value) {
                _padInterval = int.parse(value);
              },
              decoration: const InputDecoration(
                border: OutlineInputBorder(),
                labelText: 'Pad interval time',
              )),
          const SizedBox(height: 20),
          const SizedBox(
              child: Text('Pad Brightness',
                  textAlign: TextAlign.center, style: TextStyle(fontSize: 20))),
          const SizedBox(height: 30),
          SizedBox(
            width: double.maxFinite,
            child: Slider(
                min: 0.0,
                max: 100.0,
                divisions: 100,
                value: _value,
                label: '${_value.round()}',
                onChanged: (value) {
                  setState(() {
                    _value = value;
                  });
                }),
          ),
          //temporary placeholder color picker, 0 functionality
          //changes color of button to picked color
          ElevatedButton(
            onPressed: () {
              showDialog(
                  context: context,
                  builder: (BuildContext context) {
                    return AlertDialog(
                      title: Text('Pick a color!'),
                      content: SingleChildScrollView(
                        child: cp.BlockPicker(
                          pickerColor: mycolor, //default color
                          onColorChanged: (Color color) {
                            //on color picked
                            setState(() {
                              mycolor = color;
                            });
                          },
                        ),
                      ),
                      actions: <Widget>[
                        ElevatedButton(
                          child: const Text('DONE'),
                          onPressed: () {
                            Navigator.of(context)
                                .pop(); //dismiss the color picker
                          },
                        ),
                      ],
                    );
                  });
            },
            style: ElevatedButton.styleFrom(
                backgroundColor: mycolor,
                textStyle: const TextStyle(fontSize: 20)),
            child: Text('Pad Color'),
          ),
          const SizedBox(height: 20), //spacing size between each field
          ElevatedButton(
            style: style,
            onPressed: () => startGame(context),
            child: const Text('Play'),
          ),
          ColorPicker(),
        ],
      ),
    );
  }
}
