import 'dart:async';
import 'dart:convert';
import 'dart:io';
import 'dart:math';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:flutter_tts/flutter_tts.dart';
import 'package:permission_handler/permission_handler.dart';
import 'package:speech_to_text/speech_recognition_error.dart';
import 'package:speech_to_text/speech_recognition_result.dart';
import 'package:speech_to_text/speech_to_text.dart';
import '../Services/RemoteData.dart';
import 'Constants.dart';
//780103940

class SpeechSampleApp extends StatefulWidget {
  const SpeechSampleApp({Key? key}) : super(key: key);
  @override
  State<SpeechSampleApp> createState() => _SpeechSampleAppState();
}

/// An example that demonstrates the basic functionality of the
/// SpeechToText plugin for using the speech recognition capability
/// of the underlying platform.

class _SpeechSampleAppState extends State<SpeechSampleApp> {
  bool _hasSpeech = false;
  final bool _logEvents = false;
  final bool _onDevice = false;
  final FlutterTts ftts = FlutterTts();
  final TextEditingController _pauseForController =
      TextEditingController(text: '5');
  final TextEditingController _listenForController =
      TextEditingController(text: '30');
  double level = 0.0;
  double minSoundLevel = 50000;
  double maxSoundLevel = -50000;
  String lastWords = '';
  String lastError = '';
  String lastStatus = '';
  String _currentLocaleId = '';
  SpeechToText speech = SpeechToText();
  List<Data>? data = [];
  String femalevoice = "cmn-CN-Standard-A";
  String malevoice = "cmn-CN-Standard-B";

  @override
  void initState() {
    initSpeechState();
    if (Platform.isAndroid) {
      checkAndRequestMicrophonePermission();
    }
    if (Platform.isIOS) {
      // iOS needs to wait until the widget is shown before requesting permission
    }
    super.initState();
  }

  Future<void> checkAndRequestMicrophonePermission() async {
    PermissionStatus status = await Permission.microphone.status;
    if (status.isGranted) {
      if (kDebugMode) {
        print('Microphone permission is granted.');
      }
    } else {
      status = await Permission.microphone.request();
      if (status.isGranted) {
        if (kDebugMode) {
          print('Microphone permission is granted.');
        }
      } else {
        if (kDebugMode) {
          print('Microphone permission is denied.');
        }
      }
    }
  }

  /// This initializes SpeechToText.That only has to be done
  /// once per application,though calling it again is harmless
  /// it also does nothing.The UX of the sample app ensures that
  /// it can only be called once.
  Future<void> initSpeechState() async {
    _logEvent('Initialize');
    try {
      var hasSpeech = await speech.initialize(
        onError: errorListener,
        onStatus: statusListener,
        debugLogging: _logEvents,
      );
      if (hasSpeech) {
        var systemLocale = await speech.systemLocale();
        _currentLocaleId = systemLocale?.localeId ?? '';
      }
      if (!mounted) return;
      setState(() {
        _hasSpeech = hasSpeech;
      });
    } catch (e) {
      setState(() {
        lastError = 'Speech recognition failed: ${e.toString()}';
        _hasSpeech = false;
      });
    }
  }

  @override
  Widget build(BuildContext context) {
    return Scaffold(
      appBar: AppBar(
        leading: IconButton(
            icon: Image.asset(
              "assets/images/back_arrow.png",
              width: 24,
              height: 24,
              color: Colors.white,
            ),
            //color: Colors.white,
            onPressed: () {
              Navigator.pop(context);
              data!.clear();
            }),
        title: const Text(
          'Speech to Text / Text to Speech',
          style: Constants.fontStyle,
        ),
        flexibleSpace: Container(
          decoration: BoxDecoration(
            gradient: Constants.getReturn(),
          ),
        ),
      ),
      body: Column(children: [
        //const HeaderWidget(),
        Column(
          children: <Widget>[
            // InitSpeechWidget(_hasSpeech, initSpeechState),
            SpeechControlWidget(
                lastWords,
                level,
                _hasSpeech,
                speech.isListening,
                startListening,
                stopListening,
                cancelListening),
            // SessionOptionsWidget(
            //   _currentLocaleId,
            //   _switchLang,
            //   _localeNames,
            //   _logEvents,
            //   _switchLogging,
            //   _pauseForController,
            //   _listenForController,
            //   _onDevice,
            //   _switchOnDevice,
            // ),
          ],
        ),

        // Expanded(
        //   flex: 4,
        //   child: RecognitionResultsWidget(lastWords: lastWords, level: level),
        // ),
        // Expanded(
        //   flex: 1,
        //   child: ErrorWidget(lastError: lastError),
        // ),
        //SpeechStatusWidget(speech: speech),
      ]),
    );
  }

