import 'dart:io';

import 'package:dio/dio.dart';
import 'package:flutter_tesseract_ocr/flutter_tesseract_ocr.dart';
import 'package:prasule/main.dart';

/// Used for communication with my repo mirror
///
/// Downloads Tessdata for OCR
class TessdataApi {
  static final Dio _client = Dio(
    BaseOptions(
      validateStatus: (status) => true,
      headers: {"User-Agent": "prasule/1.0.0"},
    ),
  );

  /// Gets available languages from the repo
  static Future<List<String>> getAvailableData() async {
    final res = await _client.get<List<dynamic>>(
      "https://git.mnau.xyz/api/v1/repos/hernik/tessdata_fast/contents",
      options: Options(headers: {"Accept": "application/json"}),
    );
    if ((res.statusCode ?? 500) > 399) {
      return Future.error("The server returned status code ${res.statusCode}");
    }
    final data = List<Map<String, dynamic>>.from(res.data ?? []);
    final dataFiles = <String>[];
    for (final file in data) {
      if (!(file["name"] as String).endsWith(".traineddata")) continue;
      dataFiles.add((file["name"] as String).replaceAll(".traineddata", ""));
    }
    return dataFiles;
  }

  /// Deletes data from device
  static Future<void> deleteData(String name) async {
    final dataDir = Directory(await FlutterTesseractOcr.getTessdataPath());
    if (!dataDir.existsSync()) {
      dataDir.createSync();
    }
    final dataFile = File("${dataDir.path}/$name.traineddata");
    if (!dataFile.existsSync()) return;
    dataFile.deleteSync();
  }

  /// Finds existing data on the device
  static Future<List<String>> getDownloadedData() async {
    final tessDir = Directory(await FlutterTesseractOcr.getTessdataPath());
    if (!tessDir.existsSync()) {
      tessDir.createSync();
    }
    return tessDir
        .listSync()
        .where((element) => element.path.endsWith(".traineddata"))
        .map<String>((e) => e.path.split("/").last)
        .toList();
  }

  /// Downloads data from the repo to the device
  static Future<void> downloadData(
    String isoCode, {
    void Function(int, int)? callback,
  }) async {
    final tessDir = Directory(await FlutterTesseractOcr.getTessdataPath());
    if (!tessDir.existsSync()) {
      tessDir.createSync();
    }
    final file = File("${tessDir.path}/$isoCode.traineddata");
    if (file.existsSync()) return; // TODO: maybe ask to redownload?
    final res = await _client.get<List<int>>(
      "https://git.mnau.xyz/hernik/tessdata_fast/raw/branch/main/$isoCode.traineddata",
      options: Options(responseType: ResponseType.bytes),
      onReceiveProgress: callback,
    );
    if ((res.statusCode ?? 500) > 399) {
      return Future.error("The server returned status code ${res.statusCode}");
    }
    try {
      file.openSync(mode: FileMode.write)
        ..writeFromSync(res.data!)
        ..closeSync();
    } catch (e) {
      logger.e(e);
      return Future.error("Could not complete writing file");
    }
  }
}
