// Represents a collection of landmarks that represent a journey
// Different instances of a Trip can be saved and loaded by the user

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

import 'package:anyway/structs/landmark.dart';
import 'package:flutter/foundation.dart';
import 'package:geocoding/geocoding.dart';
import 'package:shared_preferences/shared_preferences.dart';

class Trip with ChangeNotifier {
  String uuid;
  int totalTime;
  LinkedList<Landmark> landmarks;
  // could be empty as well
  String? errorDescription;

  Future<String> get cityName async {
    List<double>? location = landmarks.firstOrNull?.location; 
    if (GeocodingPlatform.instance == null) {
      return '$location';
    } else if (location == null) {
      return 'Unknown';
    } else{
      List<Placemark> placemarks = await placemarkFromCoordinates(location[0], location[1]);
      return placemarks.first.locality ?? 'Unknown';
    }
  }


  Trip({
    this.uuid = 'pending',
    this.totalTime = 0,
    LinkedList<Landmark>? landmarks
    // a trip can be created with no landmarks, but the list should be initialized anyway
  }) : landmarks = landmarks ?? LinkedList<Landmark>();
  

  factory Trip.fromJson(Map<String, dynamic> json) {
    Trip trip = Trip(
      uuid: json['uuid'],
      totalTime: json['total_time'],
    );

    return trip;
  }

  void loadFromJson(Map<String, dynamic> json) {
    uuid = json['uuid'];
    totalTime = json['total_time'];
    notifyListeners();
  }
  void addLandmark(Landmark landmark) {
    landmarks.add(landmark);
    notifyListeners();
  }

  void updateUUID(String newUUID) {
    uuid = newUUID;
    notifyListeners();
  }

  void removeLandmark(Landmark landmark) {
    landmarks.remove(landmark);
    notifyListeners();
  }
  
  void updateError(String error) {
    errorDescription = error;
    notifyListeners();
  }

  factory Trip.fromPrefs(SharedPreferences prefs, String uuid) {
    String? content = prefs.getString('trip_$uuid');
    Map<String, dynamic> json = jsonDecode(content!);
    Trip trip = Trip.fromJson(json);
    String? firstUUID = json['first_landmark_uuid'];
    log('Loading trip $uuid with first landmark $firstUUID');
    LinkedList<Landmark> landmarks = readLandmarks(prefs, firstUUID);
    trip.landmarks = landmarks;
    // notifyListeners();
    return trip;
  }


  Map<String, dynamic> toJson() => {
    'uuid': uuid,
    'total_time': totalTime,
    'first_landmark_uuid': landmarks.first.uuid
  };


  void toPrefs(SharedPreferences prefs){
    Map<String, dynamic> json = toJson();
    log('Saving trip $uuid : $json');
    prefs.setString('trip_$uuid', jsonEncode(json));
    for (Landmark landmark in landmarks) {
      landmarkToPrefs(prefs, landmark, landmark.next);
    }
  }
}


// Helper
LinkedList<Landmark> readLandmarks(SharedPreferences prefs, String? firstUUID) {
  LinkedList<Landmark> landmarks = LinkedList<Landmark>();
  while (firstUUID != null) {
    var (head, nextUUID) = getLandmarkFromPrefs(prefs, firstUUID);
    landmarks.add(head);
    firstUUID = nextUUID;
  }
  return landmarks;
}