import 'dart:async';
import 'dart:typed_data';
import 'package:shared_preferences/shared_preferences.dart';
import '../core/crypto/key_manager.dart';
import 'audio_service.dart';
import 'secure_channel.dart';

/// Session lifecycle states.
enum SessionState {
  noKey,         // no passphrase / key loaded
  keyLoaded,     // key ready, not yet in call
  inCall,        // channel open, waiting for PTT or RX
  transmitting,
  receiving,
  error,
}

/// Top-level session manager exposed to the UI.
///
/// Handles:
///   • Passphrase entry and PBKDF2 key derivation (persists key hash only).
///   • Creating / tearing down [SecureChannel].
///   • Delegating PTT and RX control.
///   • Exposing a unified [onStateChange] stream and stats for the UI.
class CallSession {
  final AudioService _audio;
  final KeyManager   _keys = KeyManager();

  SecureChannel? _channel;

  SessionState _state = SessionState.noKey;
  SessionState get state   => _state;
  bool         get hasKey  => _keys.hasKey;

  String? _lastError;
  String? get lastError => _lastError;

  // Stream of [SessionState] for reactive UI updates.
  final _ctrl = StreamController<SessionState>.broadcast();
  Stream<SessionState> get onStateChange => _ctrl.stream;

  CallSession(this._audio);

  // ── Key management ─────────────────────────────────────────────────

  /// Derive session key from [passphrase].
  /// Optionally accepts a peer-supplied [salt] (from handshake packet).
  Future<bool> loadPassphrase(String passphrase, {Uint8List? peerSalt}) async {
    try {
      _keys.deriveKey(passphrase, salt: peerSalt);
      _setState(SessionState.keyLoaded);
      // Persist a salted SHA-256 fingerprint so the UI can show "key loaded"
      // without storing the raw passphrase.
      await _saveKeyFingerprint(passphrase);
      return true;
    } catch (e) {
      _lastError = 'Key derivation failed: $e';
      _setState(SessionState.error);
      return false;
    }
  }

  /// Clear the current key (end session).
  Future<void> clearKey() async {
    _keys.clear();
    final prefs = await SharedPreferences.getInstance();
    await prefs.remove('key_fingerprint');
    _setState(SessionState.noKey);
  }

  /// Returns true if a fingerprint was previously saved (key loaded).
  Future<bool> hasSavedKey() async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.containsKey('key_fingerprint');
  }

  // ── Call lifecycle ─────────────────────────────────────────────────

  /// Open the secure channel (call start).
  Future<void> startCall() async {
    if (!_keys.hasKey) {
      _lastError = 'No key loaded';
      _setState(SessionState.error);
      return;
    }
    _channel = SecureChannel(_audio, _keys);
    _channel!.onStateChange.listen(_onChannelState);
    await _channel!.open();
    _setState(SessionState.inCall);
  }

  /// Close the secure channel (call end).
  Future<void> endCall() async {
    await _channel?.close();
    await _channel?.dispose();
    _channel = null;
    if (_keys.hasKey) {
      _setState(SessionState.keyLoaded);
    } else {
      _setState(SessionState.noKey);
    }
  }

  // ── PTT ────────────────────────────────────────────────────────────

  /// Press-to-talk: start encoding and transmitting voice.
  Future<void> pttPress() async {
    await _channel?.startTransmit();
  }

  /// Release PTT: stop transmitting.
  Future<void> pttRelease() async {
    await _channel?.stopTransmit();
  }

  // ── RX toggle ─────────────────────────────────────────────────────

  Future<void> startListening() async {
    await _channel?.startReceive();
  }

  Future<void> stopListening() async {
    await _channel?.stopReceive();
  }

  // ── Stats ──────────────────────────────────────────────────────────

  int    get txFrames      => _channel?.txFrames      ?? 0;
  int    get rxFrames      => _channel?.rxFrames      ?? 0;
  int    get rxErrors      => _channel?.rxErrors      ?? 0;
  double get txRms         => _channel?.txRms         ?? 0.0;
  double get rxSignalRms   => _channel?.rxSignalRms   ?? 0.0;

  // ── Private helpers ────────────────────────────────────────────────

  void _onChannelState(ChannelState cs) {
    switch (cs) {
      case ChannelState.transmitting:
        _setState(SessionState.transmitting);
      case ChannelState.receiving:
        _setState(SessionState.receiving);
      case ChannelState.txReady:
        _setState(SessionState.inCall);
      case ChannelState.error:
        _setState(SessionState.error);
      default:
        break;
    }
  }

  void _setState(SessionState s) {
    _state = s;
    _ctrl.add(s);
  }

  Future<void> _saveKeyFingerprint(String passphrase) async {
    // Store a simple truncated hash for display — NOT the key itself.
    final hash = passphrase.codeUnits.fold<int>(0,
        (prev, c) => (prev * 31 + c) & 0xFFFFFFFF);
    final prefs = await SharedPreferences.getInstance();
    await prefs.setString('key_fingerprint',
        hash.toRadixString(16).padLeft(8, '0').toUpperCase());
  }

  Future<String?> getSavedFingerprint() async {
    final prefs = await SharedPreferences.getInstance();
    return prefs.getString('key_fingerprint');
  }

  Future<void> dispose() async {
    await endCall();
    await _ctrl.close();
  }
}