  // This is called each time the users wants to start a new speech
  // recognition session

  void startListening() {
    _logEvent('start listening');
    lastWords = '';
    lastError = '';
    final pauseFor = int.tryParse(_pauseForController.text);
    final listenFor = int.tryParse(_listenForController.text);
    final options = SpeechListenOptions(
        onDevice: _onDevice,
        listenMode: ListenMode.confirmation,
        cancelOnError: true,
        partialResults: true,
        autoPunctuation: true,
        enableHapticFeedback: true);
    // Note that `listenFor` is the maximum, not the minimum, on some
    // systems recognition will be stopped before this value is reached.
    // Similarly `pauseFor` is a maximum not a minimum and may be ignored
    // on some devices.
    speech.listen(
      onResult: resultListener,
      listenFor: Duration(seconds: listenFor ?? 30),
      pauseFor: Duration(seconds: pauseFor ?? 3),
      localeId: _currentLocaleId,
      onSoundLevelChange: soundLevelListener,
      listenOptions: options,
    );
    setState(() {});
  }

  void stopListening() {
    _logEvent('stop');
    speech.stop();
    setState(() {
      level = 0.0;
    });
  }

  void cancelListening() {
    _logEvent('cancel');
    speech.cancel();
    setState(() {
      level = 0.0;
    });
  }

  // This callback is invoked each time new recognition results are
  // available after `listen` is called.
  void resultListener(SpeechRecognitionResult result) {
    _logEvent(
        'Result listener final: ${result.finalResult}, words: ${result.recognizedWords}');
    setState(() async {
      //lastWords = '${result.recognizedWords} - ${result.finalResult}';
      lastWords = result.recognizedWords;
      if (result.finalResult) {
        if (kDebugMode) {
          print('Final Result: $lastWords');
        }
        // Data dataInstance =  Data(question: lastWords, answer: 'Hello This is Ramesh');
        // await ftts.setLanguage("en-IN");
        // await ftts.setSpeechRate(0.4); //speed of speech
        // await ftts.setVolume(1.0); //volume of speech
        // await ftts.setPitch(2.0); //pitc of sound
        // List<dynamic> languages = await ftts.getLanguages;
        // if (kDebugMode) {
        //   print(languages);
        // }
        //print(voices);
        // print(reference);
        //await ftts.setVoice(reference);
        // var voice = await ftts.getDefaultVoice;
        // print(voice);
        //{locale: en-IN, quality: default, gender: male, name: Rishi, identifier: com.apple.voice.compact.en-IN.Rishi}
        //await ftts.setVoice({"name": "en-in-x-ene-network", "locale": "en-IN"});
        //play text to sp
        // var result = await ftts.speak('Welcome to World ');
        // if (kDebugMode) {
        //   print(result);
        // }
        // data!.add(dataInstance);
        // List<dynamic> language = await ftts.getLanguages;
        // if (kDebugMode) {
        //   print(language);
        // } // In
        // for (final languags in language) {
        //   if (kDebugMode) {
        //     print(languags);
        //   }
        // }

        String res = await RemoteData().getVoiceResponse(File(lastWords), '');
        //var response = jsonDecode(res);
        Map<String, dynamic> jsonResponse = jsonDecode(res);
        //List<dynamic> output1 = jsonResponse['output1'];
        if (kDebugMode) {
          print('DataFetching $jsonResponse');
        }
        if (jsonResponse['output1'].isNotEmpty) {
          //Map<String, dynamic> firstItem = output1[0];
          String zoneValue = jsonResponse['output1'];
          if (kDebugMode) {
            print('DataFetching1 $zoneValue');
          }
          Data dataInstance =
              Data(question: lastWords, answer: zoneValue, image: 'None');
          await ftts.setLanguage("en-IN");
          await ftts.setSpeechRate(0.5); //speed of speech
          await ftts.setVolume(1.0); //volume of speech
          await ftts.setPitch(2.0); //pitc of sound
          List<dynamic> voices = await ftts.getVoices;
          for (final voice in voices) {
            if (kDebugMode) {
              print(voice);
            }
          }
          //Map<String, String> reference = {'setVoice': malevoice};
          if (Platform.isIOS) {
            await ftts.setVoice({"name": "Rishi", "locale": "en-IN"});
            //await ftts.setIosAudioCategory(
            //IosTextToSpeechAudioCategory.playAndRecord,
            //[IosTextToSpeechAudioCategoryOptions.defaultToSpeaker],);
            await ftts.setIosAudioCategory(
                IosTextToSpeechAudioCategory.playback,
                [IosTextToSpeechAudioCategoryOptions.allowBluetooth,
                 IosTextToSpeechAudioCategoryOptions.allowBluetoothA2DP,
                 IosTextToSpeechAudioCategoryOptions.mixWithOthers,
                 IosTextToSpeechAudioCategoryOptions.defaultToSpeaker],
                IosTextToSpeechAudioMode.defaultMode);
          } else {
            await ftts.setVoice({"name": "en-in-x-ene-local", "locale": "en-IN"});
          }
          //await ftts.setVoice(reference);
          //play text to sp
          var result = await ftts.speak(zoneValue);
          if (kDebugMode) {
            print(result);
          }
          if (result == 1) {
            if (kDebugMode) {
              print("Flutter Campus speaking...");
            }
          } else {
            if (kDebugMode) {
              print("Flutter Campus not speaking...");
            }
          }
          if (kDebugMode) {
            print("ZONE value: $zoneValue");
          }
          data!.add(dataInstance);
        } else {
          if (kDebugMode) {
            print("No items in 'output1'");
          }
        }
        if (kDebugMode) {
          print('Speech Text Resposne =====>$res');
        }
        // Create a list to hold instances of Data
        //List<Data> dataList = [];
        // Add the instance to the list
        SpeechControlWidget.UpdateList(data!);
        setState(() {
          data = data;
        });
        lastWords = '';
        setState(() {});
      }
    });
  }

