import 'dart:async';

import 'package:flutter/material.dart';
import 'package:intl/intl.dart' as intl;
import 'package:lucide_icons_flutter/lucide_icons.dart' as lucide;
import 'package:shadcn_ui/shadcn_ui.dart';

import '../../../../../widgets/components/feedback.dart';
import '../../../../../widgets/components/superport_detail_dialog.dart';
import '../../../../../widgets/components/superport_dialog.dart';
import '../../../../../widgets/components/superport_table.dart';
import '../../../../auth/domain/entities/authenticated_user.dart';
import '../../../domain/entities/approval.dart';
import '../../domain/entities/approval_history_record.dart';
import '../controllers/approval_history_controller.dart';
import '../widgets/approval_audit_log_table.dart';
import '../widgets/approval_flow_timeline.dart';
import '../../../shared/widgets/approver_autocomplete_field.dart';
import '../../../shared/widgets/approval_ui_helpers.dart';
import '../../../domain/entities/approval_flow.dart';

/// 결재 이력 상세 다이얼로그를 표시한다.
Future<void> showApprovalHistoryDetailDialog({
  required BuildContext context,
  required ApprovalHistoryController controller,
  required ApprovalHistoryRecord record,
  required intl.DateFormat dateFormat,
  required AuthenticatedUser? currentUser,
}) {
  return showSuperportDialog<void>(
    context: context,
    title: '결재 이력 상세',
    description: '결재번호 ${record.approvalNo}',
    body: _ApprovalHistoryDetailDialogBody(
      controller: controller,
      record: record,
      dateFormat: dateFormat,
      currentUser: currentUser,
    ),
    constraints: const BoxConstraints(maxWidth: 920),
    barrierDismissible: true,
    scrollable: true,
  );
}

class _ApprovalHistoryDetailDialogBody extends StatefulWidget {
  const _ApprovalHistoryDetailDialogBody({
    required this.controller,
    required this.record,
    required this.dateFormat,
    required this.currentUser,
  });

  final ApprovalHistoryController controller;
  final ApprovalHistoryRecord record;
  final intl.DateFormat dateFormat;
  final AuthenticatedUser? currentUser;

  @override
  State<_ApprovalHistoryDetailDialogBody> createState() =>
      _ApprovalHistoryDetailDialogBodyState();
}

