import 'dart:typed_data';
import 'dart:io';
import 'package:flutter/material.dart';
import 'package:path_provider/path_provider.dart';
import 'package:open_filex/open_filex.dart';
import 'widgets/attachment_preview_page.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 '../../shared/widgets/loading_dialog.dart';
import '../../core/utils/date_utils.dart' as du;
import '../../shared/widgets/form_section.dart';
import '../../shared/widgets/form_field_row.dart';
import 'expense_apply_model.dart';
import '../../core/i18n/app_localizations.dart';
import '../../shared/models/bill_attachment.dart';
import 'expense_apply_api.dart';
import '../../core/theme/app_colors.dart';
import '../../core/theme/app_colors_extension.dart';

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

  @override
  ConsumerState<ExpenseApplyDetailPage> createState() => _ExpenseApplyDetailPageState();
}

class _ExpenseApplyDetailPageState extends ConsumerState<ExpenseApplyDetailPage>
    with WidgetsBindingObserver {
  bool _loading = true;
  String? _error;
  ExpenseApplyModel? _data;
  List<BillAttachment> _attachments = [];
  bool _attachAvailable = false;

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

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

  bool _openingFile = false;

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

  Future<void> _loadData() async {
    setState(() { _loading = true; _error = null; });
    try {
      final api = ref.read(expenseApplyApiProvider);
      final detail = await api.fetchDetail(widget.billNo);

      // Load attachments (non-critical, best-effort)
      bool attachAvailable = false;
      try {
        attachAvailable = await api.checkAttachHealth();
        debugPrint('[Attach] checkAttachHealth result: $attachAvailable');
      } catch (e) {
        debugPrint('[Attach] checkAttachHealth error: $e');
        attachAvailable = false;
      }

      List<BillAttachment> attachments = [];
      if (attachAvailable) {
        try {
          attachments = await api.getAttachments('AE', widget.billNo);
          debugPrint('[Attach] getAttachments count: ${attachments.length}');
        } catch (e) {
          debugPrint('[Attach] getAttachments error: $e');
          // 附件列表加载失败不影响服务可用状态，保持空列表
        }
      }

      debugPrint('[Attach] final state: attachAvailable=$attachAvailable, count=${attachments.length}');
      if (mounted) {
        setState(() {
          _data = detail;
          _attachments = attachments;
          _attachAvailable = attachAvailable;
          _loading = false;
        });
      }
    } catch (e) {
      if (mounted) {
        setState(() { _error = e.toString(); _loading = 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('expenseApplyDetail'),
      showBack: true,
      onBack: () => context.pop(),
    ));

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

    if (_error != null) {
      return Center(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Icon(Icons.error_outline, size: 48, color: colors.danger),
            const SizedBox(height: 16),
            Padding(
              padding: const EdgeInsets.symmetric(horizontal: 32),
              child: Text(
                _error!,
                textAlign: TextAlign.center,
                style: TextStyle(fontSize: AppFontSizes.body, color: colors.textSecondary),
              ),
            ),
            const SizedBox(height: 16),
            TDButton(
              text: l10n.get('retry'),
              size: TDButtonSize.medium,
              onTap: _loadData,
            ),
          ],
        ),
      );
    }

    final app = _data!;

    return Expanded(
      child: SingleChildScrollView(
        physics: const AlwaysScrollableScrollPhysics(),
        padding: const EdgeInsets.all(16),
        child: Column(
          children: [
            _buildBasicInfoSection(app, l10n, colors),
            const SizedBox(height: 16),
            _buildExpenseDetailSection(app, l10n, colors),
            const SizedBox(height: 16),
            _buildAttachmentSection(l10n, colors),
            const SizedBox(height: 24),
            _buildPageFooter(colors),
          ],
        ),
      ),
    );
  }

  // ═══ 基本信息 ═══
  Widget _buildBasicInfoSection(
    ExpenseApplyModel app,
    AppLocalizations l10n,
    AppColorsExtension colors,
  ) {
    return FormSection(
      title: l10n.get('basicInfo'),
      leadingIcon: Icons.info_outline,
      children: [
        FormFieldRow(label: l10n.get('expenseApplyNo'), value: app.expenseApplyNo, readOnly: true, showArrow: false),
        const SizedBox(height: 16),
        FormFieldRow(label: l10n.get('date'), value: du.DateUtils.formatDate(app.createTime), readOnly: true, showArrow: false),
        const SizedBox(height: 16),
        FormFieldRow(label: l10n.get('applicant'), value: app.applicantName, readOnly: true, showArrow: false),
        const SizedBox(height: 16),
        FormFieldRow(label: l10n.get('department'), value: app.deptName, readOnly: true, showArrow: false),
        const SizedBox(height: 16),
        SizedBox(
          height: 24,
          child: Row(mainAxisAlignment: MainAxisAlignment.spaceBetween, children: [
            Text(l10n.get('emergencyLevel'), style: TextStyle(fontSize: AppFontSizes.subtitle, color: colors.textSecondary)),
            _buildUrgencyChip(app.urgency, l10n, colors),
          ]),
        ),
        const SizedBox(height: 16),
        FormFieldRow(label: l10n.get('applyReason'), value: app.purpose, readOnly: true, showArrow: false),
        const SizedBox(height: 16),
        FormFieldRow(label: l10n.get('remark'), value: app.remark.isNotEmpty ? app.remark : '-', readOnly: true, showArrow: false),
      ],
    );
  }

  // ═══ 费用明细 ═══
  Widget _buildExpenseDetailSection(
    ExpenseApplyModel app,
    AppLocalizations l10n,
    AppColorsExtension colors,
  ) {
    return FormSection(
      title: l10n.get('expenseDetails'),
      leadingIcon: Icons.receipt_long_outlined,
      children: [
        if (app.details.isEmpty)
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 8),
            child: Text(l10n.get('noDetailData'), style: TextStyle(fontSize: AppFontSizes.body, color: colors.textPlaceholder)),
          )
        else
          ...app.details.asMap().entries.map((e) {
            final d = e.value;
            final catLabel = d.categoryName.isNotEmpty
                ? '${d.expenseCategory}/${d.categoryName}'
                : d.expenseCategory;
            return Container(
              margin: const EdgeInsets.symmetric(vertical: 8),
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(color: colors.bgPage, borderRadius: BorderRadius.circular(8)),
              child: Row(
                crossAxisAlignment: CrossAxisAlignment.center,
                children: [
                  Expanded(
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Row(
                          mainAxisAlignment: MainAxisAlignment.spaceBetween,
                          children: [
                            Expanded(
                              child: Text(
                                catLabel,
                                maxLines: 1,
                                overflow: TextOverflow.ellipsis,
                                style: TextStyle(fontSize: AppFontSizes.subtitle, color: colors.textPrimary),
                              ),
                            ),
                            const SizedBox(width: 12),
                            Text(
                              '¥${d.estimatedAmount.toStringAsFixed(2)}',
                              style: TextStyle(fontSize: AppFontSizes.caption, fontWeight: FontWeight.w600, color: colors.amountPrimary),
                            ),
                          ],
                        ),
                        if (d.acctSubjectId.isNotEmpty) ...[
                          const SizedBox(height: 4),
                          Text(
                            '${l10n.get('acctSubject')}: ${d.acctSubjectId}${d.acctSubjectName.isNotEmpty ? '/$d.acctSubjectName' : ''}',
                            maxLines: 1,
                            overflow: TextOverflow.ellipsis,
                            style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary),
                          ),
                        ],
                        if (d.projectId.isNotEmpty && d.projectName.isNotEmpty) ...[
                          const SizedBox(height: 4),
                          Text(
                            '${d.projectId}/${d.projectName}',
                            maxLines: 1,
                            overflow: TextOverflow.ellipsis,
                            style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary),
                          ),
                        ],
                        if (d.costDeptId.isNotEmpty && d.costDeptName.isNotEmpty) ...[
                          const SizedBox(height: 4),
                          Text(
                            '${l10n.get('costDept')}: ${d.costDeptId}/${d.costDeptName}',
                            maxLines: 1,
                            overflow: TextOverflow.ellipsis,
                            style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary),
                          ),
                        ],
                        if (d.estimatedStartDate != null) ...[
                          const SizedBox(height: 4),
                          Text(
                            '${l10n.get('estimatedDate')}: ${du.DateUtils.formatDate(d.estimatedStartDate!)}${d.estimatedEndDate != null ? ' ~ ${du.DateUtils.formatDate(d.estimatedEndDate!)}' : ''}',
                            maxLines: 1,
                            overflow: TextOverflow.ellipsis,
                            style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary),
                          ),
                        ],
                        if (d.bxNo.isNotEmpty) ...[
                          const SizedBox(height: 4),
                          Text(
                            '${l10n.get('expenseNo')}: $d.bxNo',
                            maxLines: 1,
                            overflow: TextOverflow.ellipsis,
                            style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary),
                          ),
                        ],
                        if (d.remark.isNotEmpty) ...[
                          const SizedBox(height: 4),
                          Text(
                            d.remark,
                            maxLines: 2,
                            overflow: TextOverflow.ellipsis,
                            style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textSecondary),
                          ),
                        ],
                      ],
                    ),
                  ),
                ],
              ),
            );
          }),
        if (app.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)),
            Text('¥${app.estimatedAmount.toStringAsFixed(2)}',
                style: TextStyle(fontSize: AppFontSizes.subtitle, fontWeight: FontWeight.w700, color: colors.amountPrimary)),
          ]),
        ],
      ],
    );
  }

  // ═══ 附件 ═══
  Widget _buildAttachmentSection(AppLocalizations l10n, AppColorsExtension colors) {
    final children = <Widget>[];
    if (!_attachAvailable) {
      children.add(Text(l10n.get('attachServiceUnavailable'),
          style: TextStyle(fontSize: AppFontSizes.body, color: colors.textPlaceholder)));
    } else if (_attachments.isEmpty) {
      children.add(Text(l10n.get('noAttachment'),
          style: TextStyle(fontSize: AppFontSizes.body, color: colors.textPlaceholder)));
    } else {
      children.addAll(_attachments.map((a) => _buildAttachmentRow(a, colors)));
    }
    return FormSection(
      title: l10n.get('attachments'),
      leadingIcon: Icons.attach_file_outlined,
      children: children,
    );
  }

  Widget _buildAttachmentRow(BillAttachment a, AppColorsExtension colors) {
    final isImage = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].contains(a.ext.toLowerCase());
    return GestureDetector(
      onTap: () => _openAttachment(a),
      child: 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: [
          if (isImage)
            _AttachmentThumbnail(api: ref.read(expenseApplyApiProvider), attachment: a, size: 40)
          else
            Icon(_fileTypeIcon(a.ext), size: 40, 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)),
          ),
        ]),
      ),
    );
  }

  Future<void> _openAttachment(BillAttachment a) async {
    final l10n = AppLocalizations.of(context);
    final ext = a.ext.toLowerCase();
    final isImage = ['jpg', 'jpeg', 'png', 'gif', 'bmp', 'webp'].contains(ext);

    if (isImage) {
      // 图片 → 弹窗预览，内部自动下载并显示 loading
      final api = ref.read(expenseApplyApiProvider);
      AttachmentPreview.show(context,
        loader: api.downloadAttachment(a.id),
        fileName: a.fileName,
        loadingText: l10n.get('loading'),
      );
      return;
    }

    // 非图片 → 下载后调用系统工具打开
    try {
      LoadingDialog.show(context, text: l10n.get('downloading'));
      final api = ref.read(expenseApplyApiProvider);
      final bytes = await api.downloadAttachment(a.id);
      if (!mounted) return;
      LoadingDialog.hide(context);
      if (bytes == null) {
        TDToast.showText(l10n.get('downloadFailed'), context: context);
        return;
      }
      final dir = await getTemporaryDirectory();
      final file = File('${dir.path}/${a.fileName}');
      await file.writeAsBytes(bytes);
      _openingFile = true;
      await OpenFilex.open(file.path);
    } catch (_) {
      if (mounted) LoadingDialog.hide(context);
      if (mounted) TDToast.showText(l10n.get('openFailed'), context: context);
    }
  }

  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;
    }
  }

  Widget _buildPageFooter(AppColorsExtension colors) {
    final l10n = AppLocalizations.of(context);
    return Center(
      child: Padding(
        padding: const EdgeInsets.only(bottom: 16),
        child: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            Icon(Icons.rocket_launch_outlined, size: 16, color: colors.textPlaceholder),
            const SizedBox(width: 6),
            Text(l10n.get('pageFooter'),
                style: TextStyle(fontSize: AppFontSizes.caption, color: colors.textPlaceholder)),
          ],
        ),
      ),
    );
  }

  Widget _buildUrgencyChip(String urgency, AppLocalizations l10n, AppColorsExtension colors) {
    final (label, color) = switch (urgency) {
      '3' || 'critical' => (l10n.get('critical'), colors.danger),
      '2' || 'urgent' => (l10n.get('urgent'), colors.warning),
      '1' || 'normal' => (l10n.get('normal'), colors.primary),
      _ => (l10n.get('normal'), colors.primary),
    };
    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 6, vertical: 1),
      decoration: BoxDecoration(
        color: color.withValues(alpha: 0.1),
        borderRadius: BorderRadius.circular(4),
        border: Border.all(color: color, width: 0.5),
      ),
      child: Text(label, style: TextStyle(fontSize: 11, fontWeight: FontWeight.w500, color: color)),
    );
  }
}