  void soundLevelListener(double level) {
    minSoundLevel = min(minSoundLevel, level);
    maxSoundLevel = max(maxSoundLevel, level);
    // _logEvent('sound level $level: $minSoundLevel - $maxSoundLevel ');
    setState(() {
      this.level = level;
    });
  }

  void errorListener(SpeechRecognitionError error) {
    _logEvent(
        'Received error status: $error, listening: ${speech.isListening}');
    setState(() {
      lastError = '${error.errorMsg} - ${error.permanent}';
    });
  }

  void statusListener(String status) {
    _logEvent(
        'Received listener status: $status, listening: ${speech.isListening}');
    setState(() {
      lastStatus = status;
    });
  }

  //void _switchLang(selectedVal){
  // setState((){
  //  _currentLocaleId = selectedVal;
  // });
  // debugPrint(selectedVal);
  //}

  void _logEvent(String eventDescription) {
    if (_logEvents) {
      var eventTime = DateTime.now().toIso8601String();
      debugPrint('$eventTime $eventDescription');
    }
  }
  //void _switchLogging(bool? val){
  // setState(() {
  //  _logEvents = val ?? false;
  // });
  //}
  // void _switchOnDevice(bool? val) {
  //   setState(() {
  //     _onDevice = val ?? false;
  //   });
  // }'
}

/// Displays the most recently recognized words and the sound level.
class RecognitionResultsWidget extends StatelessWidget {
  const RecognitionResultsWidget({
    Key? key,
    required this.lastWords,
    required this.level,
  }) : super(key: key);

