//import 'package:html';

import 'dart:convert';
import 'dart:developer';

import 'package:flutter/foundation.dart';
import 'package:intl/intl.dart';

class ApiLido4d {
  //static const url = "https://tar.lido.aero";
  static const url =
      kIsWeb ? "https://proxy.fares.cyou" : "https://tar.lido.aero";
  //static const url = "https://proxy.fares.cyou";
  static const realurl = "https://tar.lido.aero";
  ApiLido4d({this.username = "", this.password = ""});
  bool get logged => cookieMap.isNotEmpty;
  String username;
  String password;
  String get cookie =>
      "${cookieMap.keys.fold("", (t, e) => (t == "") ? "$e=${cookieMap[e]}" : "$t; $e=${cookieMap[e]}")};SameSite=None; Secure";

  Map cookieMap = {};
  Map get headers => {
        "Accept": "application/vnd.lsy.lido.lcb.v1.hal+json",
        "Accept-Encoding": "gzip, deflate, br",
        "Accept-Language": "en",
        "Connection": "keep-alive",
        "Content-Type": "application/json;charset=UTF-8",
        //"Host": Uri.parse(realurl).host,
        "Origin": Uri.parse(realurl).host,
        //"sec-ch-ua":'" Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"',
        // "sec-ch-ua-mobile": "?0",
        // "sec-ch-ua-platform": "Windows",
        // "Sec-Fetch-Dest": "empty",
        // "Sec-Fetch-Mode": "cors",
        // "Sec-Fetch-Site": "same-origin",
        "User-Agent":
            'Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36',
        "X-lido-applicationId": "lido-lcb",
        "X-lido-clientId": "lido-lcb-web",
        "X-lido-customerId": "TAR",
        "X-lido-operatingAirline": "",
        "X-lido-timeStamp": DateTime.now().toUtc().toIso8601String(),
        "X-lido-traceId": "0c497133-2a92-45a0-8ffe-a03c77852201",
        "cookie": "SERVERID=docker2; ${cookie}",
        "X-lido-csrf": cookieMap["lido_csrf"] ?? "",
      };
  Future logout() async {
    var response = await post(Uri.parse('${url}USR/actionLogout.jsp'),
        body: {"Cookie": cookie});
  }

  Future login() async {
    try {
      var response = await get(
        Uri.parse(
            '$url/lido/las/login.jsp?DESMON_RESULT_PAGE=$realurl/briefing//'),
      );
      cookieMap.addAll(_getcookies(response.headers["set-cookie"] ??
          response.headers["_set-cookie"] ??
          ""));
      //print(response.headers);
      response = await post(
          Uri.parse('$url/lido/las/dwr/call/plaincall/LoginBean.login.dwr'),
          body: {
            "callCount": "1",
            "windowName": "DWR-5F9BFD0ECADDCF42109A9C1099F4B49B",
            "c0-scriptName": "LoginBean",
            "c0-methodName": "login",
            "c0-id": "0",
            "c0-param0": "boolean:false",
            "c0-param1": "boolean:false",
            "c0-param2": "string:$username",
            "c0-param3": "string:$password",
            "c0-param4": "string:",
            "c0-param5": "string:LIDO",
            "c0-param6": "string:en",
            "batchId": "1",
            "page":
                "/lido/las/login.jsp?DESMON_RESULT_PAGE=$realurl/briefing&DESMON_CODE=LAS_002&DESMON_LANG=en",
            "httpSessionId": "",
            "scriptSessionId": "C63C650BEED5A9D544876B2756E3ECF0"
          },
          headers: {});
      cookieMap.addAll(_getcookies(response.headers["set-cookie"] ?? ""));
      //log("$username $password ${response.statusCode} ${response.body}");

      final message = RegExp(r'(?<=errorMessage2:")(.+)(?=",)')
              .firstMatch(response.body)
              ?.group(0) ??
          RegExp(r'(?<=errorMessage1:")(.+)(?=",)')
              .firstMatch(response.body)
              ?.group(0);

      final changepass = RegExp(r'(?<=forcePasswdChange:)(.+)(?=,)')
              .firstMatch(response.body)
              ?.group(0) ==
          "true";

      cookieMap = (message != null) ? {} : cookieMap;
      log("api lido 4d login $username $password ${response.statusCode} logged:$logged msg:${message}");

      return {
        'error': logged ? null : message,
        'data': {"logged": logged},
        'meta': {
          "changepass": changepass,
          "user": username,
          "pass": password,
          "cookie": cookieMap
        }
      };
    } catch (e) {
      return {
        'error': e.toString(),
        'data': {"logged": false},
        'meta': {"user": username, "pass": password, "cookie": null}
      };
    }
  }

