import 'package:flutter_test/flutter_test.dart'; import 'package:motorcycle_dash/features/social/clubs/club_membership_presentation.dart'; import 'package:motorcycle_dash/services/clubs/club_models.dart'; void main() { group('ClubMembershipPresentation Unit Tests', () { final baseClub = Club( id: 'test_club_1', name: 'NorCal Adventurers', slug: 'norcal-adv', description: 'Adventure riding club', ownerUid: 'owner_uid', memberCount: 10, visibility: ClubVisibility.public, admissionPolicy: ClubAdmissionPolicy.open, createdAt: DateTime(2026, 1, 1), updatedAt: DateTime(2026, 1, 1), ); test('resolves unavailable when club is null', () { final p = ClubMembershipPresentation.resolve( club: null, member: null, currentUserId: 'rider_1', isAuthenticated: true, ); expect(p.state, ClubMembershipPresentationState.unavailable); expect(p.statusBadge, 'UNAVAILABLE'); expect(p.isActionable, isFalse); expect(p.primaryAction, isNull); }); test('resolves archived state when club.isArchived is true', () { final archivedClub = baseClub.copyWith(archivedAt: DateTime(2026, 2, 1)); final p = ClubMembershipPresentation.resolve( club: archivedClub, member: null, currentUserId: 'rider_1', isAuthenticated: true, ); expect(p.state, ClubMembershipPresentationState.archived); expect(p.statusBadge, 'ARCHIVED'); expect(p.badgeType, PresentationBadgeType.amber); expect(p.canLeave, isFalse); expect(p.isActionable, isFalse); expect(p.primaryAction, isNull); }); test('resolves unauthenticated state when signed out or anonymous', () { final p1 = ClubMembershipPresentation.resolve( club: baseClub, member: null, currentUserId: null, isAuthenticated: false, ); expect(p1.state, ClubMembershipPresentationState.unauthenticated); expect(p1.statusBadge, 'GUEST'); expect(p1.primaryAction, ClubMembershipAction.signIn); expect(p1.isActionable, isTrue); final p2 = ClubMembershipPresentation.resolve( club: baseClub, member: null, currentUserId: '', isAuthenticated: true, ); expect(p2.state, ClubMembershipPresentationState.unauthenticated); }); test('resolves outsiderOpen for open admission when unjoined', () { final p = ClubMembershipPresentation.resolve( club: baseClub.copyWith(admissionPolicy: ClubAdmissionPolicy.open), member: null, currentUserId: 'rider_1', isAuthenticated: true, ); expect(p.state, ClubMembershipPresentationState.outsiderOpen); expect(p.statusBadge, 'OPEN ADMISSION'); expect(p.badgeType, PresentationBadgeType.cyan); expect(p.primaryAction, ClubMembershipAction.joinOpen); expect(p.primaryActionLabel, 'Join Club'); expect(p.canLeave, isFalse); }); test('resolves outsiderRequest for request admission when unjoined', () { final p = ClubMembershipPresentation.resolve( club: baseClub.copyWith(admissionPolicy: ClubAdmissionPolicy.request), member: null, currentUserId: 'rider_1', isAuthenticated: true, ); expect(p.state, ClubMembershipPresentationState.outsiderRequest); expect(p.statusBadge, 'REQUEST REQUIRED'); expect(p.primaryAction, ClubMembershipAction.requestToJoin); expect(p.primaryActionLabel, 'Request to Join'); }); test('resolves outsiderInviteOnly for invite-only admission when unjoined', () { final p = ClubMembershipPresentation.resolve( club: baseClub.copyWith(admissionPolicy: ClubAdmissionPolicy.inviteOnly), member: null, currentUserId: 'rider_1', isAuthenticated: true, ); expect(p.state, ClubMembershipPresentationState.outsiderInviteOnly); expect(p.statusBadge, 'INVITE ONLY'); expect(p.primaryAction, isNull); expect(p.isActionable, isFalse); }); test('resolves historical states (left, declined, removed) as re-joinable outsiders', () { for (final status in [ClubMemberStatus.left, ClubMemberStatus.declined, ClubMemberStatus.removed]) { final member = ClubMember( uid: 'rider_1', clubId: baseClub.id, status: status, role: ClubRole.member, updatedAt: DateTime(2026, 1, 1), ); final p = ClubMembershipPresentation.resolve( club: baseClub.copyWith(admissionPolicy: ClubAdmissionPolicy.open), member: member, currentUserId: 'rider_1', isAuthenticated: true, ); expect(p.state, ClubMembershipPresentationState.outsiderOpen); expect(p.primaryAction, ClubMembershipAction.joinOpen); } }); test('resolves invited state with accept and decline actions', () { final invitedMember = ClubMember( uid: 'rider_1', clubId: baseClub.id, status: ClubMemberStatus.invited, role: ClubRole.member, invitedByUid: 'owner_uid', updatedAt: DateTime(2026, 1, 1), ); final p = ClubMembershipPresentation.resolve( club: baseClub, member: invitedMember, currentUserId: 'rider_1', isAuthenticated: true, ); expect(p.state, ClubMembershipPresentationState.invited); expect(p.statusBadge, 'INVITED'); expect(p.primaryAction, ClubMembershipAction.acceptInvite); expect(p.primaryActionLabel, 'Accept Invitation'); expect(p.secondaryAction, ClubMembershipAction.declineInvite); expect(p.secondaryActionLabel, 'Decline'); expect(p.isSecondaryDestructive, isTrue); expect(p.canLeave, isFalse); }); test('resolves requested state with withdraw request action', () { final requestedMember = ClubMember( uid: 'rider_1', clubId: baseClub.id, status: ClubMemberStatus.requested, role: ClubRole.member, requestedAt: DateTime(2026, 1, 1), updatedAt: DateTime(2026, 1, 1), ); final p = ClubMembershipPresentation.resolve( club: baseClub, member: requestedMember, currentUserId: 'rider_1', isAuthenticated: true, ); expect(p.state, ClubMembershipPresentationState.requested); expect(p.statusBadge, 'REQUEST PENDING'); expect(p.badgeType, PresentationBadgeType.amber); expect(p.primaryAction, ClubMembershipAction.withdrawRequest); expect(p.primaryActionLabel, 'Withdraw Request'); expect(p.isPrimaryDestructive, isTrue); expect(p.canLeave, isFalse); }); test('resolves activeMember state with leave club action', () { final activeMember = ClubMember( uid: 'rider_1', clubId: baseClub.id, status: ClubMemberStatus.active, role: ClubRole.member, joinedAt: DateTime(2026, 1, 1), updatedAt: DateTime(2026, 1, 1), ); final p = ClubMembershipPresentation.resolve( club: baseClub, member: activeMember, currentUserId: 'rider_1', isAuthenticated: true, ); expect(p.state, ClubMembershipPresentationState.activeMember); expect(p.statusBadge, 'MEMBER'); expect(p.primaryAction, ClubMembershipAction.leaveClub); expect(p.primaryActionLabel, 'Leave Club'); expect(p.isPrimaryDestructive, isTrue); expect(p.canLeave, isTrue); }); test('resolves activeAdmin state with leave club action', () { final activeAdmin = ClubMember( uid: 'rider_admin', clubId: baseClub.id, status: ClubMemberStatus.active, role: ClubRole.admin, joinedAt: DateTime(2026, 1, 1), updatedAt: DateTime(2026, 1, 1), ); final p = ClubMembershipPresentation.resolve( club: baseClub, member: activeAdmin, currentUserId: 'rider_admin', isAuthenticated: true, ); expect(p.state, ClubMembershipPresentationState.activeAdmin); expect(p.statusBadge, 'ADMIN'); expect(p.primaryAction, ClubMembershipAction.leaveClub); expect(p.canLeave, isTrue); }); test('resolves activeOwner state where owner cannot leave', () { final activeOwner = ClubMember( uid: 'owner_uid', clubId: baseClub.id, status: ClubMemberStatus.active, role: ClubRole.owner, joinedAt: DateTime(2026, 1, 1), updatedAt: DateTime(2026, 1, 1), ); final p = ClubMembershipPresentation.resolve( club: baseClub, member: activeOwner, currentUserId: 'owner_uid', isAuthenticated: true, ); expect(p.state, ClubMembershipPresentationState.activeOwner); expect(p.statusBadge, 'OWNER'); expect(p.badgeType, PresentationBadgeType.green); expect(p.primaryAction, isNull); expect(p.canLeave, isFalse); expect(p.isActionable, isFalse); expect(p.statusDescription, contains('Ownership must be transferred')); }); }); }