import 'dart:convert';

import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.dart';
import 'package:shared_preferences/shared_preferences.dart';
import 'package:tdc114plus/src/core/network/api_error.dart';
import 'package:tdc114plus/src/features/auth/data/auth_api_client.dart';
import 'package:tdc114plus/src/features/auth/data/auth_repository.dart';
import 'package:tdc114plus/src/features/auth/data/auth_session_store.dart';

void main() {
  setUp(() {
    SharedPreferences.setMockInitialValues({});
  });

  test('normalizes phone number and stores successful session', () async {
    final repository = RemoteAuthRepository(
      apiClient: AuthApiClient(
        httpClient: MockClient((request) async {
          expect(jsonDecode(request.body)['phoneNumber'], '01012345678');
          return http.Response(
            jsonEncode({
              'status': 'ok',
              'token': 'session-token',
              'expiresAt': '2026-07-02T12:00:00Z',
              'user': {
                'id': 'user-uuid',
                'name': 'User One',
                'phoneNumber': '+821012345678',
                'tenantId': 'tenant-uuid',
                'tenantName': 'Hanmac',
                'tenantSlug': 'hanmac',
              },
            }),
            200,
          );
        }),
        baseUri: Uri.parse('https://sso.example.test'),
      ),
      sessionStore: const AuthSessionStore(),
      appVersion: '0.1.0',
    );

    await repository.phoneLogin('010-1234-5678');
    final session = await repository.loadSession();

    expect(session?.token, 'session-token');
    expect(session?.user.id, 'user-uuid');
  });

  test('rejects invalid phone number before calling API', () async {
    var called = false;
    final repository = RemoteAuthRepository(
      apiClient: AuthApiClient(
        httpClient: MockClient((request) async {
          called = true;
          return http.Response('{}', 200);
        }),
        baseUri: Uri.parse('https://sso.example.test'),
      ),
      sessionStore: const AuthSessionStore(),
      appVersion: '0.1.0',
    );

    expect(
      () => repository.phoneLogin('123'),
      throwsA(
        isA<ApiException>().having(
          (error) => error.code,
          'code',
          'invalid_phone_number',
        ),
      ),
    );
    expect(called, isFalse);
  });

  test('normalizes phone number before requesting login link', () async {
    final repository = RemoteAuthRepository(
      apiClient: AuthApiClient(
        httpClient: MockClient((request) async {
          expect(request.url.path, '/api/v1/auth/link/init');
          expect(jsonDecode(request.body)['phoneNumber'], '01012345678');
          return http.Response(
            jsonEncode({
              'status': 'pending',
              'pendingRef': 'pending-ref',
              'expiresIn': 180,
              'pollInterval': 3,
              'resendAfter': 30,
            }),
            200,
          );
        }),
        baseUri: Uri.parse('https://sso.example.test'),
      ),
      sessionStore: const AuthSessionStore(),
      appVersion: '0.1.0',
    );

    final response = await repository.requestPhoneLoginLink('010-1234-5678');

    expect(response.pendingRef, 'pending-ref');
  });

  test('stores session when login link polling completes', () async {
    final repository = RemoteAuthRepository(
      apiClient: AuthApiClient(
        httpClient: MockClient((request) async {
          expect(request.url.path, '/api/v1/auth/link/poll');
          return http.Response(
            jsonEncode({
              'status': 'ok',
              'accessToken': 'session-token',
              'expiresAt': '2026-07-02T12:00:00Z',
              'user': {
                'id': 'user-uuid',
                'name': 'User One',
                'phoneNumber': '+821012345678',
                'tenantId': 'tenant-uuid',
                'tenantName': 'Hanmac',
                'tenantSlug': 'hanmac',
              },
            }),
            200,
          );
        }),
        baseUri: Uri.parse('https://sso.example.test'),
      ),
      sessionStore: const AuthSessionStore(),
      appVersion: '0.1.0',
    );

    final response = await repository.pollPhoneLoginLink('pending-ref');
    final session = await repository.loadSession();

    expect(response.session?.token, 'session-token');
    expect(session?.token, 'session-token');
  });
}
