import 'dart:convert';

import 'package:commons_core/commons_core.dart';

import '../security/secret_store.dart';

/// Persists a 1:1 chat history, keystore-backed (so no plaintext at rest). A
/// capped, per-peer JSON list — recent history survives leaving the chat. Small
/// and simple on purpose; the encrypted Drift DB is the eventual home if chats
/// grow large.
/// A conversation preview for the messages inbox.
class ChatSummary {
  const ChatSummary({
    required this.peerPubkey,
    required this.lastText,
    required this.lastAt,
  });

  final String peerPubkey;
  final String lastText;
  final DateTime lastAt;
}

class MessageStore {
  MessageStore(this._store);

  final SecretStore _store;
  static const _prefix = 'tane.social.chat.';

  /// Index of peers we have a conversation with (the keystore is key/value with
  /// no key enumeration, so we track the list ourselves).
  static const _indexKey = 'tane.social.chats';

  /// Keep only the most recent [_cap] messages per conversation, to bound the
  /// keystore entry size.
  static const _cap = 200;

  String _key(String peerPubkey) => '$_prefix$peerPubkey';

  /// Messages exchanged with [peerPubkey], oldest first.
  Future<List<PrivateMessage>> history(String peerPubkey) async {
    final raw = await _store.read(_key(peerPubkey));
    if (raw == null || raw.isEmpty) return const [];
    final list = jsonDecode(raw) as List;
    return [
      for (final m in list.cast<Map<String, dynamic>>())
        PrivateMessage(
          fromPubkey: m['from'] as String,
          text: m['text'] as String,
          at: DateTime.fromMillisecondsSinceEpoch(m['at'] as int),
        ),
    ];
  }

  /// Appends [message] to the conversation with [peerPubkey] (trimming to the
  /// cap) and records the peer in the conversation index.
  Future<void> append(String peerPubkey, PrivateMessage message) async {
    final next = [...await history(peerPubkey), message];
    final capped =
        next.length > _cap ? next.sublist(next.length - _cap) : next;
    await _store.write(
      _key(peerPubkey),
      jsonEncode([
        for (final m in capped)
          {
            'from': m.fromPubkey,
            'text': m.text,
            'at': m.at.millisecondsSinceEpoch,
          },
      ]),
    );
    await _rememberPeer(peerPubkey);
  }

  /// Conversations, most-recently-active first (for the messages inbox).
  Future<List<ChatSummary>> conversations() async {
    final summaries = <ChatSummary>[];
    for (final peer in await _peers()) {
      final history = await this.history(peer);
      if (history.isEmpty) continue;
      final last = history.last;
      summaries.add(ChatSummary(
        peerPubkey: peer,
        lastText: last.text,
        lastAt: last.at,
      ));
    }
    summaries.sort((a, b) => b.lastAt.compareTo(a.lastAt));
    return summaries;
  }

  Future<List<String>> _peers() async {
    final raw = await _store.read(_indexKey);
    if (raw == null || raw.isEmpty) return const [];
    return raw.split('\n').where((s) => s.isNotEmpty).toList();
  }

  Future<void> _rememberPeer(String peer) async {
    final peers = await _peers();
    if (peers.contains(peer)) return;
    await _store.write(_indexKey, [...peers, peer].join('\n'));
  }
}