  final String lastWords;
  final double level;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        const Center(
          child: Text(
            'Recognized Words',
            style: TextStyle(fontSize: 22.0),
          ),
        ),
        Expanded(
          child: Stack(
            children: <Widget>[
              Container(
                color: Theme.of(context).secondaryHeaderColor,
                child: Center(
                  child: Text(
                    lastWords,
                    textAlign: TextAlign.start,
                    style: Constants.LoginfontStyle,
                  ),
                ),
              ),
              Positioned.fill(
                bottom: 10,
                child: Align(
                  alignment: Alignment.bottomCenter,
                  child: Container(
                    width: 40,
                    height: 40,
                    alignment: Alignment.center,
                    decoration: BoxDecoration(
                      boxShadow: [
                        BoxShadow(
                            blurRadius: .26,
                            spreadRadius: level * 1.5,
                            color: Colors.black.withOpacity(.05))
                      ],
                      color: Colors.white,
                      borderRadius: const BorderRadius.all(Radius.circular(50)),
                    ),
                    child: IconButton(
                      icon: const Icon(Icons.mic),
                      onPressed: () {},
                    ),
                  ),
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }
}

class HeaderWidget extends StatelessWidget {
  const HeaderWidget({
    Key? key,
  }) : super(key: key);

  @override
  Widget build(BuildContext context) {
    return const Center(
      child: Text(
        'Speech recognition available',
        style: TextStyle(fontSize: 22.0),
      ),
    );
  }
}

/// Display the current error status from the speech
/// recognizer
class ErrorWidget extends StatelessWidget {
  const ErrorWidget({
    Key? key,
    required this.lastError,
  }) : super(key: key);

  final String lastError;

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        const Center(
          child: Text(
            'Error Status',
            style: TextStyle(fontSize: 22.0),
          ),
        ),
        Center(
          child: Text(lastError),
        ),
      ],
    );
  }
}

/// Controls to start and stop speech recognition
class SpeechControlWidget extends StatelessWidget {
  // final List<Data>? datalist;
  // SpeechControlWidget.withListeners({Key? key, this.datalist}) : super(key: key);
  SpeechControlWidget(this.total, this.level, this.hasSpeech, this.isListening,
      this.startListening, this.stopListening, this.cancelListening,
      {Key? key})
      : super(key: key);

  final double level;
  final String total;
  final bool hasSpeech;
  final bool isListening;
  final void Function() startListening;
  final void Function() stopListening;
  final void Function() cancelListening;
  static List<Data>? data1 = [];
  final TextStyle _textFieldStyle = Constants.LoginbuttonsfontStyle;

  //final TextEditingController _dateTime = TextEditingController();

