import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:get_it/get_it.dart';
import 'package:go_router/go_router.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart' as lucide;
import 'package:shadcn_ui/shadcn_ui.dart';

import 'package:superport_v2/core/common/models/paginated_result.dart';
import 'package:superport_v2/core/constants/app_sections.dart';
import 'package:superport_v2/core/permissions/permission_manager.dart';
import 'package:superport_v2/core/theme/superport_shad_theme.dart';
import 'package:superport_v2/core/theme/theme_controller.dart';
import 'package:superport_v2/core/services/token_storage.dart';
import 'package:superport_v2/features/auth/application/auth_service.dart';
import 'package:superport_v2/features/auth/domain/entities/auth_permission.dart';
import 'package:superport_v2/features/auth/domain/entities/auth_session.dart';
import 'package:superport_v2/features/auth/domain/entities/authenticated_user.dart';
import 'package:superport_v2/features/auth/domain/entities/login_request.dart';
import 'package:superport_v2/features/auth/domain/repositories/auth_repository.dart';
import 'package:superport_v2/features/masters/user/domain/entities/user.dart';
import 'package:superport_v2/features/masters/user/domain/repositories/user_repository.dart';
import 'package:superport_v2/widgets/app_shell.dart';

void main() {
  setUp(() {
    GetIt.I.reset();
  });

  testWidgets('계정 버튼을 누르면 계정 정보 다이얼로그가 표시된다', (tester) async {
    final session = _buildSession();
    final authService = _createAuthService(session);
    GetIt.I.registerSingleton<AuthService>(authService);
    GetIt.I.registerSingleton<UserRepository>(_StubUserRepository());
    addTearDown(authService.dispose);
    await authService.login(
      const LoginRequest(identifier: 'user@example.com', password: 'secret'),
    );

    await _pumpAppShell(tester);

    await tester.tap(find.byIcon(lucide.LucideIcons.userRound));
    await tester.pumpAndSettle();

    expect(find.text('내 정보'), findsOneWidget);
    expect(find.text('김승인'), findsWidgets);
    expect(find.text('E2025001'), findsOneWidget);
    expect(find.text('물류팀'), findsOneWidget);
    expect(find.text('연락처 / 이메일 수정'), findsOneWidget);
    expect(find.text('비밀번호 변경'), findsOneWidget);
    expect(find.textContaining('/approvals'), findsOneWidget);
  });

  testWidgets('다이얼로그에서 로그아웃을 누르면 세션이 초기화되고 로그인 화면으로 이동한다', (tester) async {
    final session = _buildSession();
    final authService = _createAuthService(session);
    GetIt.I.registerSingleton<AuthService>(authService);
    GetIt.I.registerSingleton<UserRepository>(_StubUserRepository());
    addTearDown(authService.dispose);
    await authService.login(
      const LoginRequest(identifier: 'user@example.com', password: 'secret'),
    );

    await _pumpAppShell(tester);

    expect(authService.session, isNotNull);

    await tester.tap(find.byIcon(lucide.LucideIcons.userRound));
    await tester.pumpAndSettle();

    await tester.tap(find.text('로그아웃'));
    await tester.pumpAndSettle();

    expect(authService.session, isNull);
    expect(find.text('로그인 페이지'), findsOneWidget);
  });

  testWidgets('내 정보 다이얼로그에서 연락처/이메일 저장 시 updateMe 호출', (tester) async {
    final session = _buildSession();
    final authService = _createAuthService(session);
    final captured = <UserProfileUpdateInput>[];
    final repository = _StubUserRepository(
      onUpdateMe: (input) async {
        captured.add(input);
        return UserAccount(
          id: session.user.id,
          employeeNo: session.user.employeeNo ?? '',
          employeeName: session.user.name,
          email: input.email,
          mobileNo: input.phone,
          group: UserGroup(id: 1, groupName: '물류팀'),
        );
      },
    );

    GetIt.I.registerSingleton<AuthService>(authService);
    GetIt.I.registerSingleton<UserRepository>(repository);
    addTearDown(authService.dispose);
    await authService.login(
      const LoginRequest(identifier: 'user@example.com', password: 'secret'),
    );

    final view = tester.view;
    view.physicalSize = const Size(1600, 900);
    view.devicePixelRatio = 1.0;
    addTearDown(() {
      view.resetPhysicalSize();
      view.resetDevicePixelRatio();
    });

    await _pumpAppShell(tester);

    await tester.tap(find.byIcon(lucide.LucideIcons.userRound));
    await tester.pumpAndSettle();

    await tester.enterText(
      find.byKey(const ValueKey('account_email_field')),
      'new@superport.com',
    );
    await tester.enterText(
      find.byKey(const ValueKey('account_phone_field')),
      '+82-10-9999-8888',
    );

    await tester.tap(find.text('저장'));
    await tester.pumpAndSettle();

    expect(captured, hasLength(1));
    final input = captured.single;
    expect(input.email, 'new@superport.com');
    expect(input.phone, '+82-10-9999-8888');
    expect(authService.session?.user.email, 'new@superport.com');
    expect(authService.session?.user.phone, '+82-10-9999-8888');
  });

  testWidgets('비밀번호 변경 완료 시 강제 로그아웃 안내 후 세션 초기화', (tester) async {
    final session = _buildSession();
    final authService = _createAuthService(session);
    UserProfileUpdateInput? passwordInput;
    final repository = _StubUserRepository(
      onUpdateMe: (input) async {
        passwordInput = input;
        return UserAccount(
          id: session.user.id,
          employeeNo: session.user.employeeNo ?? '',
          employeeName: session.user.name,
          email: input.email ?? session.user.email,
          mobileNo: input.phone ?? session.user.phone,
          group: UserGroup(id: 1, groupName: '물류팀'),
        );
      },
    );

    GetIt.I.registerSingleton<AuthService>(authService);
    GetIt.I.registerSingleton<UserRepository>(repository);
    addTearDown(authService.dispose);
    await authService.login(
      const LoginRequest(identifier: 'user@example.com', password: 'secret'),
    );

    final view = tester.view;
    view.physicalSize = const Size(1600, 900);
    view.devicePixelRatio = 1.0;
    addTearDown(() {
      view.resetPhysicalSize();
      view.resetDevicePixelRatio();
    });

    await _pumpAppShell(tester);

    await tester.tap(find.byIcon(lucide.LucideIcons.userRound));
    await tester.pumpAndSettle();

    final changeButton = find.text('비밀번호 변경');
    await tester.ensureVisible(changeButton);
    await tester.tap(changeButton);
    await tester.pumpAndSettle();

    await tester.enterText(
      find.byKey(const ValueKey('account_current_password')),
      'TempPass1!',
    );
    await tester.enterText(
      find.byKey(const ValueKey('account_new_password')),
      'Aa1!zzzz',
    );
    await tester.enterText(
      find.byKey(const ValueKey('account_confirm_password')),
      'Aa1!zzzz',
    );

    await tester.tap(find.text('변경'));
    await tester.pump();

    expect(passwordInput, isNotNull);
    expect(passwordInput!.currentPassword, 'TempPass1!');
    expect(passwordInput!.password, 'Aa1!zzzz');

    await tester.pumpAndSettle();
    expect(find.text('비밀번호 변경 완료'), findsOneWidget);

    await tester.tap(find.text('확인'));
    await tester.pumpAndSettle();

    expect(authService.session, isNull);
    expect(find.text('로그인 페이지'), findsOneWidget);
  });
}

