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/features/directory/data/directory_repository.dart';
import 'package:tdc114plus/src/features/auth/data/auth_session_store.dart';
import 'package:tdc114plus/src/features/auth/domain/auth_models.dart';
import 'package:tdc114plus/src/features/organization/data/org_context_api_client.dart';
import 'package:shared_preferences/shared_preferences.dart';

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

  test('maps Baron org-context response to app org chart snapshot', () async {
    final client = OrgContextApiClient(
      httpClient: MockClient((request) async {
        expect(request.url.path, '/api/v1/integrations/org-context');
        expect(request.url.queryParameters['tenantSlug'], 'hanmac-family');
        expect(request.url.queryParameters['includeUsers'], 'true');
        expect(request.url.queryParameters['includeUserIds'], 'true');
        expect(request.headers.containsKey('X-Baron-Key-ID'), isFalse);
        expect(request.headers.containsKey('X-Baron-Key-Secret'), isFalse);

        return _jsonResponse(_orgContextResponse());
      }),
      baseUri: Uri.parse('https://sadmin.hmac.kr'),
      tenantSlug: 'hanmac-family',
    );

    final snapshot = await client.fetchOrgContext();

    expect(snapshot.tenants.map((tenant) => tenant.slug), contains('is3'));
    expect(snapshot.employees, hasLength(4));
    expect(snapshot.employees.first.tenantName, 'IS3');
    expect(snapshot.employees.first.phoneDisplay, '010-3189-1514');

    final center = snapshot.tenants.singleWhere(
      (tenant) => tenant.slug == 'center',
    );
    final is3 = snapshot.tenants.singleWhere((tenant) => tenant.slug == 'is3');
    expect(center.totalMemberCount, 4);
    expect(is3.memberCount, 2);
    expect(is3.totalMemberCount, 2);
  });

  test('does not persist or send session org-context credentials', () async {
    const store = AuthSessionStore();
    await store.save(
      PhoneLoginResponse(
        status: 'ok',
        token: 'session-token',
        expiresAt: DateTime.now().toUtc().add(const Duration(hours: 1)),
        user: const LoginUser(
          id: 'user-id',
          name: 'User',
          phoneNumber: '',
          tenantId: '',
          tenantName: '',
          tenantSlug: '',
        ),
      ),
    );

    final client = OrgContextApiClient(
      httpClient: MockClient((request) async {
        expect(request.url.host, 'env.example.test');
        expect(request.url.queryParameters['tenantSlug'], 'env-family');
        expect(request.headers['Authorization'], 'Bearer session-token');
        expect(request.headers.containsKey('X-Baron-Key-ID'), isFalse);
        expect(request.headers.containsKey('X-Baron-Key-Secret'), isFalse);
        return _jsonResponse(_orgContextResponse());
      }),
      baseUri: Uri.parse('https://env.example.test'),
      tenantSlug: 'env-family',
      sessionStore: store,
    );

    await client.fetchOrgContext();
  });

  test('uses requested tenant slug for scoped org-context reads', () async {
    final client = OrgContextApiClient(
      httpClient: MockClient((request) async {
        expect(request.url.queryParameters['tenantSlug'], 'is3');
        return _jsonResponse(_orgContextResponse());
      }),
      baseUri: Uri.parse('https://sadmin.hmac.kr'),
      tenantSlug: 'hanmac-family',
    );

    await client.fetchOrgContext(tenantSlug: 'is3');
  });

  test('caches org-context response by requested tenant slug', () async {
    final requestedTenantSlugs = <String>[];
    final client = OrgContextApiClient(
      httpClient: MockClient((request) async {
        requestedTenantSlugs.add(request.url.queryParameters['tenantSlug']!);
        return _jsonResponse(_orgContextResponse());
      }),
      baseUri: Uri.parse('https://114-auth.hmac.kr'),
      tenantSlug: 'hanmac-family',
    );

    await client.fetchOrgContext(tenantSlug: 'is3');
    await client.fetchOrgContext(tenantSlug: 'is3');
    await client.fetchOrgContext(tenantSlug: 'samahn');

    expect(requestedTenantSlugs, ['is3', 'samahn']);
  });

  test('uses app session bearer token for auth-server org-context proxy', () async {
    const store = AuthSessionStore();
    await store.save(
      PhoneLoginResponse(
        status: 'ok',
        token: 'app-session-token',
        expiresAt: DateTime.now().toUtc().add(const Duration(hours: 1)),
        user: const LoginUser(
          id: 'user-id',
          name: 'User',
          phoneNumber: '',
          tenantId: '',
          tenantName: '',
          tenantSlug: '',
        ),
      ),
    );

    final client = OrgContextApiClient(
      httpClient: MockClient((request) async {
        expect(request.url.host, '114-auth.hmac.kr');
        expect(request.url.path, '/api/v1/integrations/org-context');
        expect(request.headers['Authorization'], 'Bearer app-session-token');
        expect(request.headers.containsKey('X-Baron-Key-ID'), isFalse);
        expect(request.headers.containsKey('X-Baron-Key-Secret'), isFalse);
        return _jsonResponse(_orgContextResponse());
      }),
      baseUri: Uri.parse('https://114-auth.hmac.kr'),
      tenantSlug: 'hanmac-family',
      sessionStore: store,
    );

    await client.fetchOrgContext();
  });

  test('caches org-context response for repeated badge navigation reads', () async {
    var requestCount = 0;
    final client = OrgContextApiClient(
      httpClient: MockClient((request) async {
        requestCount += 1;
        expect(request.url.path, '/api/v1/integrations/org-context');
        return _jsonResponse(_orgContextResponse());
      }),
      baseUri: Uri.parse('https://114-auth.hmac.kr'),
      tenantSlug: 'hanmac-family',
    );

    await client.fetchOrgContext();
    await client.fetchOrgContext();

    expect(requestCount, 1);
  });

  test('uses configured auth-server org-context endpoint without Baron key headers', () async {
    final client = OrgContextApiClient(
      httpClient: MockClient((request) async {
        expect(request.url.host, 'env.example.test');
        expect(request.url.queryParameters['tenantSlug'], 'env-family');
        expect(request.headers.containsKey('X-Baron-Key-ID'), isFalse);
        expect(request.headers.containsKey('X-Baron-Key-Secret'), isFalse);
        return _jsonResponse(_orgContextResponse());
      }),
      baseUri: Uri.parse('https://env.example.test'),
      tenantSlug: 'env-family',
      sessionStore: const AuthSessionStore(),
    );

    await client.fetchOrgContext();
  });

  test(
    'remote directory repository filters org-context employees locally',
    () async {
      final client = OrgContextApiClient(
        httpClient: MockClient((request) async {
          expect(request.url.queryParameters['tenantSlug'], 'is3');
          return _jsonResponse(_orgContextResponse());
        }),
        baseUri: Uri.parse('https://sadmin.hmac.kr'),
        tenantSlug: 'hanmac-family',
      );
      final repository = RemoteDirectoryRepository(orgContextApiClient: client);

      final employees = await repository.loadEmployees(
        const DirectoryQuery(query: '한', tenantSlug: 'is3'),
      );

      expect(employees.map((employee) => employee.name), ['한승민']);
    },
  );

  test(
    'remote directory repository searches selected tenant subtree',
    () async {
      final client = OrgContextApiClient(
        httpClient: MockClient((request) async {
          expect(request.url.queryParameters['tenantSlug'], 'center');
          return _jsonResponse(_orgContextResponse());
        }),
        baseUri: Uri.parse('https://sadmin.hmac.kr'),
        tenantSlug: 'hanmac-family',
      );
      final repository = RemoteDirectoryRepository(orgContextApiClient: client);

      final employees = await repository.loadEmployees(
        const DirectoryQuery(
          query: '박',
          tenantSlug: 'center',
          tenantSlugs: ['center', 'is3', 'is2'],
        ),
      );

      expect(employees.map((employee) => employee.name), ['박주한']);
    },
  );

  test(
    'remote directory repository preserves department memberships for duplicate users',
    () async {
      final client = OrgContextApiClient(
        httpClient: MockClient((_) async {
          return _jsonResponse(_orgContextResponse());
        }),
        baseUri: Uri.parse('https://sadmin.hmac.kr'),
        tenantSlug: 'hanmac-family',
      );
      final repository = RemoteDirectoryRepository(orgContextApiClient: client);

      final employees = await repository.loadEmployees(
        const DirectoryQuery(query: '', tenantSlug: 'all', department: 'IS3'),
      );

      expect(employees.map((employee) => employee.name), ['한승민', '김윤재']);
    },
  );
}

