import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';
import 'package:tdesign_flutter/tdesign_flutter.dart';
import '../../core/i18n/app_localizations.dart';
import '../../core/storage/draft_storage.dart';
import '../../shared/widgets/action_bar.dart';
import '../../shared/widgets/form_section.dart';
import '../../shared/widgets/form_field_row.dart';
import '../../shared/widgets/nav_bar_config.dart';
import '../../shared/widgets/attachment_picker.dart';
import '../../core/theme/app_colors.dart';
import '../../core/theme/app_colors_extension.dart';
import '../../core/constants/enums.dart';
import '../../core/data/mock_api_data.dart';
import 'widgets/expense_apply_detail_dialog.dart';

class ExpenseApplyCreatePage extends ConsumerStatefulWidget {
  final String? id;
  const ExpenseApplyCreatePage({super.key, this.id});

  @override
  ConsumerState<ExpenseApplyCreatePage> createState() =>
      _ExpenseApplyCreatePageState();
}

class _ExpenseApplyCreatePageState
    extends ConsumerState<ExpenseApplyCreatePage> {
  static const _draftKey = 'expense_apply';

  // ── 基本信息 ──
  String _urgency = Urgency.normal.value;
  final _purposeController = TextEditingController();
  final _purposeFocus = FocusNode();
  String _validUntil = '';
  final _referenceNoController = TextEditingController();
  final _remarkController = TextEditingController();
  final _remarkFocus = FocusNode();
  final _scrollCtrl = ScrollController();

  // ── 费用明细 ──
  final List<_DetailItem> _details = [];
  int _detailIdCounter = 1;

  // ── 附件 ──
  late final AttachmentPickerController _attachmentController;

  @override
  void initState() {
    super.initState();
    _attachmentController = AttachmentPickerController(maxCount: 9)
      ..addListener(() => setState(() {}));
    _purposeFocus.addListener(() => _ensureVisible(_purposeFocus));
    _remarkFocus.addListener(() => _ensureVisible(_remarkFocus));
    WidgetsBinding.instance.addPostFrameCallback((_) => _checkDraft());
  }

  void _ensureVisible(FocusNode node) {
    if (!node.hasFocus) return;
    WidgetsBinding.instance.addPostFrameCallback((_) {
      if (node.hasFocus && _scrollCtrl.hasClients) {
        final ctx = node.context;
        if (ctx != null) {
          Scrollable.ensureVisible(
            ctx,
            alignment: 0.3,
            duration: const Duration(milliseconds: 300),
          );
        }
      }
    });
  }

  @override
  void dispose() {
    _purposeController.dispose();
    _purposeFocus.dispose();
    _referenceNoController.dispose();
    _remarkController.dispose();
    _remarkFocus.dispose();
    _attachmentController.dispose();
    _scrollCtrl.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context);
    ref
        .read(navBarConfigProvider.notifier)
        .update(
          NavBarConfig(
            title: l10n.get('expenseApplyRequest'),
            showBack: true,
            onBack: () => _doPop(),
          ),
        );

    return PopScope(
      canPop: false,
      onPopInvokedWithResult: (didPop, _) {
        if (didPop) return;
        if (_hasUnsaved()) {
          _showConfirmDialog(
            l10n.get('confirmExit'),
            l10n.get('unsavedContentWarning'),
            l10n.get('continueEditing'),
            l10n.get('discardAndExit'),
            () => _doPop(),
          );
        } else {
          _doPop();
        }
      },
      child: Column(
        children: [
          Expanded(
            child: GestureDetector(
              onTap: () => FocusScope.of(context).unfocus(),
              child: SingleChildScrollView(
                controller: _scrollCtrl,
                padding: const EdgeInsets.all(16),
                child: Column(
                  children: [
                    _buildBasicInfo(l10n),
                    const SizedBox(height: 16),
                    _buildDetailsSection(l10n),
                    const SizedBox(height: 16),
                    _buildAttachmentSection(l10n),
                    const SizedBox(height: 80),
                  ],
                ),
              ),
            ),
          ),
          _buildBottomBar(l10n),
        ],
      ),
    );
  }

  // ═══ 草稿持久化 ═══

  Future<void> _checkDraft() async {
    if (!mounted) return;
    final has = await DraftStorage.has(_draftKey);
    if (!has || !mounted) return;
    final l10n = AppLocalizations.of(context);
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    final yes = await showDialog<bool>(
      context: context,
      builder: (ctx) => TDAlertDialog(
        title: l10n.get('draftFound'),
        content: l10n.get('draftRestorePrompt'),
        leftBtn: TDDialogButtonOptions(
          title: l10n.get('discard'),
          titleColor: colors.textSecondary,
          action: () => Navigator.pop(ctx, false),
        ),
        rightBtn: TDDialogButtonOptions(
          title: l10n.get('restore'),
          titleColor: colors.primary,
          action: () => Navigator.pop(ctx, true),
        ),
      ),
    );
    if (yes == true && mounted) {
      await _restoreDraft();
    } else {
      await DraftStorage.delete(_draftKey);
    }
  }

  Future<void> _restoreDraft() async {
    final data = await DraftStorage.load(_draftKey);
    if (data == null) return;
    setState(() {
      _urgency = data['urgency'] as String? ?? Urgency.normal.value;
      _purposeController.text = data['purpose'] as String? ?? '';
      _validUntil = data['validUntil'] as String? ?? '';
      _referenceNoController.text = data['referenceNo'] as String? ?? '';
      _remarkController.text = data['remark'] as String? ?? '';
      final attData = data['attachments'] as List<dynamic>?;
      if (attData != null) {
        _attachmentController.restoreFromPaths(attData.cast<String>());
      }
      _details.clear();
      final detailList = data['details'] as List<dynamic>?;
      if (detailList != null) {
        for (final d in detailList) {
          final m = d as Map<String, dynamic>;
          _details.add(_DetailItem(
            id: m['id'] as int? ?? _detailIdCounter++,
            category: m['category'] as String? ?? '',
            categoryName: m['categoryName'] as String? ?? '',
            acctSubjectId: m['acctSubjectId'] as String? ?? '',
            acctSubjectName: m['acctSubjectName'] as String? ?? '',
            purpose: m['purpose'] as String? ?? '',
            projectId: m['projectId'] as int? ?? 0,
            projectName: m['projectName'] as String? ?? '',
            costDeptId: m['costDeptId'] as String? ?? '',
            costDeptName: m['costDeptName'] as String? ?? '',
            startDate: m['startDate'] as String? ?? '',
            endDate: m['endDate'] as String? ?? '',
            estimatedAmount: (m['estimatedAmount'] as num?)?.toDouble() ?? 0,
            remark: m['remark'] as String? ?? '',
          ));
        }
      }
      _detailIdCounter = _details.isEmpty ? 1 : _details.map((d) => d.id).reduce((a, b) => a > b ? a : b) + 1;
    });
  }

  Future<void> _saveDraftToStorage() async {
    final detailList = _details.map((d) => {
      'id': d.id,
      'category': d.category,
      'categoryName': d.categoryName,
      'acctSubjectId': d.acctSubjectId,
      'acctSubjectName': d.acctSubjectName,
      'purpose': d.purpose,
      'projectId': d.projectId,
      'projectName': d.projectName,
      'costDeptId': d.costDeptId,
      'costDeptName': d.costDeptName,
      'startDate': d.startDate,
      'endDate': d.endDate,
      'estimatedAmount': d.estimatedAmount,
      'remark': d.remark,
    }).toList();
    await DraftStorage.save(_draftKey, {
      'urgency': _urgency,
      'purpose': _purposeController.text,
      'validUntil': _validUntil,
      'referenceNo': _referenceNoController.text,
      'remark': _remarkController.text,
      'attachments': _attachmentController.toPathList(),
      'details': detailList,
    });
  }

  // ═══ 1. 基本信息 ═══
  Widget _buildBasicInfo(AppLocalizations l10n) {
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    return FormSection(
      title: l10n.get('basicInfo'),
      leadingIcon: Icons.info_outline,
      children: [
        FormFieldRow(
          label: l10n.get('applicant'),
          value: '张三',
          readOnly: true,
          showArrow: false,
        ),
        const SizedBox(height: 16),
        FormFieldRow(
          label: l10n.get('department'),
          value: '技术部',
          readOnly: true,
          showArrow: false,
        ),
        const SizedBox(height: 16),
        FormFieldRow(
          label: l10n.get('date'),
          value: _today(),
          readOnly: true,
          showArrow: false,
        ),
        const SizedBox(height: 16),
        _label(l10n.get('emergencyLevel'), required: true),
        const SizedBox(height: 8),
        _buildUrgencyRadio(l10n),
        const SizedBox(height: 16),
        _label(l10n.get('feeReason'), required: true),
        const SizedBox(height: 8),
        TDTextarea(
          controller: _purposeController,
          focusNode: _purposeFocus,
          hintText: l10n.get('enterFeeReason'),
          maxLines: 4,
          minLines: 1,
          maxLength: 500,
          indicator: true,
          padding: EdgeInsets.zero,
          bordered: true,
          backgroundColor: colors.bgPage,
        ),
        const SizedBox(height: 16),
        FormFieldRow(
          label: l10n.get('validUntil'),
          value: _validUntil,
          hint: l10n.get('pleaseSelect'),
          onTap: () => _pickDate((d) => setState(() => _validUntil = d)),
        ),
        const SizedBox(height: 16),
        FormFieldRow(
          label: l10n.get('relatedContractNo'),
          value: _referenceNoController.text,
          hint: l10n.get('optional'),
          onTap: () => _showTextInput(
            l10n.get('relatedContractNo'),
            (v) => setState(() {
              _referenceNoController.text = v;
              _referenceNoController.selection = TextSelection.fromPosition(
                TextPosition(offset: v.length),
              );
            }),
            initialText: _referenceNoController.text,
          ),
        ),
        const SizedBox(height: 16),
        _label(l10n.get('remark')),
        const SizedBox(height: 8),
        TDTextarea(
          controller: _remarkController,
          focusNode: _remarkFocus,
          hintText: l10n.get('enterRemark'),
          maxLines: 3,
          minLines: 1,
          maxLength: 500,
          indicator: true,
          padding: EdgeInsets.zero,
          bordered: true,
          backgroundColor: colors.bgPage,
        ),
      ],
    );
  }

  Widget _buildUrgencyRadio(AppLocalizations l10n) {
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    return Row(
      children: Urgency.values.asMap().entries.map((e) {
        final sel = _urgency == e.value.value;
        final isCritical = e.value.value == Urgency.critical.value;
        final activeColor = isCritical ? colors.danger : colors.primary;
        return Padding(
          padding: EdgeInsets.only(right: e.key < 2 ? 24 : 0),
          child: GestureDetector(
            behavior: HitTestBehavior.opaque,
            onTap: () => setState(() => _urgency = e.value.value),
            child: Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                Container(
                  width: 18,
                  height: 18,
                  decoration: BoxDecoration(
                    shape: BoxShape.circle,
                    border: Border.all(
                      color: sel ? activeColor : colors.textPlaceholder,
                      width: 2,
                    ),
                  ),
                  child: sel
                      ? Center(
                          child: Container(
                            width: 8,
                            height: 8,
                            decoration: BoxDecoration(
                              shape: BoxShape.circle,
                              color: activeColor,
                            ),
                          ),
                        )
                      : null,
                ),
                const SizedBox(width: 6),
                Text(
                  l10n.get(e.value.labelKey),
                  style: TextStyle(
                    fontSize: AppFontSizes.subtitle,
                    color: sel ? activeColor : colors.textPrimary,
                  ),
                ),
              ],
            ),
          ),
        );
      }).toList(),
    );
  }

  // ═══ 2. 费用明细 ═══
  Widget _buildDetailsSection(AppLocalizations l10n) {
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    return FormSection(
      title: l10n.get('expenseDetails'),
      leadingIcon: Icons.receipt_long_outlined,
      showAction: true,
      actionText: l10n.get('add'),
      onActionTap: _showDetailDialog,
      children: [
        if (_details.isEmpty)
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 8),
            child: Text(
              l10n.get('noDetailHint'),
              style: TextStyle(
                fontSize: AppFontSizes.subtitle,
                color: colors.textPlaceholder,
              ),
            ),
          )
        else
          ..._details.asMap().entries.map((e) {
            final d = e.value;
            return Container(
              margin: const EdgeInsets.symmetric(vertical: 8),
              padding: const EdgeInsets.all(12),
              decoration: BoxDecoration(
                color: colors.bgPage,
                borderRadius: BorderRadius.circular(8),
              ),
              child: Row(
                children: [
                  Expanded(
                    flex: 3,
                    child: Column(
                      crossAxisAlignment: CrossAxisAlignment.start,
                      children: [
                        Text(
                          d.categoryName,
                          style: TextStyle(
                            fontSize: AppFontSizes.subtitle,
                            color: colors.textPrimary,
                          ),
                        ),
                        if (d.purpose.isNotEmpty)
                          Text(
                            d.purpose,
                            maxLines: 2,
                            overflow: TextOverflow.ellipsis,
                            style: TextStyle(
                              fontSize: AppFontSizes.caption,
                              color: colors.textPrimary,
                            ),
                          ),
                        const SizedBox(height: 4),
                        Text(
                          '¥${d.estimatedAmount.toStringAsFixed(2)}',
                          style: TextStyle(
                            fontSize: AppFontSizes.caption,
                            fontWeight: FontWeight.w600,
                            color: colors.amountPrimary,
                          ),
                        ),
                        if (d.projectName.isNotEmpty)
                          Text(
                            '${d.projectName}  |  ${d.acctSubjectName}',
                            style: TextStyle(
                              fontSize: AppFontSizes.caption,
                              color: colors.textSecondary,
                            ),
                          ),
                        if (d.remark.isNotEmpty)
                          Text(
                            d.remark,
                            maxLines: 1,
                            overflow: TextOverflow.ellipsis,
                            style: TextStyle(
                              fontSize: AppFontSizes.caption,
                              color: colors.textPlaceholder,
                            ),
                          ),
                      ],
                    ),
                  ),
                  GestureDetector(
                    onTap: () => setState(() => _details.removeAt(e.key)),
                    child: Container(
                      width: 24,
                      height: 24,
                      decoration: BoxDecoration(
                        color: colors.primaryLight,
                        shape: BoxShape.circle,
                      ),
                      child: Icon(
                        Icons.close,
                        size: 14,
                        color: colors.primary700,
                      ),
                    ),
                  ),
                ],
              ),
            );
          }),
        const SizedBox(height: 8),
        Container(
          height: 36,
          padding: const EdgeInsets.symmetric(vertical: 8),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(
                l10n.get('total'),
                style: TextStyle(
                  fontSize: AppFontSizes.body,
                  fontWeight: FontWeight.w600,
                  color: colors.textPrimary,
                ),
              ),
              Text(
                '¥${_totalAmount().toStringAsFixed(2)}',
                style: TextStyle(
                  fontSize: AppFontSizes.subtitle,
                  fontWeight: FontWeight.w700,
                  color: colors.amountPrimary,
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }

  double _totalAmount() =>
      _details.fold(0, (s, d) => s + d.estimatedAmount);

  Future<void> _showDetailDialog() async {
    final l10n = AppLocalizations.of(context);
    final result = await ExpenseApplyDetailDialog.show(
      context,
      categories: mockCostCategories,
      projects: mockProjects,
      costDepts: mockCostDepts,
      l10n: l10n,
    );
    if (result != null && mounted) {
      setState(
        () => _details.add(
          _DetailItem(
            id: _detailIdCounter++,
            category: result.category,
            categoryName: result.categoryName,
            acctSubjectId: result.acctSubjectId,
            acctSubjectName: result.acctSubjectName,
            purpose: result.purpose,
            projectId: result.projectId,
            projectName: result.projectName,
            costDeptId: result.costDeptId,
            costDeptName: result.costDeptName,
            startDate: result.startDate,
            endDate: result.endDate,
            estimatedAmount: result.estimatedAmount,
            remark: result.remark,
          ),
        ),
      );
    }
  }

  // ═══ 3. 附件上传 ═══

  Widget _buildAttachmentSection(AppLocalizations l10n) {
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    return FormSection(
      title: l10n.get('attachmentUpload'),
      leadingIcon: Icons.attach_file_outlined,
      children: [
        Text(
          l10n.get('maxAttachment'),
          style: TextStyle(
            fontSize: AppFontSizes.caption,
            color: colors.textPlaceholder,
          ),
        ),
        const SizedBox(height: 8),
        AttachmentPicker(
          controller: _attachmentController,
          maxImageSizeMB: 10,
          maxFileSizeMB: 20,
          allowedExtensions: const [
            'pdf', 'doc', 'docx', 'xls', 'xlsx', 'ppt', 'pptx', 'txt',
          ],
          onFileRejected: (file, reason) {
            if (context.mounted) {
              TDToast.showText(reason, context: context);
            }
          },
        ),
      ],
    );
  }

  // ═══ 4. 底部操作栏 ═══
  Widget _buildBottomBar(AppLocalizations l10n) {
    final isDraft = widget.id != null;
    return ActionBar(
      leftLabel: isDraft ? l10n.get('reset') : null,
      centerLabel: l10n.get('saveDraft'),
      rightLabel: l10n.get('submitApproval'),
      showLeft: isDraft,
      onLeftTap: isDraft
          ? () => _showConfirmDialog(
              l10n.get('confirmReset'),
              l10n.get('resetWarning'),
              l10n.get('cancel'),
              l10n.get('confirmReset'),
              _resetAll,
            )
          : null,
      onCenterTap: () async {
        await _saveDraftToStorage();
        if (mounted) {
          TDToast.showSuccess(l10n.get('draftSavedToast'), context: context);
          context.pop();
        }
      },
      onRightTap: () async {
        final err = _validate(l10n);
        if (err.isNotEmpty) {
          TDToast.showText(err.first, context: context);
          return;
        }
        await DraftStorage.delete(_draftKey);
        if (mounted) {
          TDToast.showSuccess(
            l10n.get('submittedAwaitingApproval'),
            context: context,
          );
          context.pop();
        }
      },
    );
  }

  List<String> _validate(AppLocalizations l10n) {
    final e = <String>[];
    if (_purposeController.text.trim().isEmpty) {
      e.add(l10n.get('enterFeeReason'));
    }
    if (_details.isEmpty) e.add(l10n.get('addAtLeastOneDetail'));
    return e;
  }

  void _resetAll() => setState(() {
    _purposeController.clear();
    _urgency = Urgency.normal.value;
    _validUntil = '';
    _referenceNoController.clear();
    _remarkController.clear();
    _details.clear();
    _attachmentController.clear();
  });

  void _doPop() {
    final router = GoRouter.of(context);
    if (router.canPop()) {
      router.pop();
    } else {
      SystemNavigator.pop();
    }
  }

  bool _hasUnsaved() =>
      _purposeController.text.isNotEmpty ||
      _details.isNotEmpty ||
      _attachmentController.files.isNotEmpty ||
      _referenceNoController.text.isNotEmpty ||
      _remarkController.text.isNotEmpty;

  void _unfocus() => FocusScope.of(context).unfocus();

  // ═══ 通用弹窗方法 ═══
  void _showConfirmDialog(
    String title,
    String content,
    String leftText,
    String rightText,
    VoidCallback onConfirm,
  ) {
    _unfocus();
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    showDialog(
      context: context,
      builder: (ctx) => TDAlertDialog(
        title: title,
        content: content,
        buttonStyle: TDDialogButtonStyle.text,
        leftBtn: TDDialogButtonOptions(
          title: leftText,
          titleColor: colors.primary,
          action: () => Navigator.pop(ctx),
        ),
        rightBtn: TDDialogButtonOptions(
          title: rightText,
          titleColor: colors.danger,
          action: () {
            Navigator.pop(ctx);
            onConfirm();
          },
        ),
      ),
    );
  }

  void _showTextInput(
    String title,
    Function(String) onConfirm, {
    String initialText = '',
  }) {
    _unfocus();
    final l10n = AppLocalizations.of(context);
    final c = TextEditingController(text: initialText);
    showGeneralDialog(
      context: context,
      pageBuilder: (ctx, animation, secondaryAnimation) => TDInputDialog(
        textEditingController: c,
        title: title,
        hintText: l10n.get('pleaseEnter'),
        leftBtn: TDDialogButtonOptions(
          title: l10n.get('cancel'),
          action: () => Navigator.pop(ctx),
        ),
        rightBtn: TDDialogButtonOptions(
          title: l10n.get('confirm'),
          action: () {
            onConfirm(c.text);
            Navigator.pop(ctx);
          },
        ),
      ),
    );
  }

  void _pickDate(Function(String) onPick) {
    _unfocus();
    final l10n = AppLocalizations.of(context);
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    final theme = Theme.of(context);
    final now = DateTime.now();
    showModalBottomSheet(
      context: context,
      backgroundColor: Colors.transparent,
      builder: (ctx) => Theme(
        data: theme,
        child: TDDatePicker(
          title: l10n.get('selectDate'),
          backgroundColor: colors.bgCard,
          model: DatePickerModel(
            useYear: true,
            useMonth: true,
            useDay: true,
            useHour: false,
            useMinute: false,
            useSecond: false,
            useWeekDay: false,
            dateStart: [2020, 1, 1],
            dateEnd: [now.year + 1, 12, 31],
            dateInitial: [now.year, now.month, now.day],
          ),
          onConfirm: (selected) {
            onPick(
              '${selected['year']}-${selected['month']!.toString().padLeft(2, '0')}-${selected['day']!.toString().padLeft(2, '0')}',
            );
            Navigator.of(ctx).pop();
          },
          onCancel: (_) => Navigator.of(ctx).pop(),
        ),
      ),
    );
  }

  Widget _label(String t, {bool required = false}) {
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    return Text.rich(
      TextSpan(
        children: [
          TextSpan(
            text: t,
            style: TextStyle(
              fontSize: AppFontSizes.subtitle,
              color: colors.textSecondary,
            ),
          ),
          if (required)
            TextSpan(
              text: ' *',
              style: TextStyle(
                fontSize: AppFontSizes.subtitle,
                color: colors.danger,
              ),
            ),
        ],
      ),
    );
  }

  String _today() {
    final n = DateTime.now();
    return '${n.year}-${n.month.toString().padLeft(2, '0')}-${n.day.toString().padLeft(2, '0')}';
  }
}

class _DetailItem {
  final int id;
  final String category;
  final String categoryName;
  final String acctSubjectId;
  final String acctSubjectName;
  final String purpose;
  final int projectId;
  final String projectName;
  final String costDeptId;
  final String costDeptName;
  final String startDate;
  final String endDate;
  final double estimatedAmount;
  final String remark;
  const _DetailItem({
    required this.id,
    required this.category,
    required this.categoryName,
    required this.acctSubjectId,
    required this.acctSubjectName,
    required this.purpose,
    required this.projectId,
    required this.projectName,
    required this.costDeptId,
    required this.costDeptName,
    required this.startDate,
    required this.endDate,
    required this.estimatedAmount,
    required this.remark,
  });
}
