import 'package:flutter/material.dart';
import 'package:flutter_test/flutter_test.dart';
import 'package:intl/intl.dart' as intl;
import 'package:shadcn_ui/shadcn_ui.dart';
import 'package:superport_v2/features/approvals/domain/entities/approval.dart';
import 'package:superport_v2/features/approvals/step/domain/entities/approval_step_input.dart';
import 'package:superport_v2/features/approvals/step/domain/entities/approval_step_record.dart';
import 'package:superport_v2/features/approvals/step/presentation/dialogs/approval_step_detail_dialog.dart';
import 'package:superport_v2/widgets/components/superport_detail_dialog.dart';

import '../../../../../helpers/test_app.dart';

void main() {
  TestWidgetsFlutterBinding.ensureInitialized();

  final dateFormat = intl.DateFormat('yyyy-MM-dd HH:mm');

  late ApprovalStepRecord sampleRecord;
  late ApprovalApprover approver;

  setUp(() {
    final statusPending = ApprovalStatus(
      id: 1,
      name: '대기',
      color: '#0EA5E9',
      isTerminal: false,
    );
    approver = ApprovalApprover(id: 800, employeeNo: 'E800', name: '김승인');

    final step = ApprovalStep(
      id: 900,
      stepOrder: 1,
      approver: approver,
      status: statusPending,
      assignedAt: DateTime(2024, 1, 10, 9),
    );

    sampleRecord = ApprovalStepRecord(
      approvalId: 400,
      approvalNo: 'APP-2024-0400',
      transactionNo: 'TRX-400',
      templateName: '일반 결재선',
      step: step,
    );
  });

  testWidgets('결재 단계 상세 다이얼로그는 요약과 메타 정보를 노출한다', (tester) async {
    await tester.pumpWidget(buildTestApp(const SizedBox.shrink()));
    final context = tester.element(find.byType(SizedBox));

    final resultFuture = showApprovalStepDetailDialog(
      context: context,
      record: sampleRecord,
      dateFormat: dateFormat,
      onUpdate: (_, __) => Future.value(sampleRecord),
      onDelete: (_) => Future.value(true),
      onRestore: (_) => Future.value(sampleRecord),
    );

    await tester.pump();
    await tester.pump(const Duration(milliseconds: 100));

    expect(find.text('결재 단계 상세'), findsAtLeastNWidgets(1));
    expect(find.text('결재 단계 1'), findsAtLeastNWidgets(1));
    expect(find.textContaining(approver.name), findsAtLeastNWidgets(1));
    expect(find.text('단계 순서'), findsWidgets);
    expect(find.text('상태'), findsWidgets);
    expect(find.text('승인자 사번'), findsWidgets);

    await tester.tap(find.byTooltip('닫기'), warnIfMissed: false);
    await tester.pumpAndSettle();
    expect(await resultFuture, isNull);
  });

  testWidgets('수정 탭에서 저장을 누르면 onUpdate 콜백이 입력값과 함께 호출된다', (tester) async {
    ApprovalStepInput? capturedInput;

    await tester.pumpWidget(buildTestApp(const SizedBox.shrink()));
    final context = tester.element(find.byType(SizedBox));

    final resultFuture = showApprovalStepDetailDialog(
      context: context,
      record: sampleRecord,
      dateFormat: dateFormat,
      onUpdate: (_, input) async {
        capturedInput = input;
        return sampleRecord.copyWith(
          step: sampleRecord.step.copyWith(
            stepOrder: input.stepOrder,
            approver: ApprovalApprover(
              id: input.approverId,
              employeeNo: 'E${input.approverId}',
              name: '변경 승인자',
            ),
            note: input.note,
          ),
        );
      },
      onDelete: (_) => Future.value(false),
      onRestore: (_) => Future.value(sampleRecord),
    );

    await tester.pump();
    await tester.pump(const Duration(milliseconds: 100));

    final tabsFinder = find.descendant(
      of: find.byType(SuperportDetailDialog),
      matching: find.byType(ShadTabs<String>),
    );
    final tabsState = tester.state(tabsFinder);
    final controller =
        (tabsState as dynamic).controller as ShadTabsController<String>;
    controller.select('edit');
    await tester.pump(const Duration(milliseconds: 100));

    await tester.enterText(
      find.byKey(const ValueKey('approval_step_detail_step_order')),
      '3',
    );
    await tester.enterText(
      find.byKey(const ValueKey('approval_step_detail_approver_id')),
      '901',
    );
    await tester.enterText(
      find.byKey(const ValueKey('approval_step_detail_note')),
      '조정된 결재 단계',
    );

    final submitButtonFinder = find.byKey(
      const ValueKey('approval_step_detail_submit'),
    );
    final submitButton = tester.widget<ShadButton>(submitButtonFinder);
    expect(submitButton.onPressed, isNotNull);
    submitButton.onPressed!();
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 100));

    final result = await resultFuture;
    expect(result, isNotNull);
    expect(result!.action, ApprovalStepDetailAction.updated);
    expect(capturedInput, isNotNull);
    expect(capturedInput!.stepOrder, 3);
    expect(capturedInput!.approverId, 901);
    expect(capturedInput!.note, '조정된 결재 단계');
  });

  testWidgets('삭제 탭에서 삭제 버튼을 누르면 onDelete 콜백 성공 시 결과가 반환된다', (tester) async {
    var deleteCalled = false;

    await tester.pumpWidget(buildTestApp(const SizedBox.shrink()));
    final context = tester.element(find.byType(SizedBox));

    final resultFuture = showApprovalStepDetailDialog(
      context: context,
      record: sampleRecord,
      dateFormat: dateFormat,
      onUpdate: (_, __) => Future.value(sampleRecord),
      onDelete: (_) async {
        deleteCalled = true;
        return true;
      },
      onRestore: (_) => Future.value(sampleRecord),
    );

    await tester.pump();
    await tester.pumpAndSettle();

    final tabsFinder = find.descendant(
      of: find.byType(SuperportDetailDialog),
      matching: find.byType(ShadTabs<String>),
    );
    final tabsState = tester.state(tabsFinder);
    final controller =
        (tabsState as dynamic).controller as ShadTabsController<String>;
    controller.select('delete');
    await tester.pump(const Duration(milliseconds: 100));

    final deleteButtonFinder = find.byWidgetPredicate(
      (widget) =>
          widget is ShadButton &&
          widget.variant == ShadButtonVariant.destructive &&
          widget.child is Text &&
          (widget.child as Text).data == '삭제',
    );
    expect(deleteButtonFinder, findsOneWidget);
    final deleteButton = tester.widget<ShadButton>(deleteButtonFinder);
    expect(deleteButton.onPressed, isNotNull);
    deleteButton.onPressed!();
    await tester.pump();
    await tester.pump(const Duration(milliseconds: 100));

    final result = await resultFuture;
    expect(deleteCalled, isTrue);
    expect(result, isNotNull);
    expect(result!.action, ApprovalStepDetailAction.deleted);
  });
}