  Future list(
      {String date = "",
      String dep = "",
      String des = "",
      String al = "",
      String fnum = ""}) async {
    try {
      final startdate = (date == "")
          ? DateTime.now()
              .subtract(const Duration(hours: 36))
              .toUtc()
              .millisecondsSinceEpoch
          : DateTime.parse(date).millisecondsSinceEpoch;
      final endate = startdate + (1000 * 60 * 60 * 36);
      var response = await get(
          Uri.parse(
                  "$url/lido/lcb/ui/flights?page=0&size=100&startDateTime=1653148128544&endDateTime=1653191328544")
              .replace(queryParameters: {
            "page": "0",
            "size": "1000",
            "startDateTime": startdate.toString(),
            "endDateTime": endate.toString(),
            ...(al != "" ? {"commAirLine": al} : {}),
            ...(fnum != "" ? {"flightNumber": fnum} : {}),
            ...(dep != "" ? {"departure": dep} : {}),
            ...(des != "" ? {"destination": des} : {}),
          }),
          headers: {"X-lido-businessId": "SearchFlights", ...headers});
      //log(response.headers.toString());
      Map decodedresponse;

      // print("${response.body}");
      try {
        decodedresponse = json.decode(response.body) ?? {};
      } catch (e) {
        decodedresponse = {
          "body": response.body,
          "response": response.statusCode
        };
      }
      String? message = decodedresponse["errorsAndWarnings"]?["warnings"]?[0]
              ?["message"] ??
          decodedresponse["errorsAndWarnings"]?["errors"]?[0]?["message"] ??
          ((response.statusCode == 200) ? null : "ERR");

      /*
      print(((decodedresponse["totalElements"] ?? 0) > 0
          ? decodedresponse["content"].fold([], (t, e) {
              t.add(e["leg"]);
              return t;
            })
          : []));
      */

      return {
        'error': message,
        'data': (message == null) ? decodedresponse["content"] : null,
        'meta': {
          "legs": (decodedresponse["totalElements"] ?? 0) > 0
              ? decodedresponse["content"].fold([], (t, e) {
                  t.add(e["leg"]["legidentifier"]);
                  return t;
                })
              : [],
          "user": username,
          "pass": password,
          "nb": decodedresponse["totalElements"] ?? 0,
          "cookie": cookieMap
        }
      };
    } catch (e) {
      return {'error': e.toString(), 'data': {}, 'meta': {}};
    }
  }

  Future ofp(
      {String al = "",
      String fnum = "",
      String date = "",
      String origin = "",
      String dep = '',
      String des = ''}) async {
    try {
      final dateoforigin =
          DateTime.parse("${(origin == "") ? date : origin}T00:00:00Z")
              .millisecondsSinceEpoch;
      String brieflink = "";
      String legid = "";
      if (origin == "") {
        final res = await list(
            date: date != "" ? date : origin,
            al: al,
            fnum: fnum,
            dep: dep,
            des: des);
        if (res["error"] != null) {
          return res;
        } else if (res["data"]?[0]?["_links"]?["self"]?["href"] != null) {
          //(res["data"]?[0]?["_links"]?["self"]?["href"] ?? "").toString());
          brieflink = res["data"]?[0]?["_links"]?["self"]?["href"];
          legid = res["data"]?[0]?["leg"]?["legidentifier"];
        } else {
          // no link found
          return {
            'error': "Can't find the requested OFP.",
            'data': res["data"],
            'meta': {"user": username, "pass": password, "cookie": cookieMap}
          };
        }
      } else {
        legid =
            '$al.$fnum.${DateFormat("ddLLLy").format(DateTime.fromMillisecondsSinceEpoch(dateoforigin))}.$dep.$des.';

        brieflink = "$url/lido/lcb/ui/$legid/briefing";
      }

      var response = await put(Uri.parse(brieflink),
          headers: {
            "X-lido-businessId": 'SearchBP',
            ...headers,
          },
          //body: json.encode(({"commercialAirline": al,"flightNumber": fnum,"operationalSuffix": "","date": dateoforigin.toString()

          body: json.encode(({
            "categories": [
              "APLI",
              "APTDXML",
              "SOFP",
              "CDA",
              "RADAR",
              "OFPDLK",
              "ATSXML",
              "REGWXXML",
              "WXSIGWX",
              "SIGWXROUTE",
              "VAATCA",
              "ASPDXML",
              "NOTAMXML",
              "OTS",
              "SFC",
              "WINDDATA",
              "RAIMXML",
              "ARPTWXXML",
              "SOFPINFO",
              "IWFRXML",
              "OFPNLXML",
              "VERTPROF",
              "SOFPSUM",
              "RAIM",
              "UAD",
              "DISMAP",
              "WXSATWX"
            ],
          })));
      //log(response.body);

      Map decodedresponse;
      try {
        decodedresponse = (json.decode(response.body) ?? {});
      } catch (e) {
        decodedresponse = {};
      }
      String? message = decodedresponse["errorsAndWarnings"]?["warnings"]?[0]
              ?["message"] ??
          decodedresponse["errorsAndWarnings"]?["errors"]?[0]?["message"] ??
          ((response.statusCode == 201) ? null : "ERR");

      return {
        'error': (message == null) ? null : message,
        'data': decodedresponse,
        'meta': {
          "user": username,
          "pass": password,
          "cookie": cookieMap,
          "legid": legid
        }
      };
    } catch (e) {
      return {'error': e.toString(), 'data': {}, 'meta': {}};
    }
  }

