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 'package:slrpg_app/src/shared/data/repositories/user_repository.dart';
import '../../../../core/constants/app_constants.dart';
import '../../../../shared/data/remote/api_client.dart';

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

class PartyRepository {
  final ApiClient _api;
  final PocketBase _pb;

  PartyRepository(this._api) : _pb = PocketBase(AppConstants.apiBaseUrl);

  Future<void> _syncAuth() async {
    final token = await _api.getToken();
    if (token != null) {
      _pb.authStore.save(token, null);
    }
  }

  Future<Party> createParty() async {
    final response = await _api.dio.post('/api/v1/party/create');
    final partyId = response.data['party_id'];
    return getPartyDetails(partyId);
  }

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

  Future<Party> getPartyDetails(String partyId) async {
    final response =
        await _api.dio.get('/api/collections/parties/records/$partyId');
    return Party.fromJson(response.data);
  }

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

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

    if (members.items.isNotEmpty) {
      await _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 _pb.collection('parties').update(partyId, body: body);
  }

  Stream<Party> subscribeToParty(String partyId) async* {
    await _syncAuth();

    yield await getPartyDetails(partyId);

    final controller = StreamController<Party>();

    _pb.collection('parties').subscribe(partyId, (e) {
      if (e.action == 'update') {
        controller.add(Party.fromJson(e.record!.toJson()));
      }
    });

    yield* controller.stream;
  }

  Stream<List<PartyMember>> subscribeToMembers(String partyId) async* {
    await _syncAuth();

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

    yield await fetchMembers();

    final controller = StreamController<List<PartyMember>>();

    _pb.collection('party_members').subscribe('*', (e) async {
      if (e.record!.getStringValue('party_id') == partyId) {
        controller.add(await fetchMembers());
      }
    });

    yield* controller.stream;
  }

  Future<void> dealDamage(String partyId, int damage) async {
    await _api.dio.post(
      '/api/v1/party/damage',
      data: {
        'party_id': partyId,
        'damage': damage,
      },
    );
  }

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

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