// 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:modal_bottom_sheet/modal_bottom_sheet.dart';
import 'package:super_sliver_list/super_sliver_list.dart';
import 'package:tp5/core/basic_page.dart';
import 'package:tp5/core/utils.dart';
import 'package:tp5/ftl/provider/ftl.dart';
import 'package:tp5/ftl/widget/w_shadowbox.dart';
import 'package:tp5/roster/api/crewlink_api.dart';
import 'package:tp5/roster/models/duty.dart';
import 'package:tp5/roster/widgets/w_airport.dart';
import 'package:tp5/roster/widgets/w_hour.dart';

class FtlPage extends ConsumerStatefulWidget {
  const FtlPage({super.key, required this.params});
  final FtlPageParams params;
  @override
  ConsumerState<ConsumerStatefulWidget> createState() => _FtlPageState();
}

class _FtlPageState extends ConsumerState<FtlPage> {
  late String crewlinkUser;
  late String crewlinkPass;
  late String startdate;
  late String enddate;
  Map? roster;
  List<Duty> duties = [];

  String _rosterKey({String? clUser, String? start, String? end}) =>
      "roster_${clUser ?? crewlinkUser}_${start ?? startdate}_${end ?? enddate}";
  String fileidroster({String? clUser, String? start, String? end}) =>
      PathTo().crewlinkFile(
          "${_rosterKey(clUser: clUser, start: start, end: end)}.pdf");
  // String get _rosterKey =>
  //     "roster_${crewlinkUser}_${widget.params.datestart}_${widget.params.dateend}";
  // String get fileidroster => PathTo().crewlinkFile("$_rosterKey.pdf");
  final ScrollController _scrollCtrl = ScrollController();
  final ListController _listCtrl = ListController();
  late Jiffy now;

  @override
  void initState() {
    crewlinkUser = widget.params.crewlinkuser ??
        Hive.box("settings").get("crewlink_user") ??
        "";
    crewlinkPass = widget.params.crewlinkpass ??
        Hive.box("settings").get("crewlink_pass") ??
        "";

    startdate = widget.params.datestart ??
        Jiffy.now().toUtc().startOf(Unit.month).format(pattern: "ddMMMyy");
    enddate = widget.params.dateend ??
        Jiffy.now()
            .toUtc()
            //.add(months: 1)
            .endOf(Unit.month)
            .format(pattern: "ddMMMyy");

    Future.delayed(Duration.zero, () async {
      await _loadMinMax();
      //await _loadRoster();
      await _loadOldRoster();
      await _ftlCalc(base: 'DJE');
    }).then(
        (value) => Future.delayed(const Duration(milliseconds: 200), () async {
              _scrollToDate();
            }));

    super.initState();
  }

  bool _isLoading = false;

  Future<Map?> _loadRosterOnline(
      {String? clUser, String? start, String? end}) async {
    //print("FtlPage: Requesting ONline roster $start -> $end");
    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 roster = await ref.read(crewlinkapiProvider).roster(
        start: start ?? startdate
        //??Jiffy.now().toUtc().startOf(Unit.month).format(pattern: "ddMMMyy")
        ,
        end: end ?? enddate
        //??Jiffy.now().toUtc().endOf(Unit.month).format(pattern: "ddMMMyy")
        ,
        fileid: fileidroster(clUser: clUser, start: start, end: end));

    if (roster?["data"]?["msg"] != null) {
      context.showError(roster?["data"]?["msg"] ?? "Unknown error");
    }
    if (roster["error"] == null && roster["data"] != null) {
      if (roster["msg"] != null) context.showAlert(roster["msg"]);
      Hive.box("crewlink")
          .put(_rosterKey(clUser: clUser, start: start, end: end), roster);

      return roster;
    }

    return null;
  }

  Future<Map?> _loadRosterOffline(
      {String? clUser, String? start, String? end}) async {
    //print("FtlPage: Requesting OFFline roster $start -> $end");

    return Hive.box("crewlink")
        .get(_rosterKey(clUser: clUser, start: start, end: end));
  }