class _ApprovalHistoryDetailDialogBodyState
    extends State<_ApprovalHistoryDetailDialogBody> {
  late ApprovalHistoryRecord _record;
  final TextEditingController _auditActorIdController = TextEditingController();
  final intl.DateFormat _dateTimeFormat = intl.DateFormat('yyyy-MM-dd HH:mm');
  static const _auditActionAll = '__all__';

  ApprovalHistoryController get _controller => widget.controller;

  @override
  void initState() {
    super.initState();
    _record = widget.record;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      _initialize();
    });
  }

  @override
  void didUpdateWidget(covariant _ApprovalHistoryDetailDialogBody oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (oldWidget.record.id != widget.record.id) {
      _record = widget.record;
      _initialize();
    }
  }

  Future<void> _initialize() async {
    try {
      _controller.updateActiveTab(ApprovalHistoryTab.flow);
      await _controller.loadApprovalFlow(_record.approvalId, force: true);
      if (!_controller.isSelectionForbidden) {
        await _controller.fetchAuditLogs(approvalId: _record.approvalId);
      }
    } catch (_) {
      // 오류 메시지는 컨트롤러 리스너에서 처리된다.
    }
  }

  @override
  void dispose() {
    _auditActorIdController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    return AnimatedBuilder(
      animation: _controller,
      builder: (context, _) {
        final flow = _controller.selectedFlow;
        final auditResult = _controller.auditResult;
        final auditLogs = auditResult?.items ?? const <ApprovalHistory>[];
        final pagination = auditResult == null
            ? null
            : SuperportTablePagination(
                currentPage: auditResult.page,
                totalPages: auditResult.pageSize == 0
                    ? 1
                    : (auditResult.total / auditResult.pageSize).ceil().clamp(
                        1,
                        9999,
                      ),
                totalItems: auditResult.total,
                pageSize: auditResult.pageSize,
              );
        final metadata = _buildMetadata();
        final badges = _buildBadges(flow);

        final sections = <SuperportDetailDialogSection>[
          SuperportDetailDialogSection(
            id: 'timeline',
            label: '상태 타임라인',
            icon: lucide.LucideIcons.listTree,
            builder: (_) => _buildTimelineSection(flow),
          ),
          SuperportDetailDialogSection(
            id: 'audit',
            label: '감사 로그',
            icon: lucide.LucideIcons.listChecks,
            builder: (_) =>
                _buildAuditSection(logs: auditLogs, pagination: pagination),
          ),
        ];

        return SuperportDetailDialog(
          sections: sections,
          summary: _buildSummary(flow),
          summaryBadges: badges,
          metadata: metadata,
          initialSectionId: 'timeline',
        );
      },
    );
  }

  Widget _buildSummary(ApprovalFlow? flow) {
    final theme = ShadTheme.of(context);
    final requester = flow?.requester;
    final currentStep = flow?.statusSummary.currentStepOrder;

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        ApprovalStatusBadge(
          label: _record.toStatus.name,
          colorHex: _record.toStatus.color,
        ),
        const SizedBox(height: 12),
        Text('결재번호 ${_record.approvalNo}', style: theme.textTheme.small),
        const SizedBox(height: 4),
        Text(
          _record.stepOrder == null
              ? '단계 정보 없음 · ${_record.approver.name}'
              : '${_record.stepOrder}단계 · ${_record.approver.name}',
          style: theme.textTheme.small,
        ),
        const SizedBox(height: 4),
        Text(_statusLabel(_record), style: theme.textTheme.muted),
        if (requester != null) ...[
          const SizedBox(height: 8),
          Text(
            '상신자 ${requester.name} (${requester.employeeNo})',
            style: theme.textTheme.small,
          ),
        ],
        if (flow != null && currentStep != null) ...[
          const SizedBox(height: 4),
          Text(
            '현재 진행 단계: $currentStep / ${flow.statusSummary.totalSteps}',
            style: theme.textTheme.small,
          ),
        ],
        const SizedBox(height: 16),
        _buildActionButtons(flow),
      ],
    );
  }

  List<Widget> _buildBadges(ApprovalFlow? flow) {
    final badges = <Widget>[
      ShadBadge.outline(child: Text(_record.action.name)),
      ShadBadge(child: Text(_record.toStatus.name)),
    ];
    final isForbidden = _controller.isSelectionForbidden;
    if (isForbidden) {
      badges.add(const ShadBadge.destructive(child: Text('열람 제한')));
    } else if (flow?.approval.updatedAt != null) {
      badges.add(
        ShadBadge.outline(
          child: Text(
            '변경 ${_dateTimeFormat.format(flow!.approval.updatedAt!.toLocal())}',
          ),
        ),
      );
    }
    return badges;
  }

  List<SuperportDetailMetadata> _buildMetadata() {
    return [
      SuperportDetailMetadata.text(
        label: '결재 ID',
        value: '${_record.approvalId}',
      ),
      SuperportDetailMetadata.text(
        label: '승인자 사번',
        value: _record.approver.employeeNo,
      ),
      SuperportDetailMetadata.text(
        label: '행위 시간',
        value: _dateTimeFormat.format(_record.actionAt.toLocal()),
      ),
      SuperportDetailMetadata(
        label: '메모',
        value: ApprovalNoteTooltip(note: _record.note),
      ),
    ];
  }

  Widget _buildTimelineSection(ApprovalFlow? flow) {
    final theme = ShadTheme.of(context);
    if (_controller.isLoadingFlow) {
      return const Center(child: CircularProgressIndicator());
    }
    if (_controller.isSelectionForbidden) {
      return _buildForbiddenNotice(theme);
    }
    if (flow == null) {
      return _buildPlaceholder(theme, '결재 정보를 불러오는 중입니다.');
    }
    return ApprovalFlowTimeline(flow: flow, dateFormat: _dateTimeFormat);
  }

  Widget _buildAuditSection({
    required List<ApprovalHistory> logs,
    required SuperportTablePagination? pagination,
  }) {
    final theme = ShadTheme.of(context);
    if (_controller.isSelectionForbidden) {
      return _buildForbiddenNotice(theme);
    }
    if (_controller.isLoadingAudit) {
      return const Center(child: CircularProgressIndicator());
    }
    return Column(
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        _buildAuditFilters(theme),
        const SizedBox(height: 16),
        ApprovalAuditLogTable(
          logs: logs,
          dateFormat: _dateTimeFormat,
          pagination: pagination,
          onPageChange: (page) {
            _controller.fetchAuditLogs(
              approvalId: _record.approvalId,
              page: page,
            );
          },
          onPageSizeChange: (value) {
            _controller.updateAuditPageSize(value);
            _controller.fetchAuditLogs(approvalId: _record.approvalId, page: 1);
          },
          isLoading: _controller.isLoadingAudit,
        ),
      ],
    );
  }

  Widget _buildAuditFilters(ShadThemeData theme) {
    final actorId = _controller.auditActorId;
    final actorText = actorId?.toString() ?? '';
    if (_auditActorIdController.text.trim() != actorText) {
      _auditActorIdController.value = TextEditingValue(text: actorText);
    }
    final actionOptions = _controller.auditActions;
    final currentAction = _controller.auditActionCode ?? _auditActionAll;
    final isLoading = _controller.isLoadingAudit;

    return Wrap(
      spacing: 12,
      runSpacing: 12,
      children: [
        SizedBox(
          width: 240,
          child: ApprovalApproverAutocompleteField(
            key: ValueKey(actorId ?? 'all'),
            idController: _auditActorIdController,
            hintText: '행위자 검색',
            onSelected: (candidate) {
              final selected =
                  candidate?.id ??
                  int.tryParse(_auditActorIdController.text.trim());
              _controller.updateAuditActor(selected);
              _controller.fetchAuditLogs(
                approvalId: _record.approvalId,
                page: 1,
              );
            },
          ),
        ),
        SizedBox(
          width: 200,
          child: ShadSelect<String>(
            key: ValueKey(currentAction),
            initialValue: currentAction,
            selectedOptionBuilder: (context, value) =>
                Text(_auditActionLabel(value, actionOptions)),
            onChanged: isLoading
                ? null
                : (value) {
                    if (value == null || value == _auditActionAll) {
                      _controller.updateAuditAction(null);
                    } else {
                      _controller.updateAuditAction(value);
                    }
                    _controller.fetchAuditLogs(
                      approvalId: _record.approvalId,
                      page: 1,
                    );
                  },
            options: [
              const ShadOption(value: _auditActionAll, child: Text('전체 행위')),
              ...actionOptions
                  .where(
                    (action) => action.code != null && action.code!.isNotEmpty,
                  )
                  .map(
                    (action) => ShadOption(
                      value: action.code!,
                      child: Text(action.name),
                    ),
                  ),
            ],
          ),
        ),
        if (_controller.hasActiveAuditFilters)
          ShadButton.ghost(
            onPressed: isLoading ? null : _clearAuditFilters,
            child: const Text('필터 초기화'),
          ),
      ],
    );
  }

  Widget _buildActionButtons(ApprovalFlow? flow) {
    final theme = ShadTheme.of(context);
    final canRecall = flow != null && _canRecall(flow);
    final canResubmit = flow != null && _canResubmit(flow);
    final recallReason = flow == null
        ? '결재 정보를 불러오는 중입니다.'
        : _recallDisabledReason(flow);
    final resubmitReason = flow == null
        ? '결재 정보를 불러오는 중입니다.'
        : _resubmitDisabledReason(flow);

    final recallNotice = _buildRecallConditionNotice(
      theme: theme,
      flow: flow,
      canRecall: canRecall,
      reason: recallReason,
    );

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Wrap(
          spacing: 12,
          runSpacing: 12,
          children: [
            ShadButton(
              onPressed:
                  flow == null || !canRecall || _controller.isPerformingAction
                  ? null
                  : () => _handleRecall(flow),
              child: const Text('회수'),
            ),
            ShadButton.outline(
              onPressed:
                  flow == null || !canResubmit || _controller.isPerformingAction
                  ? null
                  : () => _handleResubmit(flow),
              child: const Text('재상신'),
            ),
          ],
        ),
        if (_controller.isPerformingAction) ...[
          const SizedBox(height: 8),
          Text(
            '결재 작업을 처리하는 중입니다...',
            style: theme.textTheme.small.copyWith(
              color: theme.colorScheme.mutedForeground,
            ),
          ),
        ] else ...[
          if (recallNotice != null) ...[
            const SizedBox(height: 8),
            recallNotice,
          ],
          if (!canResubmit && resubmitReason != null) ...[
            SizedBox(height: recallNotice == null ? 8 : 4),
            Text(
              '재상신 불가: $resubmitReason',
              style: theme.textTheme.small.copyWith(
                color: theme.colorScheme.mutedForeground,
              ),
            ),
          ],
        ],
      ],
    );
  }

  Widget? _buildRecallConditionNotice({
    required ShadThemeData theme,
    required ApprovalFlow? flow,
    required bool canRecall,
    required String? reason,
  }) {
    if (flow == null) {
      return Row(
        children: [
          Icon(
            lucide.LucideIcons.info,
            size: 16,
            color: theme.colorScheme.mutedForeground,
          ),
          const SizedBox(width: 8),
          Expanded(
            child: Text(
              '회수 조건을 확인하는 중입니다.',
              style: theme.textTheme.small.copyWith(
                color: theme.colorScheme.mutedForeground,
              ),
            ),
          ),
        ],
      );
    }
    final icon = canRecall
        ? lucide.LucideIcons.badgeCheck
        : lucide.LucideIcons.shieldAlert;
    final color = canRecall
        ? theme.colorScheme.primary
        : theme.colorScheme.destructive;
    final message = canRecall
        ? '첫 승인자가 아직 결정을 내리지 않아 회수할 수 있습니다.'
        : (reason ?? '회수 조건을 확인할 수 없습니다.');
    return Row(
      children: [
        Icon(icon, size: 16, color: color),
        const SizedBox(width: 8),
        Expanded(
          child: Text(
            message,
            style: theme.textTheme.small.copyWith(color: color),
          ),
        ),
      ],
    );
  }

  Widget _buildForbiddenNotice(ShadThemeData theme) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 20),
      decoration: BoxDecoration(
        color: theme.colorScheme.secondary.withValues(alpha: 0.08),
        borderRadius: BorderRadius.circular(12),
        border: Border.all(color: theme.colorScheme.border),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(
            '열람 권한이 없습니다',
            style: theme.textTheme.p.copyWith(
              fontWeight: FontWeight.w600,
              color: theme.colorScheme.destructive,
            ),
          ),
          const SizedBox(height: 8),
          Text(
            '상신자 또는 기결재자만 감사 로그와 상세 내역을 확인할 수 있습니다.',
            style: theme.textTheme.small,
          ),
          const SizedBox(height: 8),
          Text(
            '필요 시 담당자에게 접근 권한을 요청하거나 다른 결재를 선택하세요.',
            style: theme.textTheme.small.copyWith(
              color: theme.colorScheme.mutedForeground,
            ),
          ),
        ],
      ),
    );
  }

  Widget _buildPlaceholder(ShadThemeData theme, String message) {
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 16, vertical: 24),
      decoration: BoxDecoration(
        color: theme.colorScheme.secondary.withValues(alpha: 0.05),
        borderRadius: BorderRadius.circular(12),
        border: Border.all(color: theme.colorScheme.border),
      ),
      child: Text(message, style: theme.textTheme.muted),
    );
  }

  void _clearAuditFilters() {
    _auditActorIdController.clear();
    _controller.clearAuditFilters();
    _controller.fetchAuditLogs(approvalId: _record.approvalId, page: 1);
  }

  String _statusLabel(ApprovalHistoryRecord record) {
    final from = record.fromStatus?.name;
    if (from == null || from.isEmpty) {
      return record.toStatus.name;
    }
    return '$from → ${record.toStatus.name}';
  }

  String _auditActionLabel(String value, List<ApprovalAction> actions) {
    if (value == _auditActionAll) {
      return '전체 행위';
    }
    for (final action in actions) {
      if (action.code == value) {
        return action.name;
      }
    }
    return '전체 행위';
  }

  bool _canRecall(ApprovalFlow flow) {
    if (flow.status.isTerminal) {
      return false;
    }
    if (flow.steps.isEmpty) {
      return false;
    }
    final first = flow.steps.first;
    return first.decidedAt == null;
  }

  bool _canResubmit(ApprovalFlow flow) {
    if (!flow.status.isTerminal) {
      return false;
    }
    final statusName = flow.status.name.toLowerCase();
    return statusName.contains('반려') || statusName.contains('reject');
  }

  String? _recallDisabledReason(ApprovalFlow flow) {
    if (flow.status.isTerminal) {
      return '결재가 종료되었습니다.';
    }
    if (flow.steps.isEmpty) {
      return '결재 단계 정보가 없습니다.';
    }
    if (flow.steps.first.decidedAt != null) {
      return '첫 승인자가 이미 결정을 내려 회수할 수 없습니다.';
    }
    return null;
  }

  String? _resubmitDisabledReason(ApprovalFlow flow) {
    if (!flow.status.isTerminal) {
      return '결재가 아직 진행 중입니다.';
    }
    final statusName = flow.status.name.toLowerCase();
    if (!(statusName.contains('반려') || statusName.contains('reject'))) {
      return '반려 상태에서만 재상신할 수 있습니다.';
    }
    return null;
  }

  Future<void> _handleRecall(ApprovalFlow flow) async {
    final user = widget.currentUser;
    if (user == null) {
      SuperportToast.error(context, '현재 사용자 정보를 확인할 수 없습니다.');
      return;
    }
    final approvalId = flow.id;
    if (approvalId == null) {
      SuperportToast.error(context, '결재 식별자를 확인할 수 없습니다.');
      return;
    }
    final note = await _promptActionNote(
      title: '결재 회수',
      confirmLabel: '회수',
      description: '회수 사유를 입력하세요. 입력하지 않아도 회수를 진행할 수 있습니다.',
    );
    final refreshed = await _controller.refreshFlow(approvalId);
    if (!mounted) {
      return;
    }
    if (refreshed == null) {
      SuperportToast.error(context, '결재 상세를 새로고침하지 못했습니다. 다시 시도해 주세요.');
      return;
    }
    final latestFlow = refreshed;
    final sanitizedNote = note?.isEmpty == true ? null : note;
    final transactionUpdatedAt = latestFlow.transactionUpdatedAt;
    if (transactionUpdatedAt == null) {
      SuperportToast.error(
        context,
        '연동 전표 변경 시각을 확인할 수 없습니다. 화면을 새로고침한 뒤 다시 시도하세요.',
      );
      return;
    }
    final input = ApprovalRecallInput(
      approvalId: approvalId,
      actorId: user.id,
      note: sanitizedNote,
      expectedUpdatedAt: latestFlow.approval.updatedAt,
      transactionExpectedUpdatedAt: transactionUpdatedAt,
    );
    final result = await _controller.recallApproval(input);
    if (!mounted) {
      return;
    }
    if (result != null) {
      SuperportToast.success(
        context,
        '결재(${latestFlow.approvalNo}) 회수를 완료했습니다.',
      );
      await _controller.loadApprovalFlow(approvalId, force: true);
      await _controller.fetchAuditLogs(approvalId: approvalId);
    }
  }

  Future<void> _handleResubmit(ApprovalFlow flow) async {
    final user = widget.currentUser;
    if (user == null) {
      SuperportToast.error(context, '현재 사용자 정보를 확인할 수 없습니다.');
      return;
    }
    final approvalId = flow.id;
    if (approvalId == null) {
      SuperportToast.error(context, '결재 식별자를 확인할 수 없습니다.');
      return;
    }
    final note = await _promptActionNote(
      title: '결재 재상신',
      confirmLabel: '재상신',
      description: '재상신 시 전달할 메시지를 입력하세요. 입력하지 않아도 재상신됩니다.',
    );
    final refreshed = await _controller.refreshFlow(approvalId);
    if (!mounted) {
      return;
    }
    if (refreshed == null) {
      SuperportToast.error(context, '결재 상세를 새로고침하지 못했습니다. 다시 시도해 주세요.');
      return;
    }
    final latestFlow = refreshed;
    final sanitizedNote = note?.isEmpty == true ? null : note;
    final transactionUpdatedAt = latestFlow.transactionUpdatedAt;
    if (transactionUpdatedAt == null) {
      SuperportToast.error(
        context,
        '연동 전표 변경 시각을 확인할 수 없습니다. 화면을 새로고침한 뒤 다시 시도하세요.',
      );
      return;
    }
    final steps = latestFlow.steps
        .map(
          (step) => ApprovalStepAssignmentItem(
            stepOrder: step.stepOrder,
            approverId: step.approver.id,
            note: step.note,
          ),
        )
        .toList(growable: false);
    final submission = ApprovalSubmissionInput(
      transactionId: latestFlow.transactionId,
      statusId: latestFlow.status.id,
      requesterId: latestFlow.requester.id,
      finalApproverId: latestFlow.finalApprover?.id,
      note: latestFlow.note,
      steps: steps,
    );
    final input = ApprovalResubmissionInput(
      approvalId: approvalId,
      actorId: user.id,
      submission: submission,
      note: sanitizedNote,
      expectedUpdatedAt: latestFlow.approval.updatedAt,
      transactionExpectedUpdatedAt: transactionUpdatedAt,
    );
    final result = await _controller.resubmitApproval(input);
    if (!mounted) {
      return;
    }
    if (result != null) {
      SuperportToast.success(
        context,
        '결재(${latestFlow.approvalNo}) 재상신을 완료했습니다.',
      );
      await _controller.loadApprovalFlow(approvalId, force: true);
      await _controller.fetchAuditLogs(approvalId: approvalId);
    }
  }

  Future<String?> _promptActionNote({
    required String title,
    required String confirmLabel,
    required String description,
  }) async {
    final theme = ShadTheme.of(context);
    final controller = TextEditingController();
    String? result;
    await showSuperportDialog<void>(
      context: context,
      title: title,
      description: description,
      constraints: const BoxConstraints(maxWidth: 420),
      actions: [
        ShadButton.ghost(
          onPressed: () =>
              Navigator.of(context, rootNavigator: true).maybePop(),
          child: const Text('취소'),
        ),
        ShadButton(
          onPressed: () {
            result = controller.text.trim();
            Navigator.of(context, rootNavigator: true).maybePop();
          },
          child: Text(confirmLabel),
        ),
      ],
      body: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('사유는 선택 입력입니다. 비워두면 전달되지 않습니다.', style: theme.textTheme.muted),
          const SizedBox(height: 12),
          ShadTextarea(controller: controller, minHeight: 120, maxHeight: 200),
        ],
      ),
    );
    controller.dispose();
    return result;
  }
}
