import 'dart:convert';
import 'dart:io';
import 'dart:isolate';
import 'dart:ui';
import 'package:flutter_downloader/flutter_downloader.dart';
import 'package:http/http.dart' as http;

import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:fluttertoast/fluttertoast.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:path_provider/path_provider.dart';
import 'package:quiosco_soler_2/memorias_calculo/pages/interfaz_cuadricula_page.dart';
import 'package:quiosco_soler_2/memorias_calculo/providers/pdf_provider.dart';

import '../widgets/cubo.dart';
import '../widgets/encabezado_pais.dart';
import '../widgets/formatters.dart';

class CalculadoraAmbientalPage extends StatefulWidget {
  final String pais;
  final String code;
  final String idProyecto;
  final String idUsuario;
  final String token;
  final String datos;
  final String noProyecto;
  final String archpdf;

  const CalculadoraAmbientalPage({
    Key? key,
    required this.pais,
    required this.code,
    required this.idProyecto,
    required this.idUsuario,
    required this.token,
    required this.datos,
    required this.noProyecto,
    required this.archpdf
  }) : super(key: key);

  @override
  State<CalculadoraAmbientalPage> createState() => _CalculadoraAmbientalPageState();
}

class _CalculadoraAmbientalPageState extends State<CalculadoraAmbientalPage> {
  final GlobalKey<ScaffoldState> _scaffoldKey = GlobalKey<ScaffoldState>();
  final TextEditingController _largoController = TextEditingController(text: "0.00");
  final TextEditingController _anchoController = TextEditingController(text: "0.00");
  final TextEditingController _altoController = TextEditingController(text: "0.00");
  final TextEditingController _equiposController = TextEditingController(text: "0");
  final Map<String, Map<String, double>> _aplicaciones = {};
  final _pdfProvider = PDFProvider();

  bool _isLoading = true;
  double _valLargo = 0.0;
  double _valAncho = 0.0;
  double _valAlto = 0.0;
  double _valVolumen = 0.0;
  double _valCaudalCFM = 0.0;
  double _valCaudalM3H = 0.0;
  double _valCaudalEquiCFM = 0.0;
  double _valCaudalEquiM3H = 0.0;
  double _valCambios = 0;
  int _valCamMin = 0;
  int _valEquipos = 0;
  String _pais = "";
  String _code = "";
  String _cambiosPorHora = "";
  String _aplicacion = "";
  String _unidadAltura = "m";
  String _unidadVolumen = "m³";

  static const List<String> _unidadesAltura = ["m", "ft"];
  static const List<String> _unidadesVolumen = ["m³", "ft³"];
  static const Map<String, String> _rangos = {
    "MIN": "Mínimo",
    "MED": "Medio",
    "MAX": "Máximo",
  };

  late String _localPath;
  final ReceivePort _port = ReceivePort();
  List<TaskInfo>? _tasks;

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

    FlutterDownloader.registerCallback(downloadCallback);

    _pais = widget.pais;
    _code = widget.code;

