import 'package:appwrite/models.dart' as models;
import 'package:flutter_dotenv/flutter_dotenv.dart';
import 'package:intl/intl.dart';
import 'package:appwrite/appwrite.dart';
import '../../data/models/log.dart';
import '../../data/models/project_info.dart';

/// A repository responsible for handling network interactions with the Appwrite server.
///
/// It provides a helper method to ping the server.
class AppwriteRepository {
  static const String pingPath = "/ping";
  // static const String appwriteProjectId = String.fromEnvironment('APPWRITE_PROJECT_ID');
  // static const String appwriteProjectName = String.fromEnvironment('APPWRITE_PROJECT_NAME');
  // static const String appwritePublicEndpoint = String.fromEnvironment('APPWRITE_PUBLIC_ENDPOINT');

  final Client _client = Client()
      .setProject(dotenv.get('APPWRITE_PROJECT_ID'))
      .setEndpoint(dotenv.get('APPWRITE_PUBLIC_ENDPOINT'));

  late final Account _account;
  late final Databases _databases;

  AppwriteRepository._internal() {
    _account = Account(_client);
    _databases = Databases(_client);
  }

  static final AppwriteRepository _instance = AppwriteRepository._internal();

  /// Singleton instance getter
  factory AppwriteRepository() => _instance;

  ProjectInfo getProjectInfo() {
    return ProjectInfo(
      endpoint: dotenv.get('APPWRITE_PUBLIC_ENDPOINT'),
      projectId: dotenv.get('APPWRITE_PROJECT_ID'),
      projectName: dotenv.get('APPWRITE_PROJECT_NAME'),
    );
  }

  /// Pings the Appwrite server and captures the response.
  ///
  /// @return [Log] containing request and response details.
  Future<Log> ping() async {
    try {
      final response = await _client.ping();

      return Log(
        date: _getCurrentDate(),
        status: 200,
        method: "GET",
        path: pingPath,
        response: response,
      );
    } on AppwriteException catch (error) {
      return Log(
        date: _getCurrentDate(),
        status: error.code ?? 500,
        method: "GET",
        path: pingPath,
        response: error.message ?? "Unknown error",
      );
    }
  }

  /// Retrieves the current date in the format "MMM dd, HH:mm".
  ///
  /// @return [String] A formatted date.
  String _getCurrentDate() {
    return DateFormat("MMM dd, HH:mm").format(DateTime.now());
  }

  Future<dynamic> logout() async =>
      await _account.deleteSession(sessionId: 'current');

  Future<models.Session> login(Map map) async =>
      await _account.createEmailPasswordSession(
        email: map['email'],
        password: map['password'],
      );

  Future<models.Session> signUpAnonymus() async =>
      await _account.createAnonymousSession();

  Future<models.User> signup(Map map) async => _account.create(
        userId: ID.unique(),
        email: map['email'],
        password: map['password'],
        name: map['name'],
      );

  Future<models.User> get getCurrentUser => _account.get();

  // Tank Stop CRUD operations
  // Create, Update, Get, List Tank Stops
  Future<models.Document> createTankStop(Map map) async {
    final response = await _databases.createDocument(
      databaseId: dotenv.get('APPWRITE_DATABASE_ID'),
      collectionId: dotenv.get('APPWRITE_COLLECTION_ID'),
      documentId: ID.unique(),
      data: map,
    );
    return response;
  }

  Future<models.DocumentList> listTankStops(String userId) async {
    final response = await _databases.listDocuments(
      databaseId: dotenv.get('APPWRITE_DATABASE_ID'),
      collectionId: dotenv.get('APPWRITE_COLLECTION_ID'),
      queries: [Query.equal('userId', userId)],
    );
    return response;
  }

  Future<models.Document> updateTankStop(String documentId, Map<String, dynamic> map) async {
    final response = await _databases.updateDocument(
      databaseId: dotenv.get('APPWRITE_DATABASE_ID'),
      collectionId: dotenv.get('APPWRITE_COLLECTION_ID'),
      documentId: documentId,
      data: map,
    );
    return response;
  }

  Future<dynamic> deleteTankStop(String documentId) async {
    return await _databases.deleteDocument(
      databaseId: dotenv.get('APPWRITE_DATABASE_ID'),
      collectionId: dotenv.get('APPWRITE_COLLECTION_ID'),
      documentId: documentId,
    );
  }
}
