import 'dart:io';

import 'package:dart_framework/platform/platform_base.dart';
import 'package:dart_framework/utils/path.dart';
import 'package:dart_framework/utils/string_util.dart';

/// ********************** Test ************************* ///
void test() async {
  log('test');
  log('test2');

  await Future.delayed(const Duration(seconds: 1));
  log('this is test1');
  log('this is test2');

  await Future.delayed(const Duration(seconds: 2));
  log('this is test3');
  log('this is test4');
  log('this is test5');

  await Future.delayed(const Duration(seconds: 2));
  logClear();

  await Future.delayed(const Duration(seconds: 2));
  log('this is test6');
  log('this is test7');

  await Future.delayed(const Duration(seconds: 1));
  log('this is test8');
  log('this is test9');

  await Future.delayed(const Duration(seconds: 3));
  log('this is test10');
  log('this is test11');
  log('this is test12');
  log('this is test13');

  logEnd();
}

/// ********************** Define *********************** ///
void log(String message) {
  _logSend(message, LogType.verbose);
}

void logWarning(String message) {
  _logSend(message, LogType.warning);
}

void logError(String message) {
  _logSend(message, LogType.error);
}

void _logSend(String message, LogType type) {
  var item = LogItem(message, type);
  Log.to.append(item);
}

void logClear() {
  Log.to.clear();
}

void logEnd() {
  Log.to.end();
}

enum LogType { verbose, error, warning }

class LogItem {
  late String message;
  late String date;
  late LogType type;

  LogItem(this.message, this.type) {
    date = getDates();
  }
  @override
  String toString() {
    return '[$date][${type.name}] $message';
  }
}

class Log {
  static String? path;
  int index = 0;
  StringBuffer buffer = StringBuffer();
  final LogWriter _writer = LogWriter();
  Log._privateConstructor() {
    initializeLog();
  }
  static Log _instance = Log._privateConstructor();
  static Log get to => _instance;

  final List<LogItem> logs = [];

  Log() {
    _instance = this;
    initializeLog();
  }

  void initializeLog() async {
    if (path == null) {
      path = Path.dataPath;
      if (path!.isNotEmpty) {
        path = '$path/logs';
        var dir = Directory(path!);
        dir.createSync(recursive: true);
      }
    }
    if (path != null && path!.isNotEmpty) {
      _writer.start(
          path!, {'request': _onRequestMessage, 'ready': _onReadyMessage});
    }
  }

  void _onRequestMessage(Object? data) {
    write();
  }

  void _onReadyMessage(Object? data) {
    path = data as String;
    appendString('Log path: $data');
  }

  void write() {
    if (index != logs.length) {
      for (int i = logs.length - index - 1; i >= 0; --i) {
        buffer.writeln(logs[i].toString());
      }
      index = logs.length;
      _writer.write(buffer.toString());
      buffer.clear();
    }
  }

  void appendString(String message) {
    append(LogItem(message, LogType.verbose));
  }

  void append(LogItem item) {
    logs.insert(0, item);
  }

  void clear() {
    logs.clear();
    index = 0;
    appendString('Log Restarted.');
  }

  void end() {
    write();
    _writer.end();
  }
}