  _loadRoster(
      {String? clUser,
      String? start,
      String? end,
      bool cachefirst = false}) async {
    try {
      ref.read(isLoadingProvider.notifier).state = true;

      final rosterOffline =
          await _loadRosterOffline(clUser: clUser, start: start, end: end);
      if (rosterOffline?["data"]?["decoded"] is Map) {
        print(
            "FTL Page: found offline: $start ${rosterOffline?["data"]?["decoded"] is Map}");
        _convertRoster(rosterOffline);
        setState(() {});
      }

      if (rosterOffline?["data"]?["decoded"] is! Map || !cachefirst) {
        final rosterOnline =
            await _loadRosterOnline(clUser: clUser, start: start, end: end);

        if (rosterOnline?["data"]?["decoded"] is Map) {
          print(
              "FTL Page: found online: $start ${rosterOnline?["data"]?["decoded"] is Map}");
          _convertRoster(rosterOnline);
          setState(() {});
        } else if (rosterOffline?["data"]?["decoded"] is Map) {
          print(
              "FTL Page: found offline: $start ${rosterOffline?["data"]?["decoded"] is Map}");
          _convertRoster(rosterOnline);
          setState(() {});
        }
      }
    } finally {
      if (mounted) {
        ref.read(isLoadingProvider.notifier).state = false;
      }
    }
  }

  _loadOldRoster() async {
    bool exitnow = false;
    // _rosterMax = Jiffy.now().toUtc().endOf(Unit.month).subtract(hours: 10);

    Jiffy date1 = Jiffy.parse(startdate, pattern: "ddMMMyy")
        .subtract(months: 11)
        .startOf(Unit.day)
        .startOf(Unit.month)
        .max(_rosterMin ?? Jiffy.now().toUtc().startOf(Unit.month));
    while (!exitnow) {
      Jiffy date2 = date1
          .endOf(Unit.month)
          .min(_rosterMax?.endOf(Unit.day) ?? Jiffy.now().toUtc().add(days: 3));
      if (date2.isAfter(date1) &&
          date2.endOf(Unit.month) == date1.endOf(Unit.month)) {
        //print("ftlpage: loadoldroster: loading ${DTInterval(date1, date2)}");
        await _loadRoster(
            start: date1.format(pattern: "ddMMMyy"),
            end: date2.format(pattern: "ddMMMyy"),
            cachefirst: date1
                .endOf(Unit.month)
                .isBefore(Jiffy.now().endOf(Unit.month)));
      } else {
        exitnow = true;
      }
      date1 = date1.add(months: 1).startOf(Unit.month);
    }
  }

  String get _rosterMinMaxKey => "minmax_$crewlinkUser";

  _loadMinMax() async {
    final resoff = Hive.box("crewlink").get(_rosterMinMaxKey);
    //print("ftlpage: resoff: $resoff");

    final reson = await ref.read(crewlinkapiProvider).rosterMinMax();
    //print("ftlpage: reson: $reson");
    if (mounted) {
      ref.read(isLoadingProvider.notifier).state = false;
    }

    dynamic res;

    if (reson != null && reson["error"] == null && reson?["data"] != null) {
      Hive.box("crewlink").put(_rosterMinMaxKey, reson["data"]);
      res = reson["data"];
    } else if (resoff == null) {
      //print(reson["error"] ?? "Unknown error");
    }
    res = res ?? resoff;

    _rosterMin =
        Jiffy.parse(res["mindate"], pattern: "yyyy-MM-dd", isUtc: true);
    _rosterMax =
        Jiffy.parse(res["maxdate"], pattern: "yyyy-MM-dd", isUtc: true);
  }

  Jiffy? _rosterMin;
  Jiffy? _rosterMax;

  _scrollToDate({Jiffy? date}) async {
    final jdate = date ?? Jiffy.now().toUtc();
    bool found = false;

    int id = 0;
    for (FtlDuty duty in dutiestodisplay) {
      // if (duty.jdate.yMd == jdate.yMd) {
      if (duty.start!.isSameOrAfter(jdate)) {
        found = true;
        break;
      }
      id++;
    }

    if (found && mounted && _scrollCtrl.hasClients) {
      // await _scrollCtrl.scrollToIndex(duties.length - 30,
      //     duration: const Duration(milliseconds: 500),
      //     preferPosition: AutoScrollPosition.end);
      _listCtrl.animateToItem(
        duration: (d) => const Duration(milliseconds: 700),
        index: id,
        scrollController: _scrollCtrl,
        alignment: 0.75,
        curve: (double estimatedDistance) => Curves.decelerate,
      );
    }
  }

