// Entrypoints can print
// ignore_for_file: avoid_print

import "dart:convert";
import "dart:io";
import "package:http/http.dart";
import "package:html/parser.dart";

typedef Json = Map<String, dynamic>;

extension <E> on List<E> {
  Iterable<(int, E)> enumerate() sync* {
    for (var i = 0; i < length; i++) {
      yield (i, this[i]);
    }
  }
}

final spotClient = Client();

class OcctStop {
  static final Map<int, OcctStop> stopsById = {};
  static final Map<String, OcctStop> stopsByName = {};

  static Future<void> readStops() async {
    final file = File("data/stops.json");
    final json = jsonDecode(await file.readAsString()) as List;
    for (final stopJson in json.cast<Json>()) {
      final name = stopJson["name"] as String;
      final id = stopJson["id"] as int;
      final routeId = stopJson["rid"] as int;
      var stop = stopsById[id];
      if (stop == null) {
        stop = OcctStop(id, name);
        stopsById[id] = stop;
        stopsByName[name] = stop;
      }
      stop.routes.add(routeId);
    }
  }

  final String name;
  final int id;
  final List<int> routes = [];
  OcctStop(this.id, this.name);
}

class OcctRoute {
  final int id;
  final String name;
  final String abbr;
  final List<OcctRouteStop> stops = [];
  final String encodedLine;
  final String hexColor;

  OcctRoute.fromJson(Json json) :
    id = json["id"],
    name = json["name"],
    abbr = json["abbr"],
    encodedLine = json["encLine"],
    hexColor = json["color"];
}

class OcctRouteStop {
  final int id;
  final String name;
  final List<String> times = [];

  OcctRouteStop(this.id, this.name);
}

/*
{
  "route_id": "int",
  "stops": [
    {
       "stop_id": "int",
       "stop_name": "string",
       "times": [ "HH:MM PM" ]
    }
  ]
}
*/

String getStopName(String text) {
  final regex = RegExp("(?:Returns to|Arrives at|Leaves)? ?(?:the )?(.+)");
  const stopNameSubstitutions = {
    "Binghamton University": "University Union",
    "Innovative Tech Complex": "Innovative Technology Center",
    "UClub / University Plaza": "UCLUB",
  };
  print("Trying to find stop name in [$text]");
  final match = regex.firstMatch(text)!;
  final name = match.group(1)!;
  return stopNameSubstitutions[name] ?? name;
}

void main() async {
  await OcctStop.readStops();
  final uri = Uri.parse("https://occtransport.org/pages/routes/iu.html");
  final response = await get(uri);
  if (response.statusCode != 200) {
    print("Got non-200 status: ");
    print(response.body);
    return;
  }
  final html = parse(response.body);
  final table = html.getElementsByTagName("tbody").first;
  print(table.children.first.innerHtml);
  final numStops = table.children.first.children.length;
  print("There are $numStops stops");

  final stopsHtml = html.getElementsByClassName("sch-notes").first;
  final routeStops = <OcctRouteStop>[];
  for (final stopHtml in stopsHtml.children) {
    final sourceName = stopHtml.text.substring(2);  // eg, 1 Leaves Mohawk
    final name = getStopName(sourceName);
    final id = OcctStop.stopsByName[name]?.id;
    if (id == null) {
      print("Could not find a stop with the name: $name");
      return;
    }
    routeStops.add(OcctRouteStop(id, name));
  }
  for (final row in table.children) {
    for (final (index, timeHtml) in row.children.enumerate()) {
      final time = timeHtml.innerHtml;
      routeStops[index].times.add(time);
    }
  }
  print(routeStops);
}