Future<void> _pumpAppShell(WidgetTester tester) async {
  final themeController = ThemeController();
  final permissionManager = PermissionManager();
  final router = GoRouter(
    initialLocation: dashboardRoutePath,
    routes: [
      GoRoute(
        path: loginRoutePath,
        builder: (context, state) => const _LoginPlaceholder(),
      ),
      ShellRoute(
        builder: (context, state, child) =>
            AppShell(currentLocation: state.uri.toString(), child: child),
        routes: [
          GoRoute(
            path: dashboardRoutePath,
            builder: (context, state) => const _DashboardPlaceholder(),
          ),
        ],
      ),
    ],
  );

  addTearDown(themeController.dispose);
  addTearDown(permissionManager.dispose);
  addTearDown(router.dispose);

  await tester.pumpWidget(
    PermissionScope(
      manager: permissionManager,
      child: ThemeControllerScope(
        controller: themeController,
        child: ShadApp.router(
          routerConfig: router,
          theme: SuperportShadTheme.light(),
          darkTheme: SuperportShadTheme.dark(),
          debugShowCheckedModeBanner: false,
        ),
      ),
    ),
  );
  await tester.pumpAndSettle();
}

AuthSession _buildSession() {
  return AuthSession(
    accessToken: 'access-token',
    refreshToken: 'refresh-token',
    expiresAt: DateTime.parse('2025-10-21T09:00:00Z'),
    user: const AuthenticatedUser(
      id: 7,
      name: '김승인',
      employeeNo: 'E2025001',
      email: 'approver@example.com',
      phone: '+82-10-2222-1111',
      primaryGroupId: 3,
      primaryGroupName: '물류팀',
    ),
    permissions: const [
      AuthPermission(resource: '/dashboard', actions: ['read']),
      AuthPermission(resource: '/approvals', actions: ['read', 'update']),
    ],
  );
}

