import 'dart:convert';
import 'dart:io';
import 'dart:typed_data';

import 'package:fis_common/env/env.dart';
import 'package:fis_common/extensions/string.dart';
import 'package:fis_common/logger/logger.dart';
import 'package:fis_ui/index.dart';
import 'package:flyinsono/rpc.dart';
import 'package:flyinsono/architecture/values/store_keys.dart';
import 'package:path_provider/path_provider.dart';

/// 文件存储
abstract class FileStorage {
  FileStorage({
    required this.storageName,
  });

  /// 文件名
  final String storageName;

  /// 保存文件
  Future<bool> setFile(String fileName, Uint8List file) async {
    try {
      return await _setFile(fileName, file);
    } catch (e) {
      logger.e("Text storage save fail, platform: ${FPlatform.current}.", e);
      return false;
    }
  }

  /// 获得文件
  Future<Uint8List?> getFile(String fileName) async {
    try {
      return await _getFile(fileName);
    } catch (e) {
      logger.e("File storage fetch fail, platform: ${FPlatform.current}.", e);
      return null;
    }
  }

  Future<bool> _setFile(String fileName, Uint8List file);

  Future<Uint8List?> _getFile(String fileName);

  /// 创建实例
  ///
  /// [storageName] 文件名
  static FileStorage createInstance(String storageName) {
    final platform = FPlatform.current;
    switch (platform) {
      case FPlatformEnum.android:
      case FPlatformEnum.iOS:
        return _FileStorageNative(storageName);
      case FPlatformEnum.webOnMac:
      case FPlatformEnum.webOnWin:
        return _FileStorageShellWeb(storageName);
      case FPlatformEnum.web:
        return _FileStoragePureWeb(storageName);
    }
  }
}

///本地化的文件存储
class _FileStorageNative extends FileStorage {
  _FileStorageNative(String storageName) : super(storageName: storageName);

  @override
  Future<Uint8List?> _getFile(String fileName) async {
    final storagePath = await _getStoragePath();
    final filePath = "$storagePath/$fileName";
    final file = File(filePath);
    if (!await file.exists()) return null;
    final text = await file.readAsBytes();
    return text;
  }

  @override
  Future<bool> _setFile(String fileName, Uint8List file) async {
    final storagePath = await _getStoragePath();
    final filePath = "$storagePath/$fileName";
    final fileToSave = File(filePath);
    if (kIsMobile) {
      final directory = Directory(storagePath);
      final parentDirectory = directory.parent;
      if (!await parentDirectory.exists()) await parentDirectory.create();
      if (!await directory.exists()) await directory.create();
    }
    if (!await fileToSave.exists()) await fileToSave.create();
    await fileToSave.writeAsBytes(file.toList());
    return true;
  }

  Future<String> _getStoragePath() async {
    Directory? dir;
    if (Platform.isAndroid) {
      dir = await getExternalStorageDirectory();
    }
    if (dir == null) {
      dir = await getApplicationDocumentsDirectory();
    }
    return "${dir.path}/$storageName";
  }
}

///壳子下的文件存储
class _FileStorageShellWeb extends FileStorage {
  _FileStorageShellWeb(String storageName) : super(storageName: storageName);

  @override
  Future<Uint8List?> _getFile(String fileName) async {
    var fileStr =
        await rpc.platform.getBinaryFileCache("$storageName/$fileName");
    if (fileStr != null && fileStr.isNotEmpty) {
      var data = base64Decode(fileStr);
      return data;
    }
    return null;
  }

  @override
  Future<bool> _setFile(String fileName, Uint8List file) async {
    var fileBase64 = base64Encode(file);
    return await rpc.platform
        .setBinaryFileCache(fileBase64, "$storageName/$fileName");
  }
}

/// 基于Base64字符串的壳子下文件导出
class TextMediaFileExporterForShell {
  static Future<bool> exportFile(List<int> files, String storageName) async {
    final platform = FPlatform.current;
    if (platform == FPlatformEnum.webOnMac ||
        platform == FPlatformEnum.webOnWin) {
      var data = base64Encode(files);
      return await rpc.platform.setBytesToExport(data, storageName);
    } else {
      //Web端不需要特殊处理，手机端也有native的处理，因此直接返回true
      return true;
    }
  }
}

///纯web端的文件缓存
class _FileStoragePureWeb extends FileStorage {
  _FileStoragePureWeb(String storageName) : super(storageName: storageName);

  @override
  Future<Uint8List?> _getFile(String fileName) async {
    //目前web端的持久化缓存必要性并不高
    //另外，web端没有持久化文件缓存的方案
    return null;
  }

  @override
  Future<bool> _setFile(String fileName, Uint8List file) async {
    //目前web端的持久化缓存必要性并不高
    //另外，web端没有持久化文件缓存的方案
    return false;
  }

  String _getStoreKey() =>
      StoreKeys.STORE_TEXTDATA_GEN.format([this.storageName]);
}