  @override
  Widget build(BuildContext context) {
    return Column(
      children: <Widget>[
        Column(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: <Widget>[
            SizedBox(
              height: MediaQuery.of(context).size.height * 0.80,
              child: Container(
                decoration: BoxDecoration(
                  color: const Color.fromARGB(255, 255, 255, 255),
                  border: Border.all(
                    style: BorderStyle.solid,
                    color: const Color.fromARGB(255, 255, 255, 255),
                  ),
                  borderRadius: BorderRadius.circular(0),
                ),
                child: Column(
                  children: [
                    Expanded(
                      child: ListView.builder(
                        itemCount: data1?.length,
                        itemBuilder: (context, index) {
                          //String answer = data1![index].answer;
                          Widget content = Text(
                            data1![index].answer,
                            style: Constants.LoginbuttonsfontStyle,
                            overflow: TextOverflow.ellipsis,
                            textAlign: TextAlign.left,
                            maxLines: 20,
                          );

                          if (data1![index].image != 'None') {
                            Uint8List imageBytes =
                                base64Decode(data1![index].image);
                            content = Image.memory(
                              imageBytes,
                              fit: BoxFit.cover,
                              height: 100, // Adjust height as needed
                              width: 100, // Adjust width as needed
                            );
                          }
                          return Padding(
                            padding: const EdgeInsets.fromLTRB(15, 5, 15, 5),
                            child: SizedBox(
                              width: MediaQuery.of(context).size.width / 1,
                              // Add padding as needed
                              child: Column(
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                  Container(
                                    decoration: BoxDecoration(
                                      color: const Color.fromARGB(
                                          255, 238, 177, 64),
                                      borderRadius: BorderRadius.circular(
                                          20), // Adjust the value as needed
                                    ),
                                    padding: const EdgeInsets.all(8.0),
                                    child: Row(
                                      mainAxisAlignment: MainAxisAlignment.end,
                                      children: [
                                        Expanded(
                                          child: Text(
                                            style: Constants.speeachfontStyle,
                                            data1![index].question,
                                            textAlign: TextAlign.right,
                                            softWrap: true,
                                            maxLines: 4,
                                          ),
                                        ),
                                      ],
                                    ),
                                  ),
                                  const SizedBox(
                                    height: 10,
                                  ),
                                  Container(
                                    decoration: BoxDecoration(
                                      color: const Color.fromARGB(
                                          255, 239, 242, 247),
                                      borderRadius: BorderRadius.circular(
                                          20), // Adjust the value as needed
                                    ),
                                    // Set your desired background color here
                                    padding: const EdgeInsets.all(8.0),
                                    child: Row(
                                      mainAxisAlignment:
                                          MainAxisAlignment.start,
                                      children: [
                                        Expanded(child: content
                                            // child: Text(
                                            //   style:
                                            //       Constants.LoginbuttonsfontStyle,
                                            //   data1![index].answer,
                                            //   overflow: TextOverflow.ellipsis,
                                            //   textAlign: TextAlign.left,
                                            //   maxLines: 20,
                                            // ),
                                            ),
                                      ],
                                    ),
                                  ),
                                ],
                              ),
                            ),
                          );
                        },
                      ),
                    ),
                  ],
                ),
              ),
            ),
            TextFormField(
              // style: Constants.Titletextstyle,
              // enabled: false,
              readOnly: true,
              controller: TextEditingController(
                text: total,
              ),
              onTap: () {},
              decoration: InputDecoration(
                // border: Border.all(color: Colors.grey),
                filled: true,
                fillColor: const Color.fromARGB(255, 250, 248, 248),
                contentPadding:
                    const EdgeInsets.symmetric(vertical: 15, horizontal: 10),
                isDense: true,
                hintText: '',
                border: OutlineInputBorder(
                  borderSide: const BorderSide(color: Colors.grey, width: 0.0),
                  borderRadius: BorderRadius.circular(2.0),
                ),
                suffixIcon: IconButton(
                  icon: Icon(isListening ? Icons.mic : Icons.mic_none),
                  color: isListening ? Colors.green : Colors.grey,
                  onPressed: () {
                    startListening();
                    //widget.total
                    //total = '';
                  },
                ),
              ),
              style: _textFieldStyle,
            ),
          ],
        ),
      ],
    );
  }

  static UpdateList(List<Data> dataList) {
    // setState(() {
    //   data = dataList;
    // });
    data1 = dataList;
    print(dataList);
    //data = dataList;
  }
}

class Data {
  String question = ''; // Use camelCase for variable names
  String answer = ''; // Use camelCase for variable names
  String image = '';
  // Constructor
  Data({required this.question, required this.answer, required this.image});
  // Named constructor for creating an instance from a Map
  Data.fromMap(Map<String, dynamic> map)
      : question = map['Question'] ?? '',
        answer = map['Answer'] ?? '',
        image = map['Image'] ?? '';

  // Convert the object to a Map
  Map<String, dynamic> toMap() {
    return {
      'Question': question,
      'Answer': answer,
      'Image': image,
    };
  }
}

class InitSpeechWidget extends StatelessWidget {
  const InitSpeechWidget(this.hasSpeech, this.initSpeechState, {Key? key})
      : super(key: key);
  final bool hasSpeech;
  final Future<void> Function() initSpeechState;

  @override
  Widget build(BuildContext context) {
    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceAround,
      children: <Widget>[
        TextButton(
          onPressed: hasSpeech ? null : initSpeechState,
          child: const Text('Initialize ...'),
        ),
      ],
    );
  }
}

class SpeechStatusWidget extends StatelessWidget {
  const SpeechStatusWidget({
    Key? key,
    required this.speech,
  }) : super(key: key);

  final SpeechToText speech;

  @override
  Widget build(BuildContext context) {
    return Container(
      padding: const EdgeInsets.symmetric(vertical: 20),
      color: Theme.of(context).colorScheme.background,
      child: Center(
        child: speech.isListening
            ? const Text(
                "I'm listening...",
                style: TextStyle(fontWeight: FontWeight.bold),
              )
            : const Text(
                'Not listening',
                style: TextStyle(fontWeight: FontWeight.bold),
              ),
      ),
    );
  }
}
