// Fejlesztési log service — fájlba írás terepi teszteléshez.
// Az app külső tárhelyére ír, onnan könnyen elérhető.
//
// Használat:
//   AppLogger.i('startRecording', 'Track indítva: $name');
//   AppLogger.w('_onPosition', 'Ugrás kiszűrve: ${dist}m');
//   AppLogger.e('_onPosition', 'GPS hiba', error: e);
//
// Log fájl helye: /sdcard/Android/data/hu.app_dev.terepi_seged/files/logs/
// Elérhető: Android Studio Device Explorer, adb pull, vagy fájlkezelő app

import 'dart:io';
import 'package:flutter/foundation.dart';
import 'package:get/get.dart';
import 'package:intl/intl.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:share_plus/share_plus.dart';

enum _Level { info, warning, error }

class AppLogger extends GetxService {
  static AppLogger get to => Get.find();

  // ── Konfiguráció ──────────────────────────────────────────────────

  /// Csak fejlesztési módban logol (release build-ben kikapcsol)
  static const bool _enableInRelease = true;

  /// Max log fájl méret MB-ban — felette rotál
  static const int _maxSizeMb = 5;

  /// Max megőrzött log fájlok száma
  static const int _maxFiles = 5;

  // ── Belső állapot ─────────────────────────────────────────────────

  File? _logFile;
  IOSink? _sink;
  String? _logDir;

  static final _timeFmt = DateFormat('HH:mm:ss.SSS');
  static final _dateFmt = DateFormat('yyyy-MM-dd');
  static final _fileFmt = DateFormat('yyyy-MM-dd_HH-mm-ss');

  final isEnabled = false.obs;
  final currentLogPath = ''.obs;

  // ── Lifecycle ─────────────────────────────────────────────────────

  @override
  Future<void> onReady() async {
    super.onReady();

    if (!kDebugMode && !_enableInRelease) return;

    try {
      await _initLogFile();
      isEnabled.value = true;
      i('AppLogger', 'Log indítva — ${currentLogPath.value}');
    } catch (e) {
      debugPrint('AppLogger init hiba: $e');
    }
  }

  @override
  Future<void> onClose() async {
    await _sink?.flush();
    await _sink?.close();
    super.onClose();
  }

  // ── Publikus API ──────────────────────────────────────────────────

  /// Info szintű log
  static void i(String tag, String message) =>
      _write(_Level.info, tag, message);

  /// Figyelmeztetés
  static void w(String tag, String message, {Object? error}) =>
      _write(_Level.warning, tag, message, error: error);

  /// Hiba
  static void e(String tag, String message,
          {Object? error, StackTrace? stack}) =>
      _write(_Level.error, tag, message, error: error, stack: stack);

  /// Szeparátor — jól látható elválasztó a logban
  static void separator(String label) {
    _write(_Level.info, '─────', '─── $label ───────────────────────');
  }

  // ── Log fájl megosztása ───────────────────────────────────────────

  Future<void> shareLogs() async {
    await _sink?.flush();

    final dir = _logDir;
    if (dir == null) return;

    final files = Directory(dir)
        .listSync()
        .whereType<File>()
        .where((f) => f.path.endsWith('.log'))
        .toList()
      ..sort((a, b) => b.path.compareTo(a.path));

    if (files.isEmpty) {
      Get.snackbar('Log', 'Nincs log fájl',
          snackPosition: SnackPosition.BOTTOM);
      return;
    }

    // Legutóbbi fájl megosztása
    await SharePlus.instance.share(ShareParams(
      files: [XFile(files.first.path, mimeType: 'text/plain')],
      subject: 'Terepi Segéd log — ${_dateFmt.format(DateTime.now())}',
    ));
  }

  /// Összes log fájl törlése
  Future<void> clearLogs() async {
    await _sink?.flush();
    await _sink?.close();
    _sink = null;

    final dir = _logDir;
    if (dir == null) return;

    for (final f in Directory(dir).listSync().whereType<File>()) {
      await f.delete().catchError((_) {});
    }

    await _initLogFile();
    i('AppLogger', 'Logok törölve, új fájl nyitva');
  }

  // ── Belső ─────────────────────────────────────────────────────────

  static void _write(
    _Level level,
    String tag,
    String message, {
    Object? error,
    StackTrace? stack,
  }) {
    if (!kDebugMode && !_enableInRelease) return;

    // Konzolon is megjelenik
    final prefix = switch (level) {
      _Level.info => '📋',
      _Level.warning => '⚠️',
      _Level.error => '🔴',
    };
    debugPrint('$prefix [$tag] $message'
        '${error != null ? ' | $error' : ''}');

    // Fájlba írás
    try {
      AppLogger.to._writeLine(level, tag, message, error: error, stack: stack);
    } catch (_) {}
  }

  void _writeLine(
    _Level level,
    String tag,
    String message, {
    Object? error,
    StackTrace? stack,
  }) {
    final sink = _sink;
    if (sink == null) return;

    final time = _timeFmt.format(DateTime.now());
    final lvl = switch (level) {
      _Level.info => 'I',
      _Level.warning => 'W',
      _Level.error => 'E',
    };

    sink.writeln('$time $lvl [$tag] $message');
    if (error != null) sink.writeln('       ↳ $error');
    if (stack != null) {
      // Csak az első 5 sor a stack trace-ből
      final lines = stack.toString().split('\n').take(5);
      for (final l in lines) sink.writeln('       $l');
    }

    // Méret ellenőrzés — ha szükséges, rotál
    _checkRotation();
  }

  Future<void> _initLogFile() async {
    final ext = await getExternalStorageDirectory();
    final dir = Directory(p.join(ext!.path, 'logs'));
    await dir.create(recursive: true);
    _logDir = dir.path;

    final name = 'terepi_${_fileFmt.format(DateTime.now())}.log';
    _logFile = File(p.join(dir.path, name));
    _sink = _logFile!.openWrite(mode: FileMode.append);
    currentLogPath.value = _logFile!.path;

    // Fejléc
    _sink!.writeln('═' * 60);
    _sink!.writeln('Terepi Segéd — Log');
    _sink!.writeln('Dátum: ${DateTime.now().toIso8601String()}');
    _sink!.writeln('═' * 60);

    // Régi fájlok törlése
    await _pruneOldFiles(dir);
  }

  void _checkRotation() {
    final file = _logFile;
    if (file == null) return;
    if (!file.existsSync()) return;

    final sizeMb = file.lengthSync() / (1024 * 1024);
    if (sizeMb > _maxSizeMb) {
      _sink?.flush();
      _sink?.close();
      _initLogFile(); // új fájl
    }
  }

  Future<void> _pruneOldFiles(Directory dir) async {
    final files = dir
        .listSync()
        .whereType<File>()
        .where((f) => f.path.endsWith('.log'))
        .toList()
      ..sort((a, b) => a.path.compareTo(b.path));

    while (files.length > _maxFiles) {
      await files.removeAt(0).delete();
    }
  }
}