Map<String, dynamic> _orgContextResponse() {
  return {
    'schemaVersion': 'baron.org-context.v1',
    'issuedAt': '2026-07-08T10:07:07.182Z',
    'scope': {'tenantId': 'family-id', 'tenantSlug': 'hanmac-family'},
    'tree': {
      'id': 'family-id',
      'type': 'COMPANY_GROUP',
      'name': '한맥가족',
      'slug': 'hanmac-family',
      'memberCount': 0,
      'children': [
        {
          'id': 'center-id',
          'type': 'DEPARTMENT',
          'name': '총괄기획&기술개발센터',
          'slug': 'center',
          'parentId': 'family-id',
          'memberCount': 0,
        },
      ],
    },
    'tenants': [
      {
        'id': 'is3-id',
        'type': 'TEAM',
        'name': 'IS3',
        'slug': 'is3',
        'parentId': 'center-id',
        'memberCount': 0,
        'members': [
          {
            'id': 'user-han',
            'name': '한승민',
            'phone': '+821031891514',
            'email': 'han@example.com',
            'department': 'IS3',
            'position': '팀장',
            'status': 'active',
          },
          {
            'id': 'user-kim',
            'name': '김윤재',
            'phone': '01097479838',
            'email': 'kim@example.com',
            'department': 'IS3',
            'position': '연구원',
            'status': 'active',
          },
        ],
      },
      {
        'id': 'is2-id',
        'type': 'TEAM',
        'name': 'IS2',
        'slug': 'is2',
        'parentId': 'center-id',
        'memberCount': 0,
        'members': [
          {
            'id': 'user-park',
            'name': '박주한',
            'phone': '01089553850',
            'email': 'park@example.com',
            'department': 'IS2',
            'position': '연구원',
            'status': 'active',
          },
          {
            'id': 'user-han',
            'name': '한승민',
            'phone': '01031891514',
            'email': 'han@example.com',
            'department': 'IS2',
            'position': '팀장',
            'status': 'active',
          },
        ],
      },
    ],
  };
}

http.Response _jsonResponse(Map<String, dynamic> body) {
  return http.Response.bytes(
    utf8.encode(jsonEncode(body)),
    200,
    headers: {'content-type': 'application/json; charset=utf-8'},
  );
}