  Future ofppdf(
      {String al = "",
      String fnum = "",
      String date = "",
      String origin = "",
      String dep = '',
      String des = ''}) async {
    try {
      final dateoforigin =
          DateTime.parse("${(origin == "") ? date : origin}T00:00:00Z")
              .millisecondsSinceEpoch;

      String legid = "";
      if (origin == "") {
        final res = await list(
            date: date != "" ? date : origin,
            al: al,
            fnum: fnum,
            dep: dep,
            des: des);
        if (res["error"] != null) {
          log("lido4d: ofps listed, ${res["error"]}");
          return res;
        } else if (res["data"]?[0]?["_links"]?["self"]?["href"] != null) {
          legid = res["data"]?[0]?["leg"]?["legidentifier"];
        } else {
          log("lido4d: no link found");
          // no link found
          return {
            'error': "Can't find the requested OFP.",
            'data': res["data"],
            'meta': {"user": username, "pass": password, "cookie": cookieMap}
          };
        }
      } else {
        legid =
            '$al.$fnum.${DateFormat("ddLLLy").format(DateTime.fromMillisecondsSinceEpoch(dateoforigin))}.$dep.$des.';
      }

      var response = await put(
          Uri.parse("$url/lido/lcb/ui/briefing/multi/print?force=true"),
          headers: {
            "Accept":
                "application/vnd.lsy.lido.lcb.v1.hal+json,application/pdf",
            //"Accept-Encoding": "gzip, deflate, br",
            "Accept-Language": "en",
            "Connection": "keep-alive",
            "Content-Type": "application/json;charset=UTF-8",
            "Cookie": cookie,
            //"host": Uri.parse(realurl).host,
            "Origin": Uri.parse(realurl).host,
            // "sec-ch-ua":'" Not A;Brand";v="99", "Chromium";v="101", "Google Chrome";v="101"',

            "User-Agent":
                "Mozilla/5.0 (Windows NT 10.0; Win64; x64) AppleWebKit/537.36 (KHTML, like Gecko) Chrome/101.0.4951.67 Safari/537.36",
            "X-lido-applicationId": "lido-lcb",
            "X-lido-businessId": "printBP",
            "X-lido-clientId": "lido-lcb-web",
            "X-lido-csrf": cookieMap["lido_csrf"],
            "X-lido-customerId": "TAR",
            "X-lido-operatingAirline": "TU",
            "X-lido-timeStamp": "2022-05-25T06:29:56.659Z",
            "X-lido-traceId": "3cbab7e0-56ca-49ec-b158-8899c0d3bbbb",
          },
          body: json.encode({
            "legIdentifiers": [legid],
            "categories": [
              "OFP",
              "ATS",
              "CREWINFO",
              "DISP",
              "IWFR",
              "NOTAM",
              "UAD",
              "WXSIGWX",
              "VERTPROF",
              "RAIM",
              "DMS",
              "WXNOTAM",
              "ABD",
              "SIGWXROUTE",
              //"WXSATWX"
            ],
            "merge": false,
            "quickprint": false,
            "weatherDataRequired": false,
          }));

      Map decodedresponse;
      try {
        //decodedresponse = (json.decode(response.body) ?? {});
        decodedresponse = {};
      } catch (e) {
        decodedresponse = {};
      }
      String? message = decodedresponse["errorsAndWarnings"]?["warnings"]?[0]
              ?["message"] ??
          decodedresponse["errorsAndWarnings"]?["errors"]?[0]?["message"] ??
          ((response.statusCode == 201) ? null : "ERR");
      //log("xx ${response.headers}");
      //final id ="${DateFormat("yyyyMMdd").format(DateTime.fromMillisecondsSinceEpoch(dateoforigin))}_${dep}_${des}_$al$fnum";
      final id = Lido4dService.filename(
          al: al, fnum: fnum, dep: dep, des: des, origin: origin, date: date);
      var filepdf =
          await Io.getFile(response, filename: "$id.pdf", folder: "ofps");

      return {
        'error': (message == null) ? null : message,
        'data': (message == null)
            ? {"file": filepdf["location"], "bytes": filepdf["bytes"], "id": id}
            : null,
        'meta': {"user": username, "pass": password, "cookie": cookieMap}
      };
    } catch (e) {
      return {'error': e.toString(), 'data': {}, 'meta': {}};
    }
  }

  Map<String, String> _getcookies(String cookiesData,
      {List<String> vars = const [
        "lido_auth",
        "lido_csrf",
        "JSESSIONID",
        "SERVERID"
      ]}) {
    Map<String, String> cookies = {};
    for (var title in vars) {
      if (cookiesData.contains(title)) {
        List at =
            (RegExp(r'(' + title + ')(.*?)[^;]+').stringMatch(cookiesData) ??
                    "")
                .split('=');
        cookies[title] = at[1];
      }
    }
    return cookies;
  }
}