    _init();
  }

  void _init() async{
    final aplicacionesStr = await rootBundle.loadString('assets/renovaciones.json');
    final aplicacionesArr = await jsonDecode(aplicacionesStr);

    aplicacionesArr.forEach((k0, v0){
      _aplicaciones[k0] = {};
      v0.forEach((k1, v1){
        _aplicaciones[k0]![k1] = v1;
      });
    });

    if(widget.datos.isEmpty){
      setState(() => _isLoading = false);
    }else{
      final datosDec = utf8.decode(base64.decode(widget.datos));
      final datosArr = jsonDecode(datosDec);

      _valLargo = datosArr['largo'].runtimeType != double ? double.parse("${datosArr['largo']}") : datosArr['largo'];
      _largoController.text = "$_valLargo";

      _valAncho = datosArr['ancho'].runtimeType != double ? double.parse("${datosArr['ancho']}") : datosArr['ancho'];
      _anchoController.text = "$_valAncho";

      _valAlto = datosArr['alto'].runtimeType != double ? double.parse("${datosArr['alto']}") : datosArr['alto'];
      _altoController.text = "$_valAlto";

      _unidadAltura = datosArr['unidadLargo'].runtimeType != String ? "${datosArr['unidadLargo']}" : datosArr['unidadLargo'];
      _valVolumen = datosArr['volumen'].runtimeType != double ? double.parse("${datosArr['volumen']}") : datosArr['volumen'];
      _unidadVolumen = datosArr['unidadVolumen'].runtimeType != String ? "${datosArr['unidadVolumen']}" : datosArr['unidadVolumen'];
      _aplicacion = datosArr['aplicacion'].runtimeType != String ? "${datosArr['aplicacion']}" : datosArr['aplicacion'];

      if(datosArr['cambiosPorHora'].isEmpty){
        setState(() => _isLoading = false);
      }else{
        _cambiosPorHora = datosArr['cambiosPorHora'].runtimeType != String ? "${datosArr['cambiosPorHora']}" : datosArr['cambiosPorHora'];
        _valCambios = datosArr['cambios'].runtimeType != double ? double.parse("${datosArr['cambios']}") : datosArr['cambios'];
        _valCamMin = datosArr['cambiosMinutos'].runtimeType != int ? int.parse("${datosArr['cambiosMinutos']}") : datosArr['cambiosMinutos'];
        _valCaudalM3H = datosArr['caudalM3H'].runtimeType != double ? double.parse("${datosArr['caudalM3H']}") : datosArr['caudalM3H'];
        _valCaudalCFM = datosArr['caudalCFM'].runtimeType != double ? double.parse("${datosArr['caudalCFM']}") : datosArr['caudalCFM'];

        _valEquipos = datosArr['equiposRequeridos'].runtimeType != int ? int.parse("${datosArr['equiposRequeridos']}") : datosArr['equiposRequeridos'];
        _equiposController.text = "$_valEquipos";

        if(_valEquipos == 0){
          setState(() => _isLoading = false);
        }else{
          _valCaudalEquiM3H = datosArr['caudalEquiM3H'].runtimeType != double ? double.parse("${datosArr['caudalEquiM3H']}") : datosArr['caudalEquiM3H'];
          _valCaudalEquiCFM = datosArr['caudalEquiCFM'].runtimeType != double ? double.parse("${datosArr['caudalEquiCFM']}") : datosArr['caudalEquiCFM'];

          setState(() => _isLoading = false);
        }
      }
    }
  }

  Future<bool> _cambiarDatos(String datos, String archPDF, String status) async{
    final url = Uri.https("smart.solerpalau.mx", "PR/api/v1/quiosco/matrizMemoriasCalculo/actualizarProyecto");
    final res = await http.post(url,
      headers: {
        "Authorization": "Bearer ${widget.token}"
      },
      body: {
        "IDUSUARIO": widget.idUsuario,
        "IDPROYECTO": widget.idProyecto,
        "FMODIF": DateTime.now().toIso8601String().substring(0, 19),
        "ESTATUS": status,
        "DATOS": base64Encode(utf8.encode(datos)),
        "ARCHPDF" : archPDF
      },
    );

    final decoded = jsonDecode(res.body);
    return decoded['response'];
  }

  void _requestDownload(TaskInfo task) async{
    task.taskId = await FlutterDownloader.enqueue(
      url: task.link!,
      savedDir: _localPath,
      showNotification: true,
      openFileFromNotification: true,
      saveInPublicStorage: true,
    );
  }

  Future<void> _prepareSaveDir() async{
    _localPath = (await _findLocalPath())!;
    final savedDir = Directory(_localPath);
    bool hasExisted = await savedDir.exists();
    if (!hasExisted) {
      savedDir.create();
    }
  }

  Future<String?> _findLocalPath() async{
    String externalStorageDirPath;
    if(Platform.isAndroid){
      final directory = await getExternalStorageDirectory();
      externalStorageDirPath = directory!.path;
    }else{
      final directory = await getApplicationDocumentsDirectory();
      externalStorageDirPath = directory.path;
    }

    return externalStorageDirPath;
  }

  void _bindBackgroundIsolate(){
    bool isSuccess = IsolateNameServer.registerPortWithName(_port.sendPort, 'downloader_send_port');

    if(!isSuccess){
      _unbindBackgroundIsolate();
      _bindBackgroundIsolate();
      return;
    }

    _port.listen((data) {
      print('UI Isolate Callback: $data');
      String? id = data[0];
      DownloadTaskStatus? status = data [1];
      int? progress = data[2];

      if(_tasks != null && _tasks!.isNotEmpty){
        final task = _tasks!.firstWhere((task) => task.taskId == id);
        setState(() {
          task.status = status;
          task.progress = progress;
        });
      }
    });
  }

  void _unbindBackgroundIsolate() {
    IsolateNameServer.removePortNameMapping('downloader_send_port');
  }

  static void downloadCallback(String id, DownloadTaskStatus status, int progress){
    print("Task $id: status: $status, progress: $progress");
    final SendPort send = IsolateNameServer.lookupPortByName('downloader_send_port')!;
    send.send([id, status, progress]);
  }

  @override
  Widget build(BuildContext context) {
    final _screenSize = MediaQuery.of(context).size;
    return Scaffold(
      key: _scaffoldKey,
      body: _isLoading ? const Center(
        child: CircularProgressIndicator(),
      ) : SafeArea(
        child: SingleChildScrollView(
          child: Column(
            children: [
              const SizedBox(height: 8.0),
              Container(
                margin: const EdgeInsets.symmetric(
                  horizontal: 32.0,
                ),
                child: Row(
                  children: [
                    TextButton(
                      child: Text(
                        "Memoria de cálculo de ...",
                        style: GoogleFonts.roboto(
                          fontSize: 16.0,
                          fontWeight: FontWeight.bold,
                          fontStyle: FontStyle.italic,
                        ),
                      ),
                      onPressed: () async{
                        final accion = await showDialog(
                          context: context,
                          barrierDismissible: false,
                          builder: (context) => AlertDialog(
                            title: Text(
                              "Salir sin guardar",
                              textAlign: TextAlign.center,
                              style: GoogleFonts.roboto(
                                fontWeight: FontWeight.bold,
                                fontSize: 20.0,
                                color: Colors.black87,
                              ),
                            ),
                            content: Text(
                              "¿Está seguro de salir sin guardar los cambios?",
                              textAlign: TextAlign.center,
                              style: GoogleFonts.roboto(
                                fontSize: 16.0,
                              ),
                            ),
                            actions: [
                              TextButton(
                                child: const Text("Salir sin guardar"),
                                onPressed: () => Navigator.pop(context, "salir"),
                              ),
                              TextButton(
                                child: const Text("Guardar y salir"),
                                onPressed: () => Navigator.pop(context, "guardar"),
                              ),
                              TextButton(
                                child: const Text("Cancelar"),
                                onPressed: () => Navigator.pop(context, "cancelar"),
                              )
                            ],
                          ),
                        );

                        if(accion == "salir"){
                          Navigator.pop(context);
                        }else if(accion == "guardar"){
                          final info = {
                            "largo": "$_valLargo",
                            "ancho": "$_valAncho",
                            "alto": "$_valAlto",
                            "unidadLargo": _unidadAltura,
                            "volumen": "$_valVolumen",
                            "unidadVolumen": _unidadVolumen,
                            "aplicacion": _aplicacion,
                            "cambiosPorHora": _cambiosPorHora,
                            "cambios": "$_valCambios",
                            "cambiosMinutos": "$_valCamMin",
                            "caudalM3H": "$_valCaudalM3H",
                            "caudalCFM": "$_valCaudalCFM",
                            "equiposRequeridos": "$_valEquipos",
                            "caudalEquiM3H": "$_valCaudalEquiM3H",
                            "caudalEquiCFM": "$_valCaudalEquiCFM"
                          };
                          final infoStr = jsonEncode(info);

                          final guardado = await _cambiarDatos(infoStr, "", _valEquipos > 0 ? "F" : "C");
                          if(guardado){
                            Navigator.pop(context);
                          }else{
                            Fluttertoast.showToast(
                              msg: "Hubo un error al intentar guardar el proyecto, intentelo de nuevo más tarde.",
                              toastLength: Toast.LENGTH_SHORT,
                              timeInSecForIosWeb: 4,
                              gravity: ToastGravity.CENTER,
                              webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
                            );
                          }
                        }
                      },
                      style: TextButton.styleFrom(
                        padding: const EdgeInsets.fromLTRB(0, 0, 8.0, 0),
                        minimumSize: const Size(0, 0),
                        tapTargetSize: MaterialTapTargetSize.shrinkWrap,
                      ),
                    ),
                    const SizedBox(width: 8.0),
                    Expanded(
                      child: Container(
                        padding: const EdgeInsets.fromLTRB(0, 0, 8.0, 0),
                        child: RichText(
                          maxLines: 1,
                          overflow: TextOverflow.ellipsis,
                          text: TextSpan(
                            style: GoogleFonts.roboto(
                              fontSize: 16.0,
                              color: Colors.black54,
                              fontWeight: FontWeight.bold,
                              fontStyle: FontStyle.italic,
                            ),
                            children: [
                              TextSpan(
                                text: ">  ",
                                style: GoogleFonts.roboto(
                                  fontSize: 16.0,
                                  color: const Color(0xFFB40404),
                                  fontWeight: FontWeight.bold,
                                  fontStyle: FontStyle.italic,
                                ),
                              ),
                              const TextSpan(text: "Extracción en estacionamientos cerrados"),
                            ],
                          ),
                        ),
                      ),
                    )
                  ],
                ),
              ),
              const SizedBox(height: 8.0),
              EncabezadoPais(paisCode: _code, paisName: _pais),
              const SizedBox(height: 32.0),
              Image.asset(
                "assets/1.png",
                width: 88.0,
              ),
              const SizedBox(height: 16.0),
              Container(
                width: double.infinity,
                padding: const EdgeInsets.symmetric(
                  horizontal: 32.0,
                ),
                child: Text(
                  "Extracción ambiental".toUpperCase(),
                  textAlign: TextAlign.center,
                  style: const TextStyle(
                    fontFamily: "Helvetica Neue Black Cond",
                    fontSize: 28.0,
                  ),
                ),
              ),
              const SizedBox(height: 8.0),
              Container(
                padding: const EdgeInsets.symmetric(horizontal: 32.0),
                width: double.infinity,
                child: const Text(
                  "Por favor ingresa los datos requeridos para el cálculo ambiental.",
                  textAlign: TextAlign.center,
                  style: TextStyle(
                    fontFamily: "Helvetica Neue Light",
                    fontSize: 22.0,
                    fontWeight: FontWeight.w600,
                    color: Color.fromRGBO(104, 104, 104, 1),
                  ),
                ),
              ),
              const SizedBox(height: 32.0),
              Container(
                margin: const EdgeInsets.symmetric(
                  horizontal: 32.0,
                ),
                child: Row(
                  children: [
                    Text(
                      'Largo (l):',
                      style: GoogleFonts.roboto(
                        fontWeight: FontWeight.bold,
                        fontSize: 18.0,
                      ),
                    ),
                    const SizedBox(width: 8.0),
                    Expanded(
                      child: SizedBox(
                        height: 64.0,
                        width: double.infinity,
                        child: Stack(
                          alignment: Alignment.center,
                          children: [
                            TextField(
                              textAlign: TextAlign.center,
                              controller: _largoController,
                              maxLength: 10,
                              decoration: const InputDecoration(
                                counterText: "",
                                counterStyle: TextStyle(
                                  height: double.minPositive,
                                ),
                              ),
                              inputFormatters: [
                                DecimalTextInputFormatter()
                              ],
                              onChanged: (val) => setState(() {
                                if(val.isEmpty){
                                  _valLargo = 0;
                                }else{
                                  _valLargo = double.parse(val);
                                }
                                _calcularVolumen();
                              }),
                            ),
                            Positioned(
                              left: 0.0,
                              child: IconButton(
                                icon: const Icon(
                                  Icons.remove,
                                  color: Colors.black45,
                                ),
                                onPressed: () => setState(() {
                                  _valLargo = _valLargo - 0.1;
                                  if(_valLargo < 0){
                                    _valLargo = 0;
                                  }

                                  _largoController.text = _valLargo.toStringAsFixed(2);
                                  _calcularVolumen();
                                }) ,
                              ),
                            ),
                            Positioned(
                              right: 0.0,
                              child: IconButton(
                                icon: const Icon(
                                  Icons.add,
                                  color: Colors.black45,
                                ),
                                onPressed: () => setState(() {
                                  _valLargo = _valLargo + 0.1;
                                  if(_valLargo > 9999){
                                    _valLargo = 9999;
                                  }

                                  _largoController.text = _valLargo.toStringAsFixed(2);
                                  _calcularVolumen();
                                }),
                              ),
                            )
                          ],
                        ),
                      ),
                    ),
                    const SizedBox(width: 8.0),
                    DropdownButton<String>(
                      focusColor: Colors.transparent,
                      value: _unidadAltura,
                      onChanged: (value) => setState(() {
                        _unidadAltura = value!;
                        _calcularVolumen();
                      }),
                      items: _unidadesAltura.map((e) => DropdownMenuItem<String>(
                        child: Text(
                          e,
                          style: GoogleFonts.roboto(
                            fontSize: 18.0,
                          ),
                        ),
                        value: e,
                      )).toList(),
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 16.0),
              Container(
                margin: const EdgeInsets.symmetric(
                  horizontal: 32.0,
                ),
                child: Row(
                  children: [
                    Text(
                      'Ancho (a):',
                      style: GoogleFonts.roboto(
                        fontWeight: FontWeight.bold,
                        fontSize: 18.0,
                      ),
                    ),
                    const SizedBox(width: 8.0),
                    Expanded(
                      child: SizedBox(
                        height: 64.0,
                        width: double.infinity,
                        child: Stack(
                          alignment: Alignment.center,
                          children: [
                            TextField(
                              textAlign: TextAlign.center,
                              controller: _anchoController,
                              maxLength: 10,
                              decoration: const InputDecoration(
                                counterText: "",
                                counterStyle: TextStyle(
                                  height: double.minPositive,
                                ),
                              ),
                              inputFormatters: [
                                DecimalTextInputFormatter()
                              ],
                              onChanged: (val) => setState(() {
                                if(val.isEmpty){
                                  _valAncho = 0;
                                }else{
                                  _valAncho = double.parse(val);
                                }
                                _calcularVolumen();
                              }),
                            ),
                            Positioned(
                              left: 0.0,
                              child: IconButton(
                                icon: const Icon(
                                  Icons.remove,
                                  color: Colors.black45,
                                ),
                                onPressed: () => setState(() {
                                  _valAncho = _valAncho - 0.1;
                                  if(_valAncho < 0){
                                    _valAncho = 0;
                                  }

                                  _anchoController.text = _valAncho.toStringAsFixed(2);
                                  _calcularVolumen();
                                }) ,
                              ),
                            ),
                            Positioned(
                              right: 0.0,
                              child: IconButton(
                                icon: const Icon(
                                  Icons.add,
                                  color: Colors.black45,
                                ),
                                onPressed: () => setState(() {
                                  _valAncho = _valAncho + 0.1;
                                  if(_valAncho > 9999){
                                    _valAncho = 9999;
                                  }

                                  _anchoController.text = _valAncho.toStringAsFixed(2);
                                  _calcularVolumen();
                                }),
                              ),
                            )
                          ],
                        ),
                      ),
                    ),
                    const SizedBox(width: 8.0),
                    Container(
                      child: Text(
                        _unidadAltura,
                        style: GoogleFonts.roboto(
                          fontSize: 18.0,
                        ),
                      ),
                      padding: const EdgeInsets.fromLTRB(0, 0, 24.0, 8.0),
                      decoration: BoxDecoration(
                        border: Border(
                          bottom: BorderSide(
                            color: Colors.black.withOpacity(0.18),
                            width: 2.0,
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 16.0),
              Container(
                margin: const EdgeInsets.symmetric(
                  horizontal: 32.0,
                ),
                child: Row(
                  children: [
                    Text(
                      'Alto (h):',
                      style: GoogleFonts.roboto(
                        fontWeight: FontWeight.bold,
                        fontSize: 18.0,
                      ),
                    ),
                    const SizedBox(width: 8.0),
                    Expanded(
                      child: SizedBox(
                        height: 64.0,
                        width: double.infinity,
                        child: Stack(
                          alignment: Alignment.center,
                          children: [
                            TextField(
                              textAlign: TextAlign.center,
                              controller: _altoController,
                              maxLength: 10,
                              decoration: const InputDecoration(
                                counterText: "",
                                counterStyle: TextStyle(
                                  height: double.minPositive,
                                ),
                              ),
                              inputFormatters: [
                                DecimalTextInputFormatter()
                              ],
                              onChanged: (val) => setState(() {
                                if(val.isEmpty){
                                  _valAlto = 0;
                                }else{
                                  _valAlto = double.parse(val);
                                }
                                _calcularVolumen();
                              }),
                            ),
                            Positioned(
                              left: 0.0,
                              child: IconButton(
                                icon: const Icon(
                                  Icons.remove,
                                  color: Colors.black45,
                                ),
                                onPressed: () => setState(() {
                                  _valAlto = _valAlto - 0.1;
                                  if(_valAlto < 0){
                                    _valAlto = 0;
                                  }

                                  _altoController.text = _valAlto.toStringAsFixed(2);
                                  _calcularVolumen();
                                }) ,
                              ),
                            ),
                            Positioned(
                              right: 0.0,
                              child: IconButton(
                                icon: const Icon(
                                  Icons.add,
                                  color: Colors.black45,
                                ),
                                onPressed: () => setState(() {
                                  _valAlto = _valAlto + 0.1;
                                  if(_valAlto > 9999){
                                    _valAlto = 9999;
                                  }

                                  _altoController.text = _valAlto.toStringAsFixed(2);
                                  _calcularVolumen();
                                }),
                              ),
                            )
                          ],
                        ),
                      ),
                    ),
                    const SizedBox(width: 8.0),
                    Container(
                      child: Text(
                        _unidadAltura,
                        style: GoogleFonts.roboto(
                          fontSize: 18.0,
                        ),
                      ),
                      padding: const EdgeInsets.fromLTRB(0, 0, 24.0, 8.0),
                      decoration: BoxDecoration(
                        border: Border(
                          bottom: BorderSide(
                            color: Colors.black.withOpacity(0.18),
                            width: 2.0,
                          ),
                        ),
                      ),
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 16.0),
              Container(
                margin: const EdgeInsets.symmetric(
                  horizontal: 32.0,
                ),
                child: Row(
                  children: [
                    Text(
                      'Volumen (V):',
                      style: GoogleFonts.roboto(
                        fontWeight: FontWeight.bold,
                        fontSize: 18.0,
                      ),
                    ),
                    const SizedBox(width: 8.0),
                    Expanded(
                      child: Container(
                        child: Text(
                          _formatearNumeros(_valVolumen),
                          textAlign: TextAlign.center,
                          style: GoogleFonts.roboto(
                            fontSize: 16.0,
                          ),
                        ),
                        decoration: const BoxDecoration(
                          border: Border(
                            bottom: BorderSide(
                              width: 2.0,
                              color: Color.fromRGBO(0, 0, 0, 0.2),
                            ),
                          ),
                        ),
                        padding: const EdgeInsets.symmetric(vertical: 16.0),
                      ),
                    ),
                    const SizedBox(width: 8.0),
                    DropdownButton<String>(
                      focusColor: Colors.transparent,
                      value: _unidadVolumen,
                      onChanged: (val) => setState(() {
                        _unidadVolumen = val!;
                        _calcularVolumen();
                      }),
                      items: _unidadesVolumen.map((e) => DropdownMenuItem<String>(
                        child: Text(
                          e,
                          style: GoogleFonts.roboto(
                            fontSize: 18.0,
                          ),
                        ),
                        value: e,
                      )).toList(),
                    )
                  ],
                ),
              ),
              const SizedBox(height: 16.0),
              Cubo(
                largo: _valLargo,
                ancho: _valAncho,
                alto: _valAlto,
                unidad: _unidadAltura,
              ),
              const SizedBox(height: 16.0),
              Container(
                margin: const EdgeInsets.symmetric(
                  horizontal: 32.0,
                ),
                child: Row(
                  children: [
                    Text(
                      'Aplicación:',
                      style: GoogleFonts.roboto(
                        fontWeight: FontWeight.bold,
                        fontSize: 18.0,
                      ),
                    ),
                    const SizedBox(width: 8.0),
                    Expanded(
                      child: DropdownButton<String>(
                        value: _aplicacion.isEmpty ? null : _aplicacion,
                        hint: Text(
                          "Selecciona una opción",
                          style: GoogleFonts.roboto(
                            color: Colors.grey,
                            fontStyle: FontStyle.italic,
                          ),
                        ),
                        isExpanded: true,
                        focusColor: Colors.transparent,
                        itemHeight: 64.0,
                        items: _aplicaciones.keys.map((e) => DropdownMenuItem<String>(
                          value: e,
                          child: Text(
                            e,
                            style: GoogleFonts.roboto(),
                          ),
                        )).toList(),
                        onChanged: (val) => setState(() {
                          _aplicacion = val!;
                          _cambiosPorHora = "";
                          _valCambios = 0.0;
                        }),
                      ),
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 16.0),
              Container(
                margin: const EdgeInsets.symmetric(
                  horizontal: 32.0,
                ),
                child: Column(
                  children: [
                    Text(
                      'Cambios de aire por hora*:',
                      textAlign: TextAlign.left,
                      style: GoogleFonts.roboto(
                        fontWeight: FontWeight.bold,
                        fontSize: 18.0,
                      ),
                    ),
                    const SizedBox(height: 8.0),
                    Row(
                      children: [
                        Expanded(
                          child: DropdownButton<String>(
                            value: _cambiosPorHora.isEmpty ? null : _cambiosPorHora,
                            hint: Text(
                              "Selecciona una opción",
                              style: GoogleFonts.roboto(
                                color: Colors.grey,
                                fontStyle: FontStyle.italic,
                              ),
                            ),
                            disabledHint: Text(
                              "Aún no selecciona una aplicación",
                              style: GoogleFonts.roboto(
                                color: Colors.grey,
                                fontStyle: FontStyle.italic,
                              ),
                            ),
                            isExpanded: true,
                            focusColor: Colors.transparent,
                            items: _aplicacion.isEmpty ? null : ['MIN', 'MED', 'MAX'].map((e) => DropdownMenuItem<String>(
                              value: e,
                              child: Text(
                                _rangos[e]!,
                                style: GoogleFonts.roboto(),
                              ),
                            )).toList(),
                            onChanged: _aplicacion.isEmpty ? null : (val) => setState(() {
                              _cambiosPorHora = val!;
                              _valCambios = _aplicaciones[_aplicacion]![_cambiosPorHora]!;
                              _valCamMin = (60 / _valCambios).round();

                              _calcularCaudal();
                            }),
                          ),
                        ),
                        const SizedBox(width: 8.0),
                        Expanded(
                          child: Container(
                            child: Text(
                              "$_valCambios cambios",
                              textAlign: TextAlign.center,
                              style: GoogleFonts.roboto(
                                fontSize: 16.0,
                              ),
                            ),
                            decoration: const BoxDecoration(
                              border: Border(
                                bottom: BorderSide(
                                  width: 2.0,
                                  color: Color.fromRGBO(0, 0, 0, 0.2),
                                ),
                              ),
                            ),
                            padding: const EdgeInsets.symmetric(vertical: 16.0),
                          ),
                        )
                      ],
                    ),
                  ],
                ),
              ),
              AnimatedCrossFade(
                firstChild: Container(),
                secondChild: Column(
                  children: [
                    const SizedBox(height: 16.0),
                    Container(
                      margin: const EdgeInsets.symmetric(
                        horizontal: 32.0,
                      ),
                      child: RichText(
                        textAlign: TextAlign.center,
                        text: TextSpan(
                          style: GoogleFonts.roboto(
                            fontSize: 18.0,
                            fontStyle: FontStyle.italic,
                            color: Colors.black,
                          ),
                          children: [
                            const TextSpan(text: "* Las renovaciones de aire se realizarán cada "),
                            TextSpan(text: "$_valCamMin ", style: GoogleFonts.roboto(fontWeight: FontWeight.bold)),
                            const TextSpan(text: "minutos"),
                          ],
                        ),
                      ),
                    ),
                    const SizedBox(height: 16.0),
                    Container(
                      margin: const EdgeInsets.symmetric(
                        horizontal: 32.0,
                      ),
                      child: Text(
                        "Caudal:",
                        style: GoogleFonts.roboto(
                          fontWeight: FontWeight.bold,
                          fontSize: 18.0,
                        ),
                      ),
                    ),
                    const SizedBox(height: 8.0),
                    Container(
                      margin: const EdgeInsets.symmetric(
                        horizontal: 32.0,
                      ),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        crossAxisAlignment: CrossAxisAlignment.center,
                        children: [
                          Expanded(
                            child: Text(
                              "${_formatearNumeros(_valCaudalM3H)} m³/h",
                              textAlign: TextAlign.center,
                              style: GoogleFonts.roboto(
                                fontSize: 18.0,
                              ),
                            ),
                          ),
                          const SizedBox(width: 8.0),
                          Expanded(
                            child: Text(
                              "${_formatearNumeros(_valCaudalCFM)} CFM",
                              textAlign: TextAlign.center,
                              style: GoogleFonts.roboto(
                                fontSize: 18.0,
                              ),
                            ),
                          ),
                        ],
                      ),
                    ),
                    const SizedBox(height: 16.0),
                    Container(
                      margin: const EdgeInsets.symmetric(
                        horizontal: 32.0,
                      ),
                      child: Text(
                        'Cantidad de equipos requeridos:',
                        style: GoogleFonts.roboto(
                          fontWeight: FontWeight.bold,
                          fontSize: 18.0,
                        ),
                      ),
                    ),
                    const SizedBox(height: 8.0),
                    Container(
                      margin: const EdgeInsets.symmetric(
                        horizontal: 32.0,
                      ),
                      height: 64.0,
                      width: double.infinity,
                      child: Stack(
                        alignment: Alignment.center,
                        children: [
                          TextField(
                            textAlign: TextAlign.center,
                            controller: _equiposController,
                            maxLength: 3,
                            decoration: const InputDecoration(
                              counterText: "",
                              counterStyle: TextStyle(
                                height: double.minPositive,
                              ),
                            ),
                            inputFormatters: [
                              DecimalTextInputFormatter()
                            ],
                            onChanged: (val) => setState(() {
                              if(val.isEmpty){
                                _valEquipos = 0;
                              }else{
                                _valEquipos = int.parse(val);
                              }

                              _valCaudalEquiCFM = _valCaudalCFM / _valEquipos;
                              _valCaudalEquiM3H = _valCaudalM3H / _valEquipos;
                            }),
                          ),
                          Positioned(
                            left: 0.0,
                            child: IconButton(
                              icon: const Icon(
                                Icons.remove,
                                color: Colors.black45,
                              ),
                              onPressed: () => setState(() {
                                _valEquipos = _valEquipos - 1;
                                if(_valEquipos < 0){
                                  _valEquipos = 0;
                                }

                                _equiposController.text = _valEquipos.toString();
                                _valCaudalEquiCFM = _valCaudalCFM / _valEquipos;
                                _valCaudalEquiM3H = _valCaudalM3H / _valEquipos;
                              }) ,
                            ),
                          ),
                          Positioned(
                            right: 0.0,
                            child: IconButton(
                              icon: const Icon(
                                Icons.add,
                                color: Colors.black45,
                              ),
                              onPressed: () => setState(() {
                                _valEquipos = _valEquipos + 1;
                                if(_valEquipos > 999){
                                  _valEquipos = 999;
                                }

                                _equiposController.text = _valEquipos.toString();
                                _valCaudalEquiCFM = _valCaudalCFM / _valEquipos;
                                _valCaudalEquiM3H = _valCaudalM3H / _valEquipos;
                              }),
                            ),
                          )
                        ],
                      ),
                    ),
                    AnimatedCrossFade(
                      firstChild: Container(),
                      secondChild: Column(
                        children: [
                          const SizedBox(height: 16.0),
                          Container(
                            margin: const EdgeInsets.symmetric(
                              horizontal: 32.0,
                            ),
                            child: Text(
                              "Caudal por equipo:",
                              style: GoogleFonts.roboto(
                                fontWeight: FontWeight.bold,
                                fontSize: 18.0,
                              ),
                            ),
                          ),
                          const SizedBox(height: 8.0),
                          Container(
                            margin: const EdgeInsets.symmetric(
                              horizontal: 32.0,
                            ),
                            child: Row(
                              mainAxisAlignment: MainAxisAlignment.center,
                              crossAxisAlignment: CrossAxisAlignment.center,
                              children: [
                                Expanded(
                                  child: Text(
                                    "${_formatearNumeros(_valCaudalEquiM3H)} m³/h",
                                    textAlign: TextAlign.center,
                                    style: GoogleFonts.roboto(
                                      fontSize: 18.0,
                                    ),
                                  ),
                                ),
                                const SizedBox(width: 8.0),
                                Expanded(
                                  child: Text(
                                    "${_formatearNumeros(_valCaudalEquiCFM)} CFM",
                                    textAlign: TextAlign.center,
                                    style: GoogleFonts.roboto(
                                      fontSize: 18.0,
                                    ),
                                  ),
                                ),
                              ],
                            ),
                          ),
                        ],
                      ),
                      duration: const Duration(milliseconds: 250),
                      crossFadeState: _valEquipos == 0 ? CrossFadeState.showFirst : CrossFadeState.showSecond,
                    )
                  ],
                ),
                duration: const Duration(milliseconds: 250),
                crossFadeState: _valCambios == 0 || _valLargo == 0 || _valAncho == 0 || _valAlto == 0 ? CrossFadeState.showFirst : CrossFadeState.showSecond,
              ),
              const SizedBox(height: 32.0),
              Container(
                margin: const EdgeInsets.symmetric(
                  horizontal: 32.0,
                ),
                child: Column(
                  children: [
                    MaterialButton(
                      elevation: 4,
                      padding: const EdgeInsets.symmetric(vertical: 8.0),
                      minWidth: _screenSize.width - 32,
                      color: const Color(0xFFFF0000),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: [
                          Image.asset(
                            "assets/guardar.png",
                            width: 32.0,
                          ),
                          const SizedBox(width: 8.0),
                          const Text(
                            "Guardar y regresar",
                            style: TextStyle(
                              fontFamily: "Helvetica Neue Black Cond",
                              color: Colors.white,
                              fontSize: 28.0,
                            ),
                          )
                        ],
                      ),
                      onPressed: () async{
                        final info = {
                          "largo": "$_valLargo",
                          "ancho": "$_valAncho",
                          "alto": "$_valAlto",
                          "unidadLargo": _unidadAltura,
                          "volumen": "$_valVolumen",
                          "unidadVolumen": _unidadVolumen,
                          "aplicacion": _aplicacion,
                          "cambiosPorHora": _cambiosPorHora,
                          "cambios": "$_valCambios",
                          "cambiosMinutos": "$_valCamMin",
                          "caudalM3H": "$_valCaudalM3H",
                          "caudalCFM": "$_valCaudalCFM",
                          "equiposRequeridos": "$_valEquipos",
                          "caudalEquiM3H": "$_valCaudalEquiM3H",
                          "caudalEquiCFM": "$_valCaudalEquiCFM"
                        };
                        final infoStr = jsonEncode(info);

                        final guardado = await _cambiarDatos(infoStr, "", _valEquipos > 0 ? "F" : "C");
                        if(guardado){
                          Navigator.pop(context);
                        }else{
                          Fluttertoast.showToast(
                            msg: "Hubo un error al intentar guardar el proyecto, intentelo de nuevo más tarde.",
                            toastLength: Toast.LENGTH_SHORT,
                            timeInSecForIosWeb: 4,
                            gravity: ToastGravity.CENTER,
                            webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
                          );
                        }
                      },
                    ),
                    const SizedBox(height: 16.0),
                    MaterialButton(
                      elevation: 4,
                      padding: const EdgeInsets.symmetric(vertical: 8.0),
                      minWidth: _screenSize.width - 32,
                      color: const Color(0xFFFF0000),
                      disabledColor: Colors.grey,
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.center,
                        children: const [
                          Icon(
                            Icons.print,
                            color: Colors.white,
                            size: 32.0,
                          ),
                          SizedBox(width: 8.0),
                          Text(
                            "Imprimir resultados",
                            style: TextStyle(
                              fontFamily: "Helvetica Neue Black Cond",
                              color: Colors.white,
                              fontSize: 28.0,
                            ),
                          ),
                        ],
                      ),
                      onPressed: _valEquipos > 0 ? () async{
                        final ruta = {
                          "idUsuario": widget.idUsuario,
                          "idProyecto": widget.idProyecto,
                          "noProyecto": widget.noProyecto
                        };

                        final rutab64 = base64Encode(utf8.encode(jsonEncode(ruta)));

                        final info = {
                          "largo": "$_valLargo",
                          "ancho": "$_valAncho",
                          "alto": "$_valAlto",
                          "unidadLargo": _unidadAltura,
                          "volumen": "$_valVolumen",
                          "unidadVolumen": _unidadVolumen,
                          "aplicacion": _aplicacion,
                          "cambiosPorHora": _cambiosPorHora,
                          "cambios": "$_valCambios",
                          "cambiosMinutos": "$_valCamMin",
                          "caudalM3H": "$_valCaudalM3H",
                          "caudalCFM": "$_valCaudalCFM",
                          "equiposRequeridos": "$_valEquipos",
                          "caudalEquiM3H": "$_valCaudalEquiM3H",
                          "caudalEquiCFM": "$_valCaudalEquiCFM"
                        };

                        final infoStr = jsonEncode(info);

                        final infoPDF = base64Encode(utf8.encode(jsonEncode({
                          "ruta": rutab64,
                          "infoCalculo": base64Encode(utf8.encode(infoStr))
                        })));

                        final urlArch = await _pdfProvider.fetchAtenuador(infoPDF, 'ambiental');
                        final task = TaskInfo(name: widget.idProyecto, link: urlArch);
                        _requestDownload(task);

                        final guardado = await _cambiarDatos(infoStr, urlArch, _valEquipos > 0 ? "F" : "C");
                        if(!guardado){
                          Fluttertoast.showToast(
                            msg: "Hubo un error al intentar guardar el proyecto, intentelo de nuevo más tarde.",
                            toastLength: Toast.LENGTH_SHORT,
                            timeInSecForIosWeb: 4,
                            gravity: ToastGravity.CENTER,
                            webBgColor: "linear-gradient(to right, #b40404, #ff0000)",
                          );
                        }
                      } : null,
                    ),
                  ],
                ),
              ),
              const SizedBox(height: 32.0),
            ],
          ),
        ),
      ),
    );
  }

  void _calcularVolumen() => setState(() {
    double largo;
    double ancho;
    double alto;

    if(_unidadVolumen == 'm³' && _unidadAltura == 'ft'){
      largo = _valLargo * 0.3048;
      ancho = _valAncho * 0.3048;
      alto = _valAlto * 0.3048;
    }else if(_unidadVolumen == 'ft³' && _unidadAltura == 'm'){
      largo = _valLargo * 3.28084;
      ancho = _valAncho * 3.28084;
      alto = _valAlto * 3.28084;
    }else{
      largo = _valLargo;
      ancho = _valAncho;
      alto = _valAlto;
    }

    _valVolumen = largo * ancho * alto;
    _calcularCaudal();

    if(_valEquipos > 0){
      _valCaudalEquiM3H = _valCaudalM3H / _valEquipos;
      _valCaudalEquiCFM = _valCaudalCFM / _valEquipos;
    }
  });

  void _calcularCaudal() => setState(() {
    if(_valVolumen > 0){
      final largo = _unidadAltura == 'm' ? _valLargo : _valLargo * 0.3048;
      final ancho = _unidadAltura == 'm' ? _valAncho : _valAncho * 0.3048;
      final alto = _unidadAltura == 'm' ? _valAlto : _valAlto * 0.3048;

      _valCaudalM3H = (largo * ancho * alto) * _valCambios;
      _valCaudalCFM = _valCaudalM3H * 0.58857777869148;

      if(_valEquipos > 0){
        _valCaudalEquiM3H = _valCaudalM3H / _valEquipos;
        _valCaudalEquiCFM = _valCaudalCFM / _valEquipos;
      }
    }
  });

  String _formatearNumeros(double numero){
    final numArr = numero.toStringAsFixed(2).split(".");
    final entero = numArr[0];

    final enteroArr = entero.split("").reversed.toList();
    String formatted = "";

    for(int i = 0; i < enteroArr.length; i++){
      if(i % 3 == 2 && i < enteroArr.length - 1){
        formatted = ",${enteroArr[i]}$formatted";
      }else{
        formatted = "${enteroArr[i]}$formatted";
      }
    }

    return "$formatted.${numArr.last}";
  }
}
