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 'package:go_router/go_router.dart';
import '../../shared/widgets/attachment_preview_page.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
import 'package:flutter_riverpod/flutter_riverpod.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 '../../shared/widgets/app_skeletons.dart';
import '../../shared/models/bill_file_rights.dart';
import '../../shared/widgets/attachment_download_helper.dart';
import '../../shared/widgets/action_bar.dart';
import '../../core/navigation/host_app_channel.dart';
import 'expense_apply_model.dart';
import 'widgets/expense_apply_detail_view_dialog.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';
import '../../core/utils/amount_utils.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> {
  bool _loading = true;
  String? _error;
  ExpenseApplyModel? _data;
  List<BillAttachment> _attachments = [];
  bool _attachAvailable = false;
  BillFileRights _billFileRights = BillFileRights.none;
  Map<String, dynamic>? _billStatus;
  bool _statusLoading = false;
  bool _canEdit = false;

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

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

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

      // 加载附件权限
      BillFileRights billFileRights = BillFileRights.none;
      try {
        billFileRights = await api.getBillFileRights('AE');
      } catch (_) {}

      List<BillAttachment> attachments = [];
      if (attachAvailable && billFileRights.canBrowseAttachments) {
        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;
          _billFileRights = billFileRights;
          _loading = false;
        });
      }

      // 单据状态（非关键，尽力加载）
      setState(() => _statusLoading = true);
      try {
        final status = await api.getBillStatus(widget.billNo);
        if (mounted) {
          setState(() {
            _billStatus = status;
            _canEdit = status['canEdit'] == true;
            _statusLoading = false;
          });
        }
      } catch (_) {
        if (mounted) setState(() => _statusLoading = 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);

    if (_loading) {
      return const SkeletonDetailPage();
    }

    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 Column(
      children: [
        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),
              ],
            ),
          ),
        ),
        // TODO: 等 ERP 提供"能否修改单据"接口后，恢复为 if (_canEdit)
        if (false)
          ActionBar(
            showLeft: false,
            showCenter: false,
            rightLabel: l10n.get('editApply'),
            onRightTap: () async {
              final result = await GoRouter.of(
                context,
              ).push('/expense-apply/edit/${widget.billNo}');
              if (result == true && mounted) _loadData();
            },
          ),
      ],
    );
  }

  // ═══ 状态 tag（标题行右侧） ═══
  Widget? _buildStatusTag(AppLocalizations l10n) {
    final isTransferred = _billStatus?['isTransferred'] == true;
    final approvalStatus = _billStatus?['approvalStatus'] as String?;
    final approvalText = _billStatus?['approvalText'] as String? ?? '';

    IconData icon;
    String text;
    Color color;

    if (isTransferred) {
      icon = Icons.swap_horiz;
      text = l10n.get('statusConvertedToExpense');
      color = Colors.blue;
    } else if (approvalStatus == null || approvalStatus.isEmpty) {
      return null;
    } else {
      switch (approvalStatus) {
        case 'SHCOUNT0':
          icon = Icons.edit_note;
          color = Colors.teal;
          break;
        case 'SHCOUNT1':
          icon = Icons.hourglass_empty;
          color = Colors.blueGrey;
          break;
        case 'SHCOUNT2':
          icon = Icons.cancel_outlined;
          color = Colors.red;
          break;
        case 'SHCOUNT3':
          icon = Icons.undo;
          color = Colors.deepOrange;
          break;
        case 'SHCOUNT4':
          icon = Icons.check_circle_outline;
          color = Colors.green;
          break;
        default:
          return null;
      }
      text = approvalText;
    }

    final tag = Container(
      padding: const EdgeInsets.symmetric(horizontal: 10, vertical: 4),
      decoration: BoxDecoration(
        color: color.withValues(alpha: 0.1),
        borderRadius: BorderRadius.circular(6),
        border: Border.all(color: color.withValues(alpha: 0.3), width: 0.5),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(icon, size: 18, color: color),
          const SizedBox(width: 4),
          Text(
            text,
            style: TextStyle(
              fontSize: 13,
              fontWeight: FontWeight.w600,
              color: color,
            ),
          ),
        ],
      ),
    );
    final canTap =
        approvalStatus != null &&
        approvalStatus.isNotEmpty &&
        approvalText.isNotEmpty;
    if (canTap) {
      return GestureDetector(onTap: () => _showAuditTrail('AE'), child: tag);
    }
    return tag;
  }

  Future<void> _showAuditTrail(String billId) async {
    await HostAppChannel.showAuditTrail(billId, widget.billNo);
  }

  // ═══ 基本信息 ═══
  Widget _buildBasicInfoSection(
    ExpenseApplyModel app,
    AppLocalizations l10n,
    AppColorsExtension colors,
  ) {
    return FormSection(
      title: l10n.get('basicInfo'),
      leadingIcon: Icons.info_outline,
      trailing: _buildStatusTag(l10n),
      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('applyDept'),
          value: app.deptId.isNotEmpty
              ? '${app.deptId}${app.deptName.isNotEmpty ? '/${app.deptName}' : ''}'
              : '-',
          readOnly: true,
          showArrow: false,
        ),
        const SizedBox(height: 16),
        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.isNotEmpty ? app.purpose : '-',
          readOnly: true,
          showArrow: false,
          bold: true,
          showMoreOnOverflow: true,
        ),
        const SizedBox(height: 16),
        FormFieldRow(
          label: l10n.get('remark'),
          value: app.remark.isNotEmpty ? app.remark : '-',
          readOnly: true,
          showArrow: false,
          bold: false,
          showMoreOnOverflow: true,
        ),
      ],
    );
  }

  // ═══ 费用明细 ═══
  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 GestureDetector(
              onTap: () => _showExpenseDetailDialog(context, d),
              child: 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(
                                formatAmount(d.estimatedAmount),
                                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.sqMan.isNotEmpty) ...[
                            const SizedBox(height: 4),
                            Text(
                              '${l10n.get('applicant')}: ${d.sqMan}${d.sqName.isNotEmpty ? '/${d.sqName}' : ''}',
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                              style: TextStyle(
                                fontSize: AppFontSizes.caption,
                                color: colors.textSecondary,
                              ),
                            ),
                          ],
                          if (d.projectId.isNotEmpty) ...[
                            const SizedBox(height: 4),
                            Text(
                              '${l10n.get('project')}: ${d.projectId}${d.projectName.isNotEmpty ? '/${d.projectName}' : ''}',
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                              style: TextStyle(
                                fontSize: AppFontSizes.caption,
                                color: colors.textSecondary,
                              ),
                            ),
                          ],
                          if (d.costDeptId.isNotEmpty) ...[
                            const SizedBox(height: 4),
                            Text(
                              '${l10n.get('costDept')}: ${d.costDeptId}${d.costDeptName.isNotEmpty ? '/${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(
                formatAmount(
                  app.details.fold<double>(
                    0,
                    (sum, d) => sum + d.estimatedAmount,
                  ),
                ),
                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 (!_billFileRights.canBrowseAttachments) {
      children.add(
        Text(
          l10n.get('noAttachmentPermission'),
          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,
                ),
              ),
            ),
            const SizedBox(width: 8),
            GestureDetector(
              onTap: () => AttachmentDownloadHelper.downloadAndSave(
                context,
                a,
                ref.read(expenseApplyApiProvider).downloadAttachment,
              ),
              child: Icon(
                Icons.download_outlined,
                size: 22,
                color: colors.primary,
              ),
            ),
          ],
        ),
      ),
    );
  }

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

  void _showExpenseDetailDialog(
    BuildContext context,
    ExpenseApplyDetailModel d,
  ) {
    ExpenseApplyDetailViewDialog.show(context, d);
  }
}

/// 附件缩略图 — 自动调用 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,
    );
  }
}
