// Hangjegyzet service:
//  - Felvétel (record csomag, AAC/m4a)
//  - Lejátszás (audioplayers csomag)
//  - Fájl kezelés + SQLite mentés

import 'dart:async';
import 'dart:io';

import 'package:flutter/foundation.dart';
import 'package:geolocator/geolocator.dart';
import 'package:get/get.dart';
import 'package:path/path.dart' as p;
import 'package:path_provider/path_provider.dart';
import 'package:record/record.dart';
import 'package:audioplayers/audioplayers.dart';

import '../models/note_item_audio.dart';
import '../services/app_database.dart';

// ─── Felvétel állapot ─────────────────────────────────────────────────────────

enum AudioRecordState { idle, recording, stopped }

enum AudioPlayState { idle, playing, paused }

// ─── NoteAudioService ─────────────────────────────────────────────────────────

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

  // ── Reaktív állapot ────────────────────────────────────────────────────────
  final recordState = AudioRecordState.idle.obs;
  final recordDurationMs = 0.obs; // eltelt ms felvétel közben
  final playingAudioId = Rxn<int>(); // melyik clip játszik épp
  final playState = AudioPlayState.idle.obs;
  final playPositionMs = 0.obs;

  // ── Belső ──────────────────────────────────────────────────────────────────
  final _recorder = AudioRecorder();
  final _player = AudioPlayer();
  String? _audioDir;
  String? _currentRecordPath;
  Timer? _recordTimer;
  int? _recordStartMs;

  // ── Inicializálás ──────────────────────────────────────────────────────────

  @override
  Future<void> onInit() async {
    super.onInit();
    await _initAudioDir();
    _initPlayerListeners();
  }

  Future<void> _initAudioDir() async {
    final ext = await getExternalStorageDirectory();
    final dir = Directory(p.join(ext!.path, 'audio'));
    if (!await dir.exists()) await dir.create(recursive: true);
    _audioDir = dir.path;
  }

  void _initPlayerListeners() {
    // Lejátszás pozíció frissítése
    _player.onPositionChanged.listen((pos) {
      playPositionMs.value = pos.inMilliseconds;
    });

    // Lejátszás vége
    _player.onPlayerComplete.listen((_) {
      playState.value = AudioPlayState.idle;
      playingAudioId.value = null;
      playPositionMs.value = 0;
    });
  }

  // ── Felvétel ──────────────────────────────────────────────────────────────

  Future<bool> startRecording(int noteItemId) async {
    // Engedély ellenőrzés
    final hasPermission = await _recorder.hasPermission();
    if (!hasPermission) {
      Get.snackbar(
          'Engedély szükséges', 'Mikrofon hozzáférés engedélyezése szükséges.',
          snackPosition: SnackPosition.BOTTOM);
      return false;
    }

    // Aktív lejátszás leállítása
    if (playState.value != AudioPlayState.idle) {
      await stopPlayback();
    }

    final fileName = 'audio_${noteItemId}_'
        '${DateTime.now().millisecondsSinceEpoch}.m4a';
    _currentRecordPath = p.join(_audioDir!, fileName);

    await _recorder.start(
      const RecordConfig(
        encoder: AudioEncoder.aacLc, // jó minőség, kis méret
        bitRate: 64000, // 64kbps elegendő hanghoz
        sampleRate: 22050,
      ),
      path: _currentRecordPath!,
    );

    _recordStartMs = DateTime.now().millisecondsSinceEpoch;
    recordState.value = AudioRecordState.recording;
    recordDurationMs.value = 0;

    // Másodpercenkénti számláló
    _recordTimer = Timer.periodic(const Duration(milliseconds: 100), (_) {
      recordDurationMs.value =
          DateTime.now().millisecondsSinceEpoch - _recordStartMs!;
    });

    return true;
  }

  /// Felvétel leállítása és SQLite mentés
  Future<NoteItemAudio?> stopRecording(int noteItemId) async {
    if (recordState.value != AudioRecordState.recording) return null;

    _recordTimer?.cancel();
    _recordTimer = null;

    final path = await _recorder.stop();
    recordState.value = AudioRecordState.idle;

    if (path == null) return null;

    final durationSec =
        (DateTime.now().millisecondsSinceEpoch - _recordStartMs!) ~/ 1000;
    recordDurationMs.value = 0;
    _recordStartMs = null;

    // Nagyon rövid felvétel dobja el (véletlen érintés)
    if (durationSec < 1) {
      await File(path).delete().catchError((_) => File(path));
      return null;
    }

    // GPS pozíció
    final pos = await _currentPosition();

    final audio = NoteItemAudio(
      noteItemId: noteItemId,
      localPath: path,
      durationSeconds: durationSec,
      latitude: pos?.latitude,
      longitude: pos?.longitude,
      createdAt: DateTime.now(),
    );

    final id = await AppDatabase.instance.insertNoteAudio(audio);
    return NoteItemAudio(
      id: id,
      noteItemId: audio.noteItemId,
      localPath: audio.localPath,
      durationSeconds: audio.durationSeconds,
      latitude: audio.latitude,
      longitude: audio.longitude,
      createdAt: audio.createdAt,
    );
  }

  /// Felvétel megszakítása (mentés nélkül)
  Future<void> cancelRecording() async {
    if (recordState.value != AudioRecordState.recording) return;
    _recordTimer?.cancel();
    _recordTimer = null;
    recordDurationMs.value = 0;

    final path = await _recorder.stop();
    recordState.value = AudioRecordState.idle;
    if (path != null) {
      await File(path).delete().catchError((_) => File(path));
    }
  }

  // ── Lejátszás ─────────────────────────────────────────────────────────────

  Future<void> playAudio(NoteItemAudio audio) async {
    if (!audio.fileExists) {
      Get.snackbar('Fájl nem található', 'A hangjegyzet fájlja törlődött.',
          snackPosition: SnackPosition.BOTTOM);
      return;
    }

    // Ha ugyanaz játszik → pause/resume toggle
    if (playingAudioId.value == audio.id) {
      if (playState.value == AudioPlayState.playing) {
        await _player.pause();
        playState.value = AudioPlayState.paused;
      } else {
        await _player.resume();
        playState.value = AudioPlayState.playing;
      }
      return;
    }

    // Más vagy új clip
    await _player.stop();
    playingAudioId.value = audio.id;
    playState.value = AudioPlayState.playing;
    playPositionMs.value = 0;

    await _player.play(DeviceFileSource(audio.localPath));
  }

  Future<void> stopPlayback() async {
    await _player.stop();
    playState.value = AudioPlayState.idle;
    playingAudioId.value = null;
    playPositionMs.value = 0;
  }

  // ── Törlés ────────────────────────────────────────────────────────────────

  Future<void> deleteAudio(NoteItemAudio audio) async {
    // Leállítás ha épp játszik
    if (playingAudioId.value == audio.id) await stopPlayback();

    final file = File(audio.localPath);
    if (await file.exists()) await file.delete();
    await AppDatabase.instance.deleteNoteAudio(audio.id!);
  }

  Future<NoteItemAudio> updateCaption(
      NoteItemAudio audio, String caption) async {
    final updated = audio.copyWith(caption: caption);
    await AppDatabase.instance.updateNoteAudio(updated);
    return updated;
  }

  Future<List<NoteItemAudio>> loadAudios(int noteItemId) =>
      AppDatabase.instance.listNoteAudios(noteItemId);

  // ── Segéd ─────────────────────────────────────────────────────────────────

  Future<Position?> _currentPosition() async {
    try {
      return await Geolocator.getCurrentPosition(
        locationSettings: const LocationSettings(
            accuracy: LocationAccuracy.medium, timeLimit: Duration(seconds: 3)),
      ).timeout(const Duration(seconds: 3));
    } catch (_) {
      return Geolocator.getLastKnownPosition();
    }
  }

  // Formázott időtartam: ms → "0:42"
  String formatMs(int ms) {
    final s = ms ~/ 1000;
    final m = s ~/ 60;
    return '$m:${(s % 60).toString().padLeft(2, '0')}';
  }

  @override
  void onClose() {
    _recorder.dispose();
    _player.dispose();
    _recordTimer?.cancel();
    super.onClose();
  }
}
