import 'dart:convert';

import 'package:flutter_test/flutter_test.dart';
import 'package:http/http.dart' as http;
import 'package:http/testing.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/domain/auth_models.dart';

void main() {
  test('posts phone login request to tdc114plus namespace', () async {
    final client = AuthApiClient(
      httpClient: MockClient((request) async {
        expect(
          request.url.toString(),
          'https://sso.example.test/api/v1/tdc114plus/auth/phone-login',
        );
        expect(request.method, 'POST');
        expect(request.headers['content-type'], 'application/json');
        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,
          headers: {'content-type': 'application/json'},
        );
      }),
      baseUri: Uri.parse('https://sso.example.test'),
    );

    final response = await client.phoneLogin(
      const PhoneLoginRequest(
        phoneNumber: '01012345678',
        device: LoginDeviceInfo(
          platform: 'android',
          appVersion: '0.1.0',
          deviceName: 'Pixel 8',
        ),
      ),
    );

    expect(response.token, 'session-token');
    expect(response.user.tenantSlug, 'hanmac');
  });

  test('throws ApiException when login fails', () async {
    final client = AuthApiClient(
      httpClient: MockClient((request) async {
        return http.Response(
          jsonEncode({
            'error': 'login failed',
            'code': 'login_failed',
            'details': {},
          }),
          401,
          headers: {'content-type': 'application/json'},
        );
      }),
      baseUri: Uri.parse('https://sso.example.test'),
    );

    expect(
      () => client.phoneLogin(
        const PhoneLoginRequest(
          phoneNumber: '01012345678',
          device: LoginDeviceInfo(
            platform: 'android',
            appVersion: '0.1.0',
            deviceName: 'Pixel 8',
          ),
        ),
      ),
      throwsA(
        isA<ApiException>()
            .having((error) => error.statusCode, 'statusCode', 401)
            .having((error) => error.code, 'code', 'login_failed'),
      ),
    );
  });

  test('requests phone link from auth server namespace', () async {
    final client = AuthApiClient(
      httpClient: MockClient((request) async {
        expect(
          request.url.toString(),
          'https://sso.example.test/api/v1/auth/link/init',
        );
        expect(request.method, 'POST');
        expect(jsonDecode(request.body)['phoneNumber'], '01012345678');
        return http.Response(
          jsonEncode({
            'status': 'pending',
            'pendingRef': 'pending-ref',
            'expiresIn': 180,
            'pollInterval': 3,
            'resendAfter': 30,
            'provider': 'Ory (Kratos/Hydra)',
          }),
          200,
          headers: {'content-type': 'application/json'},
        );
      }),
      baseUri: Uri.parse('https://sso.example.test'),
    );

    final response = await client.requestPhoneLoginLink(
      const PhoneLoginLinkInitRequest(
        phoneNumber: '01012345678',
        device: LoginDeviceInfo(
          platform: 'android',
          appVersion: '0.1.0',
          deviceName: 'Pixel 8',
        ),
      ),
    );

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

  test('polls headless phone link and parses completed session', () async {
    final client = AuthApiClient(
      httpClient: MockClient((request) async {
        expect(
          request.url.toString(),
          'https://sso.example.test/api/v1/auth/link/poll',
        );
        expect(jsonDecode(request.body)['pendingRef'], 'pending-ref');
        return http.Response(
          jsonEncode({
            'status': 'ok',
            'session': {
              '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,
          headers: {'content-type': 'application/json'},
        );
      }),
      baseUri: Uri.parse('https://sso.example.test'),
    );

    final response = await client.pollPhoneLoginLink(
      const PhoneLoginLinkPollRequest(pendingRef: 'pending-ref'),
    );

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

  test('parses completed auth-server poll response with top-level accessToken', () async {
    final client = AuthApiClient(
      httpClient: MockClient((request) async {
        expect(
          request.url.toString(),
          'https://auth.example.test/api/v1/auth/link/poll',
        );
        return http.Response(
          jsonEncode({
            'status': 'ok',
            'accessToken': 'app-session-jwt',
            'expiresAt': '2026-07-13T16:32:56+09:00',
            'user': {
              'id': 'baron-user',
              'name': 'Baron User',
              'phoneNumber': '01091365338',
            },
          }),
          200,
          headers: {'content-type': 'application/json'},
        );
      }),
      baseUri: Uri.parse('https://auth.example.test'),
    );

    final response = await client.pollPhoneLoginLink(
      const PhoneLoginLinkPollRequest(pendingRef: 'pending-ref'),
    );

    expect(response.status, 'ok');
    expect(response.session?.token, 'app-session-jwt');
    expect(response.session?.user.phoneNumber, '01091365338');
  });
}