/// 附件缩略图 — 自动调用 DownloadAttachment 加载图片
class _AttachmentThumbnail extends StatefulWidget {
  final ExpenseApplyApi api;
  final BillAttachment attachment;
  final double size;
  const _AttachmentThumbnail({required this.api, required this.attachment, required this.size});
  @override
  State<_AttachmentThumbnail> createState() => _AttachmentThumbnailState();
}

class _AttachmentThumbnailState extends State<_AttachmentThumbnail> {
  Uint8List? _bytes;
  bool _loading = true;

  @override
  void initState() {
    super.initState();
    _load();
  }

  Future<void> _load() async {
    try {
      final bytes = await widget.api.downloadAttachment(widget.attachment.id);
      if (mounted) setState(() { _bytes = bytes; _loading = false; });
    } catch (_) {
      if (mounted) setState(() => _loading = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    if (_loading) {
      return SizedBox(width: widget.size, height: widget.size,
          child: const Center(child: SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2))));
    }
    if (_bytes != null) {
      return ClipRRect(
        borderRadius: BorderRadius.circular(4),
        child: Image.memory(_bytes!, width: widget.size, height: widget.size, fit: BoxFit.cover),
      );
    }
    return Icon(Icons.broken_image, size: widget.size * 0.6, color: Colors.grey);
  }
}
