import 'package:flutter/material.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import '../../shared/widgets/nav_bar_config.dart';
import '../../core/utils/date_utils.dart' as du;
import '../../shared/widgets/form_section.dart';
import '../../shared/widgets/form_field_row.dart';
import 'expense_model.dart';
import '../../core/i18n/app_localizations.dart';
import '../../shared/widgets/loading_dialog.dart';
import '../../shared/models/bill_attachment.dart';
import '../../core/theme/app_colors.dart';
import '../../core/theme/app_colors_extension.dart';
import 'expense_api.dart';
import '../../shared/widgets/approval_actions.dart';
import '../../shared/widgets/approval_timeline.dart';
import '../../shared/models/approval_status.dart';

class ExpenseDetailPage extends ConsumerStatefulWidget {
  final String billNo;
  final int queryId;
  const ExpenseDetailPage({super.key, required this.billNo, this.queryId = 0});

  @override
  ConsumerState<ExpenseDetailPage> createState() => _ExpenseDetailPageState();
}

class _ExpenseDetailPageState extends ConsumerState<ExpenseDetailPage>
    with WidgetsBindingObserver {
  ExpenseModel? _expense;
  List<BillAttachment> _attachments = [];
  bool _attachAvailable = false;
  List<ApprovalRecord> _timelineRecords = [];
  List<String> _timelineChain = [];
  String _timelineCurrentApproverId = '';
  bool _isLoading = true;
  String? _error;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addObserver(this);
    _loadData();
  }

  @override
  void dispose() {
    WidgetsBinding.instance.removeObserver(this);
    super.dispose();
  }

  @override
  void didChangeAppLifecycleState(AppLifecycleState state) {
    if (state == AppLifecycleState.resumed) {
      _attachments = [];
      _attachAvailable = false;
      _loadData();
    }
  }

  Future<void> _loadData() async {
    setState(() {
      _isLoading = true;
      _error = null;
    });
    try {
      final api = ref.read(expenseApiProvider);
      // 1. 加载报销详情（主表 + 明细）
      final expense = await api.fetchDetail(widget.billNo);
      setState(() => _expense = expense);

      // 2. 加载审批时间线（非致命——失败时回退到 expense 模型数据）
      try {
        final timelineData = await api.fetchApprovalTimeline('BX', widget.billNo);
        setState(() {
          _timelineRecords = (timelineData['records'] as List<dynamic>?)
                  ?.map((e) => ApprovalRecord.fromJson(e as Map<String, dynamic>))
                  .toList() ??
              [];
          _timelineChain = (timelineData['chain'] as List<dynamic>?)
                  ?.map((e) => e as String)
                  .toList() ??
              [];
          _timelineCurrentApproverId =
              (timelineData['currentApproverId'] as String?) ?? '';
        });
      } catch (_) {
        // 回退到 expense 自带的审批数据
        setState(() {
          _timelineRecords = expense.approvalRecords;
          _timelineChain = expense.approvalChain;
          _timelineCurrentApproverId = expense.currentApproverId;
        });
      }

      // 3. 加载附件（非致命）
      try {
        if (mounted) setState(() => _attachAvailable = false);
        _attachAvailable = await api.checkAttachHealth();
        if (_attachAvailable) {
          _attachments = await api.getAttachments('BX', widget.billNo);
        }
      } catch (_) {
        _attachAvailable = false;
        _attachments = [];
      }
    } catch (e) {
      setState(() => _error = e.toString());
    } finally {
      setState(() => _isLoading = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    final l10n = AppLocalizations.of(context);

    setNavBarTitle(context, ref, NavBarConfig(
      title: l10n.get('expenseDetail'),
      showBack: true,
      onBack: () => context.pop(),
    ));

    if (_isLoading) {
      return const Center(
        child: TDLoading(
          size: TDLoadingSize.large,
          icon: TDLoadingIcon.activity,
        ),
      );
    }

    if (_error != null) {
      return Center(
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            Icon(Icons.error_outline, size: 48, color: colors.danger),
            const SizedBox(height: 12),
            Text(
              _error!,
              style: TextStyle(fontSize: AppFontSizes.body, color: colors.danger),
              textAlign: TextAlign.center,
            ),
            const SizedBox(height: 16),
            TDButton(
              text: l10n.get('retry'),
              theme: TDButtonTheme.primary,
              onTap: _loadData,
            ),
          ],
        ),
      );
    }

    final expense = _expense!;

    return Column(
      children: [
        Expanded(
          child: SingleChildScrollView(
            physics: const AlwaysScrollableScrollPhysics(),
            padding: const EdgeInsets.all(16),
            child: Column(
              children: [
                _buildBasicInfoSection(expense, l10n, colors),
                const SizedBox(height: 16),
                _buildExpenseDetailSection(expense, l10n, colors),
                const SizedBox(height: 16),
                _buildAttachmentSection(l10n, colors),
                const SizedBox(height: 16),
                _buildApprovalSection(l10n, colors),
              ],
            ),
          ),
        ),
        ApprovalActions(
          queryId: widget.queryId,
          onApprove: () => _handleApprove(),
          onReject: () => _handleReject(),
          onReverseAudit: () => _handleReverseAudit(),
        ),
      ],
    );
  }

  // ── 审核操作 handler ──

  void _handleApprove() async {
    final l10n = AppLocalizations.of(context);
    final rem = await _showOpinionDialog(
      title: l10n.get('confirmApprove'),
      hint: l10n.get('approvalComment'),
    );
    if (rem == null || !mounted) return;
    await _doAudit('approve', rem: rem);
  }

  void _handleReject() async {
    final l10n = AppLocalizations.of(context);
    final rem = await _showOpinionDialog(
      title: l10n.get('confirmReject'),
      hint: l10n.get('rejectReason'),
    );
    if (rem == null || !mounted) return;
    await _doAudit('reject', rem: rem);
  }

  void _handleReverseAudit() async {
    final l10n = AppLocalizations.of(context);
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (ctx) => TDAlertDialog(
        title: l10n.get('withdrawConfirm'),
        content: l10n.get('withdrawConfirmTip'),
        leftBtn: TDDialogButtonOptions(title: l10n.get('cancel'), action: () => Navigator.pop(ctx, false)),
        rightBtn: TDDialogButtonOptions(title: l10n.get('confirm'), action: () => Navigator.pop(ctx, true)),
      ),
    );
    if (confirmed != true || !mounted) return;
    final rem = await _showOpinionDialog(
      title: l10n.get('withdrawConfirm'),
      hint: l10n.get('approvalComment'),
    );
    if (rem == null || !mounted) return;
    await _doAudit('reverseAudit', rem: rem);
  }

  /// 弹出审批意见输入框，返回 null 表示取消
  Future<String?> _showOpinionDialog({
    required String title,
    required String hint,
  }) async {
    final ctrl = TextEditingController();
    return showDialog<String>(
      context: context,
      builder: (ctx) => TDAlertDialog(
        title: title,
        content: hint,
        leftBtn: TDDialogButtonOptions(
          title: AppLocalizations.of(context).get('cancel'),
          action: () => Navigator.pop(ctx),
        ),
        rightBtn: TDDialogButtonOptions(
          title: AppLocalizations.of(context).get('confirm'),
          action: () => Navigator.pop(ctx, ctrl.text),
        ),
      ),
    );
  }

  Future<void> _doAudit(String action, {String rem = ''}) async {
    try {
      LoadingDialog.show(context);
      final api = ref.read(expenseApiProvider);
      await api.executeApproval(bilId: 'BX', bilNo: widget.billNo, action: action, rem: rem);
      if (mounted) {
        LoadingDialog.hide(context);
        TDToast.showSuccess(AppLocalizations.of(context).get('submitSuccess'), context: context);
        if (mounted) context.pop();
      }
    } catch (e) {
      if (mounted) {
        LoadingDialog.hide(context);
        TDToast.showFail(e.toString(), context: context);
      }
    }
  }

  // ═══ 基本信息 ═══
  Widget _buildBasicInfoSection(
      ExpenseModel expense, AppLocalizations l10n, AppColorsExtension colors) {
    return FormSection(
      title: l10n.get('basicInfo'),
      leadingIcon: Icons.info_outline,
      children: [
        FormFieldRow(
            label: l10n.get('expenseNo'),
            value: expense.expenseNo,
            readOnly: true,
            showArrow: false),
        const SizedBox(height: 16),
        FormFieldRow(
            label: l10n.get('voucherNo'),
            value: expense.voucherNo.isNotEmpty ? expense.voucherNo : '-',
            readOnly: true,
            showArrow: false),
        const SizedBox(height: 16),
        FormFieldRow(
            label: l10n.get('expensePersonnel'),
            value: expense.applicantId.isNotEmpty
                ? '${expense.applicantId}/${expense.applicantName}'
                : expense.applicantName,
            readOnly: true,
            showArrow: false),
        const SizedBox(height: 16),
        FormFieldRow(
            label: l10n.get('expenseDept'),
            value: expense.deptId.isNotEmpty
                ? '${expense.deptId}/${expense.deptName}'
                : expense.deptName,
            readOnly: true,
            showArrow: false),
        const SizedBox(height: 16),
        FormFieldRow(
            label: l10n.get('date'),
            value: du.DateUtils.formatDateTime(expense.createTime),
            readOnly: true,
            showArrow: false),
        const SizedBox(height: 16),
        FormFieldRow(
            label: l10n.get('currency'),
            value: expense.currencyCode.isNotEmpty ? expense.currencyCode : '-',
            readOnly: true,
            showArrow: false),
        const SizedBox(height: 16),
        SizedBox(
          height: 24,
          child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
            Text(l10n.get('feeReason'),
                style: TextStyle(fontSize: AppFontSizes.subtitle, color: colors.textSecondary)),
            const SizedBox(width: 8),
            Expanded(
              child: Text(expense.purpose.isNotEmpty ? expense.purpose : '-',
                  textAlign: TextAlign.end,
                  maxLines: 2,
                  overflow: TextOverflow.ellipsis,
                  style: TextStyle(fontSize: AppFontSizes.subtitle, fontWeight: FontWeight.w500, color: colors.textPrimary)),
            ),
          ]),
        ),
        const SizedBox(height: 16),
        FormFieldRow(
            label: l10n.get('paymentMethod'),
            value: expense.paymentMethod.isNotEmpty ? expense.paymentMethod : '-',
            readOnly: true,
            showArrow: false),
        const SizedBox(height: 16),
        SizedBox(
          height: 24,
          child: Row(crossAxisAlignment: CrossAxisAlignment.center, children: [
            Text(l10n.get('remark'),
                style: TextStyle(fontSize: AppFontSizes.subtitle, color: colors.textSecondary)),
            const SizedBox(width: 8),
            Expanded(
              child: Text(expense.remark.isNotEmpty ? expense.remark : '-',
                  textAlign: TextAlign.end,
                  maxLines: 2,
                  overflow: TextOverflow.ellipsis,
                  style: TextStyle(fontSize: AppFontSizes.subtitle, fontWeight: FontWeight.w500, color: colors.textPrimary)),
            ),
          ]),
        ),
      ],
    );
  }

  // ═══ 费用明细 ═══
  Widget _buildExpenseDetailSection(
      ExpenseModel expense, AppLocalizations l10n, AppColorsExtension colors) {
    final totalAmount = expense.details.fold<double>(
      0,
      (sum, d) => sum + d.totalAmount,
    );
    final totalApproved = expense.details.fold<double>(
      0,
      (sum, d) => sum + d.approvedAmount,
    );
    return FormSection(
      title: l10n.get('expenseDetails'),
      leadingIcon: Icons.receipt_long_outlined,
      children: [
        if (expense.details.isEmpty)
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 8),
            child: Text(l10n.get('noDetailData'),
                style: TextStyle(fontSize: AppFontSizes.body, color: colors.textPlaceholder)),
          )
        else
          ...expense.details.asMap().entries.map((e) {
            final d = e.value;
            final title = d.categoryName.isNotEmpty
                ? '${d.expenseCategory}/${d.categoryName}'
                : (d.remark.isNotEmpty ? d.remark : (d.acctSubjectId.isNotEmpty ? d.acctSubjectId : '--'));
            return Container(
              margin: const EdgeInsets.symmetric(vertical: 6),
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(color: colors.bgPage, borderRadius: BorderRadius.circular(8)),
              child: Row(
                children: [
                  Expanded(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Row(
                          children: [
                            Expanded(
                              child: Text(title,
                                  style: TextStyle(fontSize: AppFontSizes.body, fontWeight: FontWeight.w500, color: colors.textPrimary)),
                            ),
                            Column(
                              crossAxisAlignment: CrossAxisAlignment.end,
                              children: [
                                Text('¥${d.totalAmount.toStringAsFixed(2)}',
                                    style: TextStyle(fontSize: AppFontSizes.body, fontWeight: FontWeight.w600, color: colors.amountPrimary)),
                                if (d.approvedAmount > 0)
                                  Text('¥${d.approvedAmount.toStringAsFixed(2)}',
                                      style: TextStyle(fontSize: AppFontSizes.body, fontWeight: FontWeight.w600, color: colors.success)),
                              ],
                            ),
                          ],
                        ),
                        const SizedBox(height: 2),
                        Text('${l10n.get('amountExcludingTax')}: ¥${d.amount.toStringAsFixed(2)}',
                            style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary)),
                        if (d.taxAmount > 0)
                          Text('${l10n.get('taxAmount')}: ¥${d.taxAmount.toStringAsFixed(2)}',
                              style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary)),
                        if (d.approvedAmount > 0)
                          Text('${l10n.get('approvedAmount')}: ¥${d.approvedAmount.toStringAsFixed(2)}',
                              style: TextStyle(fontSize: AppFontSizes.caption, fontWeight: FontWeight.w500, color: colors.success)),
                        if (d.acctSubjectName.isNotEmpty)
                          Text('${l10n.get('acctSubject')}: ${d.acctSubjectId}/${d.acctSubjectName}',
                              maxLines: 1, overflow: TextOverflow.ellipsis,
                              style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary)),
                        if (d.aeNo.isNotEmpty)
                          Text('${l10n.get('expenseApplyNo')}: ${d.aeNo}',
                              maxLines: 1, overflow: TextOverflow.ellipsis,
                              style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary)),
                        if (d.aeDd.isNotEmpty)
                          Text('${l10n.get('applyDate')}: ${d.aeDd}',
                              style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary)),
                        if (d.projectName.isNotEmpty)
                          Text('${l10n.get('project')}: ${d.projectId}/${d.projectName}',
                              maxLines: 1, overflow: TextOverflow.ellipsis,
                              style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary)),
                        if (d.costDeptName.isNotEmpty)
                          Text('${l10n.get('dept')}: ${d.costDeptId}/${d.costDeptName}',
                              maxLines: 1, overflow: TextOverflow.ellipsis,
                              style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary)),
                        if (d.customerVendorName.isNotEmpty)
                          Text('${l10n.get('customerVendor')}: ${d.customerVendorName}',
                              maxLines: 1, overflow: TextOverflow.ellipsis,
                              style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary)),
                        if (d.remark.isNotEmpty)
                          Text(d.remark,
                              maxLines: 2, overflow: TextOverflow.ellipsis,
                              style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary)),
                      ],
                    ),
                  ),
                ],
              ),
            );
          }),
        if (expense.details.isNotEmpty) ...[
          const SizedBox(height: 8),
          Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
            Text(l10n.get('total'),
                style: TextStyle(fontSize: AppFontSizes.body, fontWeight: FontWeight.w600, color: colors.textPrimary)),
            Column(
              crossAxisAlignment: CrossAxisAlignment.end,
              children: [
                Text('¥${totalAmount.toStringAsFixed(2)}',
                    style: TextStyle(fontSize: AppFontSizes.subtitle, fontWeight: FontWeight.w700, color: colors.amountPrimary)),
                if (totalApproved > 0)
                  Text('${l10n.get('approvedAmount')} ¥${totalApproved.toStringAsFixed(2)}',
                      style: TextStyle(fontSize: AppFontSizes.caption, fontWeight: FontWeight.w600, color: colors.success)),
              ],
            ),
          ]),
        ],
      ],
    );
  }

  // ═══ 附件 ═══
  Widget _buildAttachmentSection(AppLocalizations l10n, AppColorsExtension colors) {
    if (!_attachAvailable) {
      return FormSection(
        title: l10n.get('attachments'),
        leadingIcon: Icons.attach_file_outlined,
        children: [Text(l10n.get('attachServiceUnavailable'),
            style: TextStyle(fontSize: AppFontSizes.body, color: colors.textPlaceholder))],
      );
    }

    final headerAtts = _attachments.where((a) => a.isHeader).toList();
    final bodyGroups = <int, List<BillAttachment>>{};
    for (final a in _attachments.where((a) => a.isBody)) {
      bodyGroups.putIfAbsent(a.srcItm, () => []).add(a);
    }

    final children = <Widget>[];
    if (_attachments.isEmpty) {
      children.add(Text(l10n.get('noAttachment'),
          style: TextStyle(fontSize: AppFontSizes.body, color: colors.textPlaceholder)));
    } else {
      // 表头附件
      if (headerAtts.isNotEmpty) {
        children.add(Padding(
          padding: const EdgeInsets.only(bottom: 8),
          child: Text(l10n.get('headerAttachments'),
              style: TextStyle(fontSize: AppFontSizes.caption, fontWeight: FontWeight.w600, color: colors.textSecondary)),
        ));
        for (final a in headerAtts) {
          children.add(_buildAttachmentRow(a, colors));
        }
      }
      // 表身附件（按明细行分组）
      for (final entry in bodyGroups.entries) {
        children.add(const SizedBox(height: 8));
        children.add(Padding(
          padding: const EdgeInsets.only(bottom: 8),
          child: Text('${l10n.get('detailLine')} ${entry.key}',
              style: TextStyle(fontSize: AppFontSizes.caption, fontWeight: FontWeight.w600, color: colors.textSecondary)),
        ));
        for (final a in entry.value) {
          children.add(_buildAttachmentRow(a, colors));
        }
      }
    }

    return FormSection(
      title: l10n.get('attachments'),
      leadingIcon: Icons.attach_file_outlined,
      children: children,
    );
  }

  Widget _buildAttachmentRow(BillAttachment a, AppColorsExtension colors) {
    return Container(
      margin: const EdgeInsets.symmetric(vertical: 4),
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      decoration: BoxDecoration(
        color: colors.bgPage,
        borderRadius: BorderRadius.circular(8),
      ),
      child: Row(children: [
        Icon(_fileTypeIcon(a.ext), size: 24, color: colors.primary),
        const SizedBox(width: 10),
        Expanded(
          child: Text(a.fileName,
              maxLines: 1, overflow: TextOverflow.ellipsis,
              style: TextStyle(fontSize: AppFontSizes.body, color: colors.textPrimary)),
        ),
      ]),
    );
  }

  // ═══ 审核流程 — 使用 ApprovalTimeline 组件 ═══
  Widget _buildApprovalSection(
      AppLocalizations l10n, AppColorsExtension colors) {
    return FormSection(
      title: l10n.get('approvalFlow'),
      leadingIcon: Icons.fact_check_outlined,
      children: [
        ApprovalTimeline(
          records: _timelineRecords,
          chain: _timelineChain,
          currentApproverId: _timelineCurrentApproverId,
        ),
      ],
    );
  }

  IconData _fileTypeIcon(String ext) {
    switch (ext.toLowerCase()) {
      case 'pdf': return Icons.picture_as_pdf;
      case 'doc': case 'docx': return Icons.description;
      case 'xls': case 'xlsx': return Icons.table_chart;
      case 'jpg': case 'jpeg': case 'png': case 'gif': case 'bmp': return Icons.image_outlined;
      default: return Icons.insert_drive_file;
    }
  }
}