AuthService _createAuthService(AuthSession session) {
  final repository = _FakeAuthRepository(session);
  final tokenStorage = _MemoryTokenStorage();
  return AuthService(repository: repository, tokenStorage: tokenStorage);
}

class _FakeAuthRepository implements AuthRepository {
  _FakeAuthRepository(this.session);

  final AuthSession session;

  @override
  Future<AuthSession> login(LoginRequest request) async => session;

  @override
  Future<AuthSession> refresh(String refreshToken) async => session;
}

class _MemoryTokenStorage implements TokenStorage {
  String? _access;
  String? _refresh;

  @override
  Future<void> clear() async {
    _access = null;
    _refresh = null;
  }

  @override
  Future<String?> readAccessToken() async => _access;

  @override
  Future<String?> readRefreshToken() async => _refresh;

  @override
  Future<void> writeAccessToken(String? token) async {
    _access = token;
  }

  @override
  Future<void> writeRefreshToken(String? token) async {
    _refresh = token;
  }
}

class _DashboardPlaceholder extends StatelessWidget {
  const _DashboardPlaceholder();

  @override
  Widget build(BuildContext context) {
    return const Scaffold(body: Center(child: Text('대시보드 본문')));
  }
}

class _LoginPlaceholder extends StatelessWidget {
  const _LoginPlaceholder();

  @override
  Widget build(BuildContext context) {
    return const Scaffold(body: Center(child: Text('로그인 페이지')));
  }
}

class _StubUserRepository implements UserRepository {
  _StubUserRepository({this.onUpdateMe});

  final Future<UserAccount> Function(UserProfileUpdateInput input)? onUpdateMe;

  @override
  Future<UserAccount> create(UserInput input) {
    throw UnimplementedError();
  }

  @override
  Future<void> delete(int id) {
    throw UnimplementedError();
  }

  @override
  Future<PaginatedResult<UserAccount>> list({
    int page = 1,
    int pageSize = 20,
    String? query,
    int? groupId,
    bool? isActive,
  }) {
    throw UnimplementedError();
  }

  @override
  Future<UserAccount> resetPassword(int id) {
    throw UnimplementedError();
  }

  @override
  Future<UserAccount> restore(int id) {
    throw UnimplementedError();
  }

  @override
  Future<UserAccount> update(int id, UserInput input) {
    throw UnimplementedError();
  }

  @override
  Future<UserAccount> updateMe(UserProfileUpdateInput input) {
    if (onUpdateMe != null) {
      return onUpdateMe!(input);
    }
    throw UnimplementedError();
  }
}
