import 'dart:convert';

import 'package:flutter_test/flutter_test.dart';
import 'package:gametime/application/application.dart';
import 'package:gametime/domain/domain.dart';
import 'package:gametime/infrastructure/remote/remote.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';

void main() {
  test(
    'sendShare maps local workout pack payload to server pack contract',
    () async {
      Map<String, Object?>? capturedBody;
      final api = HttpRemoteShareApi(
        HttpApiClient(
          baseUrl: Uri.parse('http://api.example.test'),
          client: MockClient((request) async {
            capturedBody = _jsonMap(request.body);
            expect(request.method, 'POST');
            expect(request.url.path, '/shares');
            expect(request.headers['authorization'], 'Bearer token-1');
            return http.Response(
              jsonEncode({
                'shareId': 'share-1',
                'recipientUserIds': ['user-2'],
                'unresolvedEmails': const <String>[],
              }),
              201,
            );
          }),
        ),
      );

      await api.sendShare(
        resourceType: ShareResourceType.pack,
        payload: const {
          'name': 'Pack reprise',
          'workouts': [
            {'id': 'template-1', 'name': 'Séance 1'},
            {'id': 'template-2', 'name': 'Séance 2'},
          ],
        },
        recipientEmails: const ['friend@example.com'],
        token: 'token-1',
      );

      expect(capturedBody, {
        'shareKind': 'pack',
        'packName': 'Pack reprise',
        'items': [
          {
            'resourceType': 'workoutTemplate',
            'payload': {'id': 'template-1', 'name': 'Séance 1'},
          },
          {
            'resourceType': 'workoutTemplate',
            'payload': {'id': 'template-2', 'name': 'Séance 2'},
          },
        ],
        'recipientEmails': ['friend@example.com'],
      });
    },
  );

  test(
    'fetchInbox maps server pack payload without resourceType to local pack',
    () async {
      final api = HttpRemoteShareApi(
        HttpApiClient(
          baseUrl: Uri.parse('http://api.example.test'),
          client: MockClient((request) async {
            expect(request.method, 'GET');
            expect(request.url.path, '/shares/inbox');
            return http.Response(
              jsonEncode({
                'items': [
                  {
                    'shareId': 'share-pack-1',
                    'senderUserId': 'sender-1',
                    'shareKind': 'pack',
                    'packName': 'Pack été',
                    'resourceType': null,
                    'payload': {
                      'items': [
                        {
                          'resourceType': 'workoutTemplate',
                          'payload': {'id': 'template-1', 'name': 'Séance 1'},
                        },
                      ],
                    },
                    'status': 'pending',
                    'createdAt': '2026-07-17T12:00:00.000Z',
                    'respondedAt': null,
                  },
                ],
              }),
              200,
            );
          }),
        ),
      );

      final items = await api.fetchInbox('token-1');
      final payload = _jsonMap(items.single.payloadJson);

      expect(items.single.resourceType, ShareResourceType.pack);
      expect(payload, {
        'name': 'Pack été',
        'workouts': [
          {'id': 'template-1', 'name': 'Séance 1'},
        ],
      });
    },
  );

  test(
    'acceptShare returns every created resource from server packs',
    () async {
      final api = HttpRemoteShareApi(
        HttpApiClient(
          baseUrl: Uri.parse('http://api.example.test'),
          client: MockClient((request) async {
            expect(request.method, 'POST');
            expect(request.url.path, '/shares/share-pack-1/accept');
            return http.Response(
              jsonEncode({
                'createdResources': [
                  _createdResourceJson(
                    resourceType: 'program',
                    clientId: 'program-1',
                    serverId: 'server-program-1',
                  ),
                  _createdResourceJson(
                    resourceType: 'workoutTemplate',
                    clientId: 'template-1',
                    serverId: 'server-template-1',
                  ),
                ],
              }),
              200,
            );
          }),
        ),
      );

      final resources = await api.acceptShare('share-pack-1', 'token-1');

      expect(resources.map((item) => item.resourceType), [
        SyncResourceType.program,
        SyncResourceType.workoutTemplate,
      ]);
      expect(resources.map((item) => item.clientId), [
        'program-1',
        'template-1',
      ]);
    },
  );
}

Map<String, Object?> _createdResourceJson({
  required String resourceType,
  required String clientId,
  required String serverId,
}) {
  return {
    'resourceType': resourceType,
    'clientId': clientId,
    'serverId': serverId,
    'schemaVersion': 1,
    'clientUpdatedAt': '2026-07-17T12:00:00.000Z',
    'serverUpdatedAt': '2026-07-17T12:01:00.000Z',
    'deletedAt': null,
    'payload': {'id': clientId},
  };
}

Map<String, Object?> _jsonMap(String source) {
  final decoded = jsonDecode(source);
  return Map<String, Object?>.from(decoded as Map);
}
