// ignore_for_file: use_build_context_synchronously

import 'package:collection/collection.dart';
import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:gap/gap.dart';
import 'package:go_router/go_router.dart';
import 'package:hive_flutter/hive_flutter.dart';
import 'package:jiffy/jiffy.dart';
import 'package:tp5/core/core.dart';
import 'package:tp5/roster/api/crewlink_api.dart';
import 'package:tp5/roster/models/crewlist_leg.dart';
import 'package:tp5/roster/widgets/w_crewlist.dart';
import 'package:tp5/roster/widgets/w_day.dart';

import 'package:tp5/core/basic_page.dart';
import 'package:scroll_to_index/scroll_to_index.dart';

class CrewlistPage extends ConsumerStatefulWidget {
  const CrewlistPage({required this.params, super.key});

  final CrewlistPageParams params;
  @override
  ConsumerState<ConsumerStatefulWidget> createState() => _CrewlistPageState();
}

class _CrewlistPageState extends ConsumerState<CrewlistPage> {
  late String crewlinkUser;
  late String crewlinkPass;

  TextEditingController ctrldep = TextEditingController();
  TextEditingController ctrldes = TextEditingController();
  TextEditingController ctrlairline = TextEditingController();
  TextEditingController ctrlfnum = TextEditingController();
  TextEditingController ctrlstartdate = TextEditingController();
  TextEditingController ctrlenddate = TextEditingController();

  Map? apires;
  List<CrewlistLeg> legs = [];

  String get _crewlistKey =>
      "crewlist_${widget.params.datestart}_${widget.params.dateend}_${widget.params.al}_${widget.params.fnum}_${widget.params.dep}_${widget.params.des}";
  String get _crewlistMinMaxKey => "minmax_crewlist";

  final AutoScrollController _scrollCtrl = AutoScrollController();
  late Jiffy now;

  @override
  void initState() {
    crewlinkUser = widget.params.crewlinkuser!;
    crewlinkPass = widget.params.crewlinkpass!;

    Future.delayed(Duration.zero, () => _loadCrewlist());

    super.initState();
  }

  Future<Map?> _loadCrewlistOnline() async {
    if (!ref.read(crewlinkapiProvider).logged) {
      final login = await ref
          .read(crewlinkapiProvider)
          .login(username: crewlinkUser, password: crewlinkPass);
      if (login["data"]?["logged"] != true) {
        context.showError(login["error"] ?? "Unknown error");
        return null;
      }
    }

    final res = await ref.read(crewlinkapiProvider).showCrew(
        crewlist: false,
        start: widget.params.datestart!,
        end: widget.params.dateend!,
        al: widget.params.al!,
        fnum: widget.params.fnum!,
        dep: widget.params.dep!,
        des: widget.params.des!);

    if (res?["data"]?["msg"] != null) {
      context.showError(res?["data"]?["msg"] ?? "Unknown error");
    }
    if (res["error"] == null && res["data"] != null) {
      if (res["msg"] != null) context.showAlert(res["msg"]);
      Hive.box("crewlink").put(_crewlistKey, res);

      return res;
    }

    return null;
  }

  Future<Map?> _loadCrewlistOffline() async {
    return Hive.box("crewlink").get(_crewlistKey);
  }

  _loadCrewlist() async {
    try {
      ref.read(isLoadingProvider.notifier).state = true;
      final crewlistOffline = await _loadCrewlistOffline();

      if (crewlistOffline != null && mounted) {
        _convertCrewlist(crewlistOffline);
        setState(() {});
        _scrollToDate();
      }
      final crewlistOnline = await _loadCrewlistOnline();

      if (crewlistOnline != null && mounted) {
        _convertCrewlist(crewlistOnline);
        setState(() {});

        _scrollToDate();
      }
    } finally {
      if (mounted) {
        ref.read(isLoadingProvider.notifier).state = false;
      }
    }
  }

  _scrollToDate({Jiffy? date}) {
    final jdate = date ?? Jiffy.now().toUtc();
    print("scroll request to ${jdate.Hm}");
    bool found = false;
    int id = 0;
    if (legs.isNotEmpty &&
        jdate.isSameOrAfter(legs.map((e) => e.jdep).first) &&
        jdate.isSameOrBefore(legs.map((e) => e.jdep).last)) {
      for (CrewlistLeg leg in legs) {
        if (leg.jdep.isSameOrAfter(jdate)) {
          found = true;
          break;
        }
        id++;
      }
    }
    Future.delayed(const Duration(milliseconds: 100)).then((value) {
      if ((found || jdate.yMd == Jiffy.now().toUtc().yMd) &&
          mounted &&
          _scrollCtrl.hasClients) {
        print("scrolling to id:$id  ${jdate.Hm}");

        _scrollCtrl.scrollToIndex(id,
            duration: const Duration(milliseconds: 1300),
            preferPosition: AutoScrollPosition.begin);
      }
    });
  }

  void _convertCrewlist(Map? input) {
    // print("${input?["data"]["leglist"].first[7].runtimeType}");
    apires = input;
    legs = [];
    for (var leg in input?["data"]?["leglist"] ?? []) {
      final CrewlistLeg newleg = CrewlistLeg(leg);
      if ((newleg.jdep.isSameOrAfter(Jiffy.parse(widget.params.datestart ?? "",
                  pattern: "ddMMMyy", isUtc: true)
              .startOf(Unit.day))) &&
          (newleg.jdep.isSameOrBefore(Jiffy.parse(widget.params.dateend ?? "",
                  pattern: "ddMMMyy", isUtc: true)
              .endOf(Unit.day))) &&
          (legs.firstWhereOrNull((e) =>
                  "${e.al}${e.fnum}${e.dep}${e.des}${e.jdep.millisecondsSinceEpoch}" ==
                  "${newleg.al}${newleg.fnum}${newleg.dep}${newleg.des}${newleg.jdep.millisecondsSinceEpoch}") ==
              null)) legs.add(newleg);
    }
    legs.sort((a, b) {
      if (a.jdep.isBefore(b.jdep)) {
        return -1;
      } else if (a.jdep.isAfter(b.jdep)) {
        return 1;
      } else {
        return 0;
      }
    });
  }

  final bottomnavstyle = ElevatedButton.styleFrom(
      shape: RoundedRectangleBorder(
        borderRadius: BorderRadius.circular(5.0),
      ),
      backgroundColor:
          const Color.fromARGB(255, 0, 36, 53) //elevated btton background color
      );
  @override
  Widget build(BuildContext context) {
    now = ref.watch(clockProvider);

    return BasicPage(
      actions: [
        IconButton(
            onPressed: () => context.push("/crewlink/settings"),
            icon: const Icon(Icons.settings)),
        const Gap(10)
      ],
      bottomNavigationBar: Container(
        padding: const EdgeInsets.all(8),
        // color: Colors.black,
        decoration: BoxDecoration(
            gradient: LinearGradient(
          begin: Alignment.topCenter,
          end: Alignment.bottomCenter,
          colors: [
            Colors.grey[700]!,
            Colors.black,
          ],
        )),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceAround,
          children: [
            ElevatedButton.icon(
              onPressed: () {
                _changeDay(context);
              },
              icon: const Icon(
                  Icons.calendar_month), //icon data for elevated button
              label: const Text("Change\n  Day"), //label text
              style: bottomnavstyle,
            ),
            const Gap(10),
            ElevatedButton.icon(
              onPressed: () {
                _searchFlights(context);
              },
              icon: const Icon(Icons.manage_search),
              label: const Text("Search\nFlights"),
              style: bottomnavstyle,
            ),
            const Gap(10), //icon data for elevated button
          ],
        ),
      ),
      title: "CrewLink / Crewlist",
      body: ListView.builder(
        itemCount: legs.length,
        itemBuilder: (_, index) => AutoScrollTag(
            key: ValueKey(index),
            controller: _scrollCtrl,
            index: index,
            child: _getItem(_, index)),
        shrinkWrap: true,
        controller: _scrollCtrl,
      ),
    );
  }

  Widget _getItem(BuildContext ctx, int i) {
    final leg = legs.elementAt(i);
    CrewlistLeg? firstitem =
        legs.firstWhereOrNull((CrewlistLeg el) => el.date == leg.date);
    bool isfirstitem = false;
    if (firstitem != null && firstitem.data == leg.data) isfirstitem = true;

    return Column(
      children: [
        if (i == 0) ...[
          const Gap(20),
          InkWell(
              onTap: () => context.push("/crewlink/crewlist",
                  extra: CrewlistPageParams(
                    al: widget.params.al,
                    fnum: widget.params.fnum,
                    dep: widget.params.dep,
                    des: widget.params.des,
                    datestart: Jiffy.parse(widget.params.datestart ?? leg.date,
                            pattern: "ddMMMyy", isUtc: true)
                        .subtract(days: 1)
                        .format(pattern: "ddMMMyy"),
                    dateend: Jiffy.parse(widget.params.dateend ?? leg.date,
                            pattern: "ddMMMyy", isUtc: true)
                        .subtract(days: 1)
                        .format(pattern: "ddMMMyy"),
                  )),
              child: Container(
                margin: const EdgeInsets.symmetric(horizontal: 15),
                width: double.infinity,
                padding: const EdgeInsets.all(5),
                decoration:
                    BoxDecoration(border: Border.all(color: Colors.grey)),
                child: const Text(
                  "Load Previous Day",
                  textAlign: TextAlign.center,
                  style: TextStyle(fontSize: 12),
                ),
              )),
          const Gap(20)
        ],
        if (isfirstitem)
          WDay(
            date: leg.jdate,
            highlight: now.yMd == leg.jdate.yMd,
            onTap: () => context.push("/crewlink/crewlist",
                extra: CrewlistPageParams(
                    datestart: leg.jdate.format(pattern: "ddMMMyy"))),
          ),
        SingleChildScrollView(
          scrollDirection: Axis.horizontal,
          child: WCrewlist(
            leg: leg,
          ),
        ),
        Divider(
          height: 1,
          thickness: 1,
          color: Colors.grey[700],
        ),
        const Gap(5),
        if (i == legs.length - 1) ...[
          const Gap(20),
          InkWell(
              onTap: () => context.push("/crewlink/crewlist",
                  extra: CrewlistPageParams(
                    al: widget.params.al,
                    fnum: widget.params.fnum,
                    dep: widget.params.dep,
                    des: widget.params.des,
                    datestart: Jiffy.parse(widget.params.datestart ?? leg.date,
                            pattern: "ddMMMyy", isUtc: true)
                        .add(days: 1)
                        .format(pattern: "ddMMMyy"),
                    dateend: Jiffy.parse(widget.params.dateend ?? leg.date,
                            pattern: "ddMMMyy", isUtc: true)
                        .add(days: 1)
                        .format(pattern: "ddMMMyy"),
                  )),
              child: Container(
                margin: const EdgeInsets.symmetric(horizontal: 15),
                width: double.infinity,
                padding: const EdgeInsets.all(5),
                decoration:
                    BoxDecoration(border: Border.all(color: Colors.grey)),
                child: const Text(
                  "Load Next Day",
                  textAlign: TextAlign.center,
                  style: TextStyle(fontSize: 12),
                ),
              )),
          const Gap(20)
        ],
      ],
    );
  }

  void _changeDay(xcontext) async {
    ref.read(isLoadingProvider.notifier).state = true;

    final resoff = Hive.box("crewlink").get(_crewlistMinMaxKey);

    final reson = await ref.read(crewlinkapiProvider).showCrewMinMax();
    if (mounted) {
      ref.read(isLoadingProvider.notifier).state = false;
    }

    dynamic res;
    if (reson["error"] == null && reson?["data"] != null) {
      Hive.box("crewlink").put(_crewlistMinMaxKey, reson["data"]);
      res = reson["data"];
    } else if (resoff == null) {
      context.showError(reson["error"] ?? "Unknown error");
      return;
    }
    res = res ?? resoff;

    if (res != null) {
      final firstDate =
          Jiffy.parse(res["mindate"], pattern: "yyyy-MM-dd", isUtc: true);
      final lastDate =
          Jiffy.parse(res["maxdate"], pattern: "yyyy-MM-dd", isUtc: true);
      final initialDate = Jiffy.parse(widget.params.datestart ?? "",
              pattern: "ddMMMyy", isUtc: true)
          .max(firstDate)
          .min(lastDate);
      final DateTime? pickedDate = await showDatePicker(
        context: xcontext,
        confirmText: null,
        initialDate: initialDate.dateTime,
        firstDate: firstDate.dateTime,
        lastDate: lastDate.dateTime,
        currentDate: Jiffy.now().toUtc().dateTime,
        selectableDayPredicate: (day) => true,
        initialDatePickerMode: DatePickerMode.day,
      );

      if (pickedDate != null) {
        context.push("/crewlink/crewlist",
            extra: CrewlistPageParams(
                datestart: Jiffy.parseFromDateTime(pickedDate)
                    .format(pattern: "ddMMMyy")));
      }
    }
  }

  Widget _searchFilter(BuildContext xcontext, DateTime min, DateTime max) =>
      Container(
        padding: const EdgeInsets.all(20),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Row(
              children: [
                Expanded(
                  child: TextField(
                    decoration:
                        const InputDecoration(labelText: "Departure Airport"),
                    maxLength: 3, // Set maximum length
                    controller: ctrldep,
                  ),
                ),
                const SizedBox(width: 10),
                Expanded(
                  child: TextField(
                    decoration:
                        const InputDecoration(labelText: "Arrival Airport"),
                    maxLength: 3, // Set maximum length
                    controller: ctrldes,
                  ),
                ),
              ],
            ),
            const SizedBox(height: 15),
            Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: ctrlairline,

                    decoration:
                        const InputDecoration(labelText: "Airline IATA code"),
                    maxLength: 2, // Set maximum length
                  ),
                ),
                const SizedBox(width: 10),
                Expanded(
                  child: TextField(
                    controller: ctrlfnum,

                    decoration:
                        const InputDecoration(labelText: "Flight number"),
                    maxLength: 6, // Set maximum length
                  ),
                ),
              ],
            ),
            const SizedBox(height: 15),
            Row(
              children: [
                Expanded(
                  child: TextField(
                      decoration:
                          const InputDecoration(labelText: "Starting date"),
                      controller: ctrlstartdate,
                      readOnly:
                          true, //set it true, so that user will not able to edit text
                      onTap: () async {
                        DateTime? pickedDate = await showDatePicker(
                            context: context,
                            initialDate: DateTime.now().toUtc(),
                            firstDate:
                                min, //DateTime.now () - not to allow to choose before today.
                            lastDate: max);
                        if (pickedDate != null) {
                          String formattedDate =
                              Jiffy.parseFromDateTime(pickedDate).format(
                                  pattern:
                                      "ddMMMyy"); //formatted date output using intl package => 2021-03-16
                          setState(() {
                            ctrlstartdate.text = formattedDate;
                            if (Jiffy.parseFromDateTime(pickedDate).isAfter(
                                Jiffy.parse(ctrlenddate.text,
                                    pattern: "ddMMMyy", isUtc: true))) {
                              ctrlenddate.text = formattedDate;
                            }
                          });
                        } else {
                          print("Date is not selected");
                        }
                      }),
                ),
                const SizedBox(width: 10),
                Expanded(
                  child: TextField(
                      decoration:
                          const InputDecoration(labelText: "Ending date"),
                      controller: ctrlenddate,
                      readOnly:
                          true, //set it true, so that user will not able to edit text
                      onTap: () async {
                        DateTime? pickedDate = await showDatePicker(
                            context: context,
                            initialDate: DateTime.now().toUtc(),
                            firstDate: min,
                            lastDate: max);
                        if (pickedDate != null) {
                          String formattedDate =
                              Jiffy.parseFromDateTime(pickedDate)
                                  .format(pattern: "ddMMMyy");
                          setState(() {
                            ctrlenddate.text = formattedDate;
                            if (Jiffy.parseFromDateTime(pickedDate).isBefore(
                                Jiffy.parse(ctrlstartdate.text,
                                    pattern: "ddMMMyy", isUtc: true))) {
                              ctrlstartdate.text = formattedDate;
                            }
                          });
                        } else {
                          print("Date is not selected");
                        }
                      }),
                ),
              ],
            ),
            const SizedBox(height: 35),
            SizedBox(
              width: 360,
              child: ElevatedButton(
                onPressed: () =>
                    Navigator.pop(context, true), // Close the bottom sheet
                style: ElevatedButton.styleFrom(
                  backgroundColor: Colors.green, // Set button color to green
                  shape: RoundedRectangleBorder(
                    borderRadius:
                        BorderRadius.circular(15), // Add rounded corners
                  ),
                  padding:
                      const EdgeInsets.symmetric(horizontal: 20, vertical: 15),
                ),
                child: const Text(
                  'Search Flights',
                  style: TextStyle(fontSize: 18, color: Colors.white),
                ),
              ),
            ),
          ],
        ),
      );

  void _searchFlights(xcontext) async {
    ref.read(isLoadingProvider.notifier).state = true;
    final resoff = Hive.box("crewlink").get(_crewlistMinMaxKey);
    final reson = await ref.read(crewlinkapiProvider).showCrewMinMax();
    if (mounted) {
      ref.read(isLoadingProvider.notifier).state = false;
    }
    dynamic res;
    if (reson["error"] == null && reson?["data"] != null) {
      Hive.box("crewlink").put(_crewlistMinMaxKey, reson["data"]);
      res = reson["data"];
    } else if (resoff == null) {
      context.showError(reson["error"] ?? "Unknown error");
      return;
    }
    res = res ?? resoff;

    if (res != null) {
      ctrldep.text = widget.params.dep!;
      ctrldes.text = widget.params.des!;
      ctrlairline.text = widget.params.al!;
      ctrlfnum.text = widget.params.fnum!;
      ctrlstartdate.text = widget.params.datestart!;
      ctrlenddate.text = widget.params.dateend!;

      final out = await showModalBottomSheet(
          context: context,
          builder: (context) => _searchFilter(
              xcontext,
              Jiffy.parse(res["mindate"], isUtc: true, pattern: "yyyy-MM-dd")
                  .dateTime,
              Jiffy.parse(res["maxdate"], isUtc: true, pattern: "yyyy-MM-dd")
                  .dateTime));

      if (out == true) {
        context.push("/crewlink/crewlist",
            extra: CrewlistPageParams(
              dep: ctrldep.text.toUpperCase(),
              des: ctrldes.text.toUpperCase(),
              al: ctrlairline.text.toUpperCase(),
              fnum: ctrlfnum.text,
              datestart: ctrlstartdate.text,
              dateend: ctrlenddate.text,
            ));
      }
    }
  }
}

class CrewlistPageParams {
  const CrewlistPageParams({
    this.dateend,
    this.datestart,
    this.al,
    this.fnum,
    this.dep,
    this.des,
    this.crewlinkuser,
    this.crewlinkpass,
  });

  final String? dateend;
  final String? datestart;
  final String? al;
  final String? fnum;
  final String? dep;
  final String? des;
  final String? crewlinkuser;
  final String? crewlinkpass;
}
