import 'dart:async';
import 'dart:developer';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:pocketbase/pocketbase.dart';
import 'package:slrpg_app/src/features/multiplayer/domain/entities/party.dart';
import 'package:slrpg_app/src/features/multiplayer/domain/entities/party_member.dart';
import '../../../../shared/data/remote/api_client.dart';

final partyRepositoryProvider = Provider((ref) {
  return PartyRepository(ref.read(apiClientProvider));
});

class PartyRepository {
  final ApiClient _api;

  PartyRepository(this._api);

  Future<Party> createParty() async {
    final response = await _api.pb.send('/api/v1/party/create', method: 'POST');
    final partyId = response['party_id'];
    return getPartyDetails(partyId);
  }

  Future<Party> joinParty(String code) async {
    final response = await _api.pb.send(
      '/api/v1/party/join',
      method: 'POST',
      body: {'code': code},
    );
    final partyId = response['party_id'];
    return getPartyDetails(partyId);
  }

  Future<Party> getPartyDetails(String partyId) async {
    final record = await _api.pb.collection('parties').getOne(partyId);
    return Party.fromJson(record.toJson());
  }

  Future<void> setReady(String partyId, bool isReady) async {
    final userId = _api.getUserId()!;

    final members = await _api.pb.collection('party_members').getList(
          filter: 'party_id="$partyId" && user_id="$userId"',
        );

    if (members.items.isNotEmpty) {
      await _api.pb.collection('party_members').update(
        members.items.first.id,
        body: {'is_ready': isReady},
      );
    }
  }

  Future<void> startRaid(String partyId, {int? customHp}) async {
    final body = <String, dynamic>{'status': 'active'};

    if (customHp != null) {
      body['current_hp'] = customHp;
      body['max_hp'] = customHp;
    }

    await _api.pb.collection('parties').update(partyId, body: body);
  }

  Stream<Party> subscribeToParty(String partyId) {
    late StreamController<Party> controller;
    UnsubscribeFunc? unsubscribe;

    controller = StreamController<Party>(
      onListen: () async {
        try {
          final initial = await getPartyDetails(partyId);
          controller.add(initial);
        } catch (e) {
          controller.addError(e);
        }

        unsubscribe =
            await _api.pb.collection('parties').subscribe(partyId, (e) {
          if (e.action == 'update' && e.record != null) {
            controller.add(Party.fromJson(e.record!.toJson()));
          }
        });
      },
      onCancel: () async {
        await unsubscribe?.call();
        log('🔌 Unsubscribed from party $partyId');
      },
    );

    return controller.stream;
  }

  Stream<List<PartyMember>> subscribeToMembers(String partyId) {
    late StreamController<List<PartyMember>> controller;
    UnsubscribeFunc? unsubscribe;

    Future<List<PartyMember>> fetchMembers() async {
      final records = await _api.pb.collection('party_members').getFullList(
            filter: 'party_id="$partyId"',
            expand: 'user_id',
          );
      return records.map((r) => PartyMember.fromRecord(r.toJson())).toList();
    }

    controller = StreamController<List<PartyMember>>(
      onListen: () async {
        try {
          controller.add(await fetchMembers());
        } catch (e) {
          controller.addError(e);
        }

        unsubscribe =
            await _api.pb.collection('party_members').subscribe('*', (e) async {
          if (e.record != null &&
              e.record!.getStringValue('party_id') == partyId) {
            controller.add(await fetchMembers());
          }
        });
      },
      onCancel: () async {
        await unsubscribe?.call();
        log('🔌 Unsubscribed from party members $partyId');
      },
    );

    return controller.stream;
  }

  Future<void> dealDamage(String partyId, int damage) async {
    await _api.pb.send(
      '/api/v1/party/damage',
      method: 'POST',
      body: {
        'party_id': partyId,
        'damage': damage,
      },
    );
  }

  Future<void> leaveParty(String partyId, String userId) async {
    try {
      final result = await _api.pb.collection('party_members').getList(
            filter: 'party_id="$partyId" && user_id="$userId"',
          );

      if (result.items.isNotEmpty) {
        final memberId = result.items.first.id;
        await _api.pb.collection('party_members').delete(memberId);
      }
    } catch (e) {
      log('Error leaving party: $e');
    }
  }
}