  int i = 0;
  _convertRoster(Map? input) {
    roster = input;
    final decoded = (input?["data"]?["decoded"]?["roster"] ?? {});
    for (var date in decoded.keys) {
      duties = duties.where((e) => e.date != date).toList();
      var dutylist = (decoded[date] as List);
      for (var duty in dutylist) {
        i++;
        duties.add(
            Duty(date: date, type: duty["type"], data: duty["data"], order: i));
        //print("${(duties.last).jdate.yMd} ${(duties.last).type} ${(duties.last).start?.Hm} ${(duties.last).end?.Hm}");
      }
    }
  }

  Ftl ftldata = Ftl.fromCrewlink(clDuties: [], base: 'DJE');

  Jiffy ftlcalcdate = Jiffy.now().subtract(days: 30).startOf(Unit.month);

  _ftlCalc({required String base}) async {
    ref.read(isLoadingProvider.notifier).state = true;

    ftldata = Ftl.fromCrewlink(clDuties: duties, base: base);
    //await compute(ftlCalc, {"clDuties": duties, "base": base});

    // await ftldata.calcduties(date: null);
    await ftldata.calcduties(date: ftlcalcdate);

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

  List<FtlDuty> get dutiestodisplay => ftldata.duties
      .whereIndexed((i, e) => e.start!.isSameOrAfter(ftlcalcdate))
      .toList();

  @override
  Widget build(BuildContext context) {
    return BasicPage(
      actions: [
        ElevatedButton(
            onPressed: _isLoading
                ? null
                : () async {
                    setState(() {
                      _isLoading = true;
                    });
                    await _ftlCalc(base: "DJE");
                    setState(() {
                      _isLoading = false;
                    });
                  },
            child: const Text("calc"))
      ],
      title: "FTL",
      body: ftldata.duties.isEmpty
          ? const Text("Please wait, calculations in progress...")
          : SuperListView.builder(
              itemCount: dutiestodisplay.length,
              itemBuilder: (contexte, index) => _getItem(contexte, index),
              listController: _listCtrl,
              shrinkWrap: false,
              controller: _scrollCtrl,
            ),
    );
  }

  bool _is36h(DTInterval? e, String station) {
    if (e == null) return false;
    final firstnight = DTInterval.fromHm(
        apartir: Ftl.changeTz(e.start, station).toUtc(),
        h: 23,
        m: 0,
        duration: const Duration(hours: 7, minutes: 59),
        ap: station);
    final secondnight =
        DTInterval(firstnight.start.add(days: 1), firstnight.end.add(days: 1));
    if (e.duration.inHours >= 36 &&
        e.contains(firstnight) &&
        e.contains(secondnight)) {
      return true;
    } else {
      return false;
    }
  }

  bool _is48h(DTInterval? e, String station) {
    if (e == null) return false;
    final localdays = DTInterval.fromHm(
        apartir: Ftl.changeTz(e.start, station).toUtc(),
        h: 0,
        m: 0,
        duration: const Duration(hours: 47, minutes: 59),
        ap: station);
    if (e.contains(localdays)) {
      return true;
    } else {
      return false;
    }
  }

  _showDutyInfo(int i) {
    final duty = dutiestodisplay[i];
    //print("ftlpage: ${duty.interval}  ${duty.type}");
    final margin =
        ((duty.fdpExt ? duty.fdpExtMax : duty.fdpMax) ?? Duration.zero)
            .subtract(duty.fdpLength);
    showMaterialModalBottomSheet(
      bounce: true,
      context: context,
      builder: (context) => Container(
        padding: const EdgeInsets.all(10),
        decoration: const BoxDecoration(
            border: Border(top: BorderSide(width: 3, color: Colors.white70))),
        //height: 250,
        child: SingleChildScrollView(
          child: Column(
            children: [
              const Gap(5),
              ElevatedButton(
                  onPressed: () {
                    context.pop();
                  },
                  child: const Text(
                    "Close",
                    style: TextStyle(
                        color: Colors.red, fontWeight: FontWeight.w700),
                  )),
              const Gap(5),
              const Text(
                "Duty FTL Details",
                style: TextStyle(fontSize: 22),
              ),
              const Gap(10),
              Row(
                children: [
                  const Text("Duty:",
                      style: TextStyle(fontWeight: FontWeight.w800)),
                  const Gap(20),
                  _titleInfo(duty.start!.yMMMEd, duty.start!.Hm),
                  const Gap(20),
                  _titleInfo(duty.start!.yMMMEd, duty.end!.Hm)
                ],
              ),
              const Gap(20),
              if (duty.fdpStart != null)
                Row(
                  children: [
                    const Text("FDP:",
                        style: TextStyle(fontWeight: FontWeight.w800)),
                    const Gap(20),
                    _titleInfo("FDP Length", duty.fdpLength.tohhmm),
                    const Gap(20),
                    _titleInfo("Fdp Max", duty.fdpMax!.tohhmm),
                    const Gap(20),
                    _titleInfo("Fdp Ext Max", duty.fdpExtMax!.tohhmm),
                    const Gap(20),
                    _titleInfo(margin.isNegative ? "Exceeded" : "Margin",
                        margin.abs().tohhmm,
                        color: margin.isNegative ? Colors.red : Colors.green,
                        sizeinfo: 12),
                  ],
                ),
              const Gap(20),
              if (duty.fdpStart != null)
                Row(
                  children: [
                    const Text("Acclim:",
                        style: TextStyle(fontWeight: FontWeight.w800)),
                    const Gap(20),
                    _titleInfo("Acclim type", duty.acclim),
                    const Gap(20),
                    _titleInfo("Ref time", duty.reftime),
                  ],
                ),
              const Gap(20),
              if (duty.fdpStart != null)
                Row(
                  children: [
                    const Text("Report:",
                        style: TextStyle(fontWeight: FontWeight.w800)),
                    const Gap(10),
                    _titleInfo("Report time", duty.start?.Hm ?? "----"),
                    const Gap(10),
                    _titleInfo(
                        "Delayed Report1", duty.reportdelay1?.Hm ?? "----"),
                    const Gap(10),
                    _titleInfo(
                        "Delayed Report1", duty.reportdelay2?.Hm ?? "----"),
                  ],
                ),
              const Gap(20),
              if (duty.fdpStart != null &&
                  (duty.lateFinish || duty.earlyStart || duty.nightDuty))
                Row(
                  children: [
                    const Text("Disruptive:",
                        style: TextStyle(fontWeight: FontWeight.w800)),
                    const Gap(10),
                    if (duty.earlyStart)
                      const Text("early start duty",
                          style: TextStyle(
                              fontWeight: FontWeight.w800,
                              fontSize: 12,
                              color: Colors.cyan)),
                    const Gap(10),
                    if (duty.lateFinish)
                      const Text("late finish duty",
                          style: TextStyle(
                              fontWeight: FontWeight.w800,
                              fontSize: 12,
                              color: Colors.cyan)),
                    const Gap(10),
                    if (duty.nightDuty)
                      const Text("night duty",
                          style: TextStyle(
                              fontWeight: FontWeight.w800,
                              fontSize: 12,
                              color: Colors.cyan)),
                    const Gap(10),
                  ],
                ),
              const Gap(20),
              Row(
                children: [
                  SingleChildScrollView(
                    scrollDirection: Axis.horizontal,
                    child: Row(
                        mainAxisSize: MainAxisSize.max,
                        mainAxisAlignment: MainAxisAlignment.start,
                        children: [
                          const Text("Detail:",
                              style: TextStyle(fontWeight: FontWeight.w800)),
                          ...(duty.dutiesDetailsIndex.map((e) {
                            final detail = ftldata.dutiesDetails[e];
                            final label = (detail.placeEnd != null)
                                ? "${detail.placeStart}-${detail.placeEnd}"
                                : "${detail.label}";
                            return [
                              const Gap(20),
                              _titleInfo(label,
                                  "${detail.start?.Hm}-${detail.end?.Hm}",
                                  sizeinfo: 10)
                            ];
                          }).flattened),
                        ]),
                  ),
                ],
              ),
              const Gap(20),
              Row(
                children: [
                  const Text("Tot duties hrs:",
                      style: TextStyle(fontWeight: FontWeight.w800)),
                  const Gap(10),
                  _titleInfo("7 days",
                      "${duty.dutyTotal?.dutylast7?.tohhmm}|${Ftl.maxdutylast7.tohhmm}",
                      sizeinfo: 10),
                  const Gap(5),
                  _titleInfo("14 days",
                      "${duty.dutyTotal?.dutylast14?.tohhmm}|${Ftl.maxdutylast14.tohhmm}",
                      sizeinfo: 10),
                  const Gap(5),
                  _titleInfo("28 days",
                      "${duty.dutyTotal?.dutylast28?.tohhmm}|${Ftl.maxdutylast28.tohhmm}",
                      sizeinfo: 10),
                ],
              ),
              const Gap(20),
              Row(
                children: [
                  const Text("Tot Flt hrs:",
                      style: TextStyle(fontWeight: FontWeight.w800)),
                  const Gap(10),
                  _titleInfo("28 days",
                      "${duty.dutyTotal?.fltlast28?.tohhmm}|${Ftl.maxfltlast28.tohhmm}",
                      sizeinfo: 10),
                  const Gap(5),
                  _titleInfo("12 months",
                      "${duty.dutyTotal?.fltlast12?.tohhmm}|${Ftl.maxfltlast12.tohhmm}",
                      sizeinfo: 10),
                  const Gap(5),
                  _titleInfo("year",
                      "${duty.dutyTotal?.fltyear?.tohhmm}|${Ftl.maxfltlastyear.tohhmm}",
                      sizeinfo: 10),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }

  _titleInfo(String? title, String? info,
          {double sizetitle = 10,
          double sizeinfo = 16,
          Color color = Colors.blueGrey}) =>
      Column(
        children: [
          Text(
            title ?? "---",
            style: TextStyle(color: Colors.grey, fontSize: sizetitle),
          ),
          Text(info ?? "---",
              style: TextStyle(color: color, fontSize: sizeinfo)),
        ],
      );

  Widget _getItem(BuildContext _, int i) {
    final duty = dutiestodisplay.elementAt(i);
    final lastduty = i == 0 ? null : dutiestodisplay.elementAt(i - 1);

    final rest =
        lastduty == null ? null : DTInterval(lastduty.end!, duty.start!);

    Color legal;
    if (duty.legals.isEmpty) {
      legal = Colors.green[900]!;
    } else if (duty.legals.every((e) => (e.condition ?? "") != "")) {
      legal = Colors.amber;
    } else {
      legal = Colors.red;
    }

    return Column(
      children: [
        if (lastduty != null)
          WShadowbox(
              child: Column(children: [
            Container(
              decoration: const BoxDecoration(
                color: Color.fromARGB(255, 8, 9, 9),
                border: Border(top: BorderSide(width: 5)),
                borderRadius: BorderRadius.all(Radius.circular(10.0)),
              ),
              padding: const EdgeInsets.all(5),
              // width: double.infinity,
              child: Row(
                mainAxisAlignment: MainAxisAlignment.spaceBetween,
                children: [
                  Column(
                    children: [
                      _titleInfo("Rest",
                          "${(rest?.duration.inDays ?? 0)} days, ${(rest?.duration.inHours ?? 0) % 24} hours, ${(rest?.duration.inMinutes ?? 0) % 60} minutes",
                          sizeinfo: 10),
                    ],
                  ),
                  Column(children: [
                    if (_is48h(rest, lastduty.placeEnd ?? "UTC"))
                      Container(
                          color: Colors.teal[900],
                          padding: const EdgeInsets.all(5),
                          child: Text(
                            "48h with 2 local days",
                            style: TextStyle(
                                color: Colors.yellow[600]!,
                                fontSize: 11,
                                fontWeight: FontWeight.w600),
                          )),
                    if (_is36h(rest, lastduty.placeEnd ?? "UTC"))
                      Container(
                          color: Colors.teal[800],
                          padding: const EdgeInsets.all(5),
                          child: Text(
                            "36h with 2 local nights",
                            style: TextStyle(
                                color: Colors.yellow[500]!,
                                fontSize: 11,
                                fontWeight: FontWeight.w600),
                          ))
                  ]),
                ],
              ),
            )
          ])),
        InkWell(
          onTap: () => _showDutyInfo(i),
          child: WShadowbox(
            child: Column(
              children: [
                Container(
                  decoration: BoxDecoration(
                    color: Color.fromARGB(
                        duty.start!.isAfter(Jiffy.now()) ? 255 : 70, 1, 45, 47),
                    border: Border(top: BorderSide(width: 5, color: legal)),
                    borderRadius:
                        const BorderRadius.vertical(top: Radius.circular(10.0)),
                  ),
                  padding: const EdgeInsets.symmetric(horizontal: 20),
                  // width: double.infinity,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      Text(
                        "${duty.start?.format(pattern: "dd MMM'yy")}",
                        style: const TextStyle(color: Colors.white54),
                      ),
                      if (duty.start != null) WHour(jiffy: duty.start!),
                    ],
                  ),
                ),

                Container(
                  width: double.infinity,
                  padding: const EdgeInsets.only(left: 20, right: 10),
                  decoration: const BoxDecoration(
                    color: Colors.black,
                  ),
                  child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: duty.legals
                          .map((e) => Text(
                                "+ ${e.condition ?? ""} ${e.legalCauseMsg}",
                                style: const TextStyle(fontSize: 10),
                              ))
                          .toList()),
                ),

                //details

                ...duty.dutiesDetailsIndex.map((index) {
                  final FtlDutyDetails dutydetail =
                      ftldata.dutiesDetails[index];
                  return Row(
                    children: [
                      const Gap(40),
                      SizedBox(
                        width: 50,
                        child: Row(children: [
                          Text(
                            dutydetail.typeString,
                            style: TextStyle(
                              backgroundColor: Colors.blueGrey[900],
                              color: Colors.yellow,
                              fontSize: 10,
                              fontWeight: FontWeight.w600,
                            ),
                          )
                        ]),
                      ),
                      SizedBox(
                        width: 60,
                        child: Row(
                          children: [
                            WHour(
                              jiffy: dutydetail.start!,
                              size: 12,
                              color: Colors.white38,
                            ),
                            const Gap(5),
                            WHour(
                              jiffy: dutydetail.end!,
                              size: 12,
                              color: Colors.white38,
                            ),
                          ],
                        ),
                      ),
                      SizedBox(
                        // width: 80,
                        child: Row(children: [
                          const Gap(10),
                          if (dutydetail.placeStart != null)
                            WAirport(iata: dutydetail.placeStart!, size: 12),
                          if (dutydetail.placeEnd != null) ...[
                            const Icon(Icons.arrow_right_alt, size: 9),
                            WAirport(iata: dutydetail.placeEnd!, size: 12)
                          ] else if ((dutydetail.label ?? "") != "")
                            Text(" (${dutydetail.label})",
                                style: const TextStyle(
                                    color: Colors.white54,
                                    fontSize: 10,
                                    letterSpacing: 2),
                                overflow: TextOverflow.ellipsis),
                        ]),
                      ),
                    ],
                  );
                }),

                Container(
                  decoration: BoxDecoration(
                    color: Color.fromARGB(
                        duty.start!.isAfter(Jiffy.now()) ? 255 : 70, 1, 45, 47),
                    borderRadius:
                        BorderRadius.vertical(bottom: Radius.circular(10.0)),
                  ),
                  padding: const EdgeInsets.symmetric(horizontal: 20),
                  // width: double.infinity,
                  child: Row(
                    mainAxisAlignment: MainAxisAlignment.spaceBetween,
                    children: [
                      if (duty.end != null && duty.start != null)
                        _titleInfo(
                            "Duty length",
                            duty.end!.dateTime
                                .difference(duty.start!.dateTime)
                                .tohhmm),
                      const Row(children: []),
                      Column(
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          Text(
                            (duty.end?.yMMMd != duty.start?.yMMMd)
                                ? "${duty.end?.format(pattern: "dd MMM")}"
                                : "",
                            style: const TextStyle(
                                color: Colors.white54, fontSize: 12),
                          ),
                          if (duty.end != null) WHour(jiffy: duty.end!),
                        ],
                      ),
                    ],
                  ),
                ),
              ],
            ),
          ),
        ),
      ],
    );
  }
}

class FtlPageParams {
  const FtlPageParams({
    this.dateend,
    this.datestart,
    this.crewlinkuser,
    this.crewlinkpass,
  });

  final String? dateend;
  final String? datestart;
  final String? crewlinkuser;
  final String? crewlinkpass;
}
