import 'dart:async';

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/navigation/host_app_channel.dart';
import '../../core/storage/draft_storage.dart';
import '../../core/theme/app_colors.dart';
import '../../core/theme/app_colors_extension.dart';
import '../../core/utils/amount_utils.dart';
import '../../shared/widgets/action_bar.dart';
import '../../shared/widgets/app_skeletons.dart';
import '../../shared/widgets/form_field_row.dart';
import '../../shared/widgets/form_section.dart';
import '../../shared/widgets/loading_dialog.dart';
import '../../shared/widgets/nav_bar_config.dart';
import '../../shared/widgets/searchable_picker_sheet.dart';
import '../expense_apply/expense_apply_api.dart';
import 'overtime_api.dart';
import 'widgets/overtime_detail_dialog.dart';

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

  @override
  ConsumerState<OvertimeCreatePage> createState() => _OvertimeCreatePageState();
}

class _OvertimeCreatePageState extends ConsumerState<OvertimeCreatePage> {
  static const _draftKey = 'overtime_apply';

  // ── 基本信息 ──
  String _billType = '工作日加班';
  String _selectedDeptId = '';
  String _selectedDeptName = '';
  String _selectedSalesmanId = '';
  String _selectedSalesmanName = '';
  final _customerController = TextEditingController();
  final _origBillNoController = TextEditingController();
  bool _isClosed = false;
  final _feedbackController = TextEditingController();
  final _remarkController = TextEditingController();
  final _scrollCtrl = ScrollController();

  // ── 明细 ──
  final List<OvertimeDetailData> _details = [];

  // ── 草稿 ──
  late Future<bool> _draftFuture;
  bool _draftHandled = false;

  // ── 参考数据 ──
  List<DepartmentItem> _departments = [];
  bool _firstBuild = true;
  bool _refDataLoading = true;
  bool _addingDetail = false;

  @override
  void initState() {
    super.initState();
    SystemChrome.setSystemUIOverlayStyle(
      const SystemUiOverlayStyle(
        statusBarColor: Colors.transparent,
        statusBarIconBrightness: Brightness.dark,
      ),
    );
    _departments = [];
    _refDataLoading = true;
    _draftFuture = DraftStorage.has(_draftKey);
    _loadRefData();
    WidgetsBinding.instance.addPostFrameCallback((_) => _checkDataReady());
  }

  void _checkDataReady() {
    if (!_refDataLoading && mounted) {
      setState(() => _firstBuild = false);
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (mounted) setState(() {});
      });
    } else if (mounted) {
      WidgetsBinding.instance.addPostFrameCallback((_) => _checkDataReady());
    }
  }

  Future<void> _loadRefData({bool showLoading = false}) async {
    if (showLoading) {
      LoadingDialog.show(
        context,
        text: AppLocalizations.of(context).get('dataLoading'),
      );
    }
    try {
      final api = ref.read(overtimeApiProvider);
      final deps = await api.getDepartments();
      if (!mounted) return;
      setState(() {
        _departments = deps;
        _refDataLoading = false;
        _autoSelectDept();
      });
    } catch (_) {
      if (!mounted) return;
      setState(() => _refDataLoading = false);
    } finally {
      if (showLoading && mounted) LoadingDialog.hide(context);
    }
  }

  void _autoSelectDept() {
    if (_selectedDeptId.isNotEmpty) return;
    final dep = HostAppChannel.dep;
    if (dep.isEmpty) return;
    final match = _departments.where((d) => d.dep == dep);
    if (match.isNotEmpty) {
      _selectedDeptId = match.first.dep;
      _selectedDeptName = match.first.name;
    }
  }

  @override
  void dispose() {
    _customerController.dispose();
    _origBillNoController.dispose();
    _feedbackController.dispose();
    _remarkController.dispose();
    _scrollCtrl.dispose();
    super.dispose();
  }

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

  Future<void> _restoreDraft() async {
    final data = await DraftStorage.load(_draftKey);
    if (data == null) return;
    setState(() {
      _billType = data['billType'] as String? ?? '工作日加班';
      _selectedDeptId = data['selectedDeptId'] as String? ?? '';
      _selectedDeptName = data['selectedDeptName'] as String? ?? '';
      _selectedSalesmanId = data['selectedSalesmanId'] as String? ?? '';
      _selectedSalesmanName = data['selectedSalesmanName'] as String? ?? '';
      _customerController.text = data['customer'] as String? ?? '';
      _origBillNoController.text = data['origBillNo'] as String? ?? '';
      _isClosed = data['isClosed'] as bool? ?? false;
      _feedbackController.text = data['feedback'] as String? ?? '';
      _remarkController.text = data['remark'] as 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(
            OvertimeDetailData(
              empCode: m['empCode'] as String? ?? '',
              shiftType: m['shiftType'] as String? ?? '',
              startDate: m['startDate'] as String? ?? '',
              endDate: m['endDate'] as String? ?? '',
              approvedHours: (m['approvedHours'] as num?)?.toDouble() ?? 0,
              isApproved: m['isApproved'] as String? ?? 'N',
              directOt: m['directOt'] as String? ?? 'N',
              otQuantity: (m['otQuantity'] as num?)?.toDouble() ?? 0,
              reason: m['reason'] as String? ?? '',
              handleMethod: m['handleMethod'] as String? ?? '',
              chargeMethod: m['chargeMethod'] as String? ?? '',
              remark: m['remark'] as String? ?? '',
              isClosed: m['isClosed'] as String? ?? 'N',
              outBillNo: m['outBillNo'] as String? ?? '',
            ),
          );
        }
      }
    });
  }

  Future<void> _saveDraftToStorage() async {
    final detailList = _details
        .map(
          (d) => {
            'empCode': d.empCode,
            'shiftType': d.shiftType,
            'startDate': d.startDate,
            'endDate': d.endDate,
            'approvedHours': d.approvedHours,
            'isApproved': d.isApproved,
            'directOt': d.directOt,
            'otQuantity': d.otQuantity,
            'reason': d.reason,
            'handleMethod': d.handleMethod,
            'chargeMethod': d.chargeMethod,
            'remark': d.remark,
            'isClosed': d.isClosed,
            'outBillNo': d.outBillNo,
          },
        )
        .toList();
    await DraftStorage.save(_draftKey, {
      'billType': _billType,
      'selectedDeptId': _selectedDeptId,
      'selectedDeptName': _selectedDeptName,
      'selectedSalesmanId': _selectedSalesmanId,
      'selectedSalesmanName': _selectedSalesmanName,
      'customer': _customerController.text,
      'origBillNo': _origBillNoController.text,
      'isClosed': _isClosed,
      'feedback': _feedbackController.text,
      'remark': _remarkController.text,
      'details': detailList,
    });
  }

  // ═══ 草稿弹窗 ═══
  void _showDraftDialog() {
    final l10n = AppLocalizations.of(context);
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    FocusManager.instance.primaryFocus?.unfocus();
    showDialog(
      context: context,
      barrierDismissible: false,
      builder: (ctx) => TDAlertDialog(
        title: l10n.get('draftFound'),
        content: l10n.get('draftRestorePrompt'),
        leftBtn: TDDialogButtonOptions(
          title: l10n.get('discard'),
          titleColor: colors.textSecondary,
          action: () {
            Navigator.pop(ctx);
            DraftStorage.delete(_draftKey);
          },
        ),
        rightBtn: TDDialogButtonOptions(
          title: l10n.get('restore'),
          titleColor: colors.primary,
          action: () {
            Navigator.pop(ctx);
            _restoreDraft();
          },
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final l10n = AppLocalizations.of(context);

    if (_firstBuild) {
      return const SkeletonFormPage();
    }

    Future.microtask(
      () => ref.read(pageBackProvider.notifier).state = () => _doPop(),
    );

    return FutureBuilder<bool>(
      future: _draftFuture,
      builder: (ctx, snapshot) {
        final hasDraft = snapshot.hasData && snapshot.data == true;

        if (hasDraft && !_draftHandled) {
          _draftHandled = true;
          WidgetsBinding.instance.addPostFrameCallback((_) {
            if (mounted) _showDraftDialog();
          });
        }

        Future.microtask(
          () => ref.read(pageBackProvider.notifier).state = () => _doPop(),
        );
        return PopScope(
          canPop: false,
          onPopInvokedWithResult: (didPop, _) {
            if (didPop) return;
            _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: 24),
                        _buildPageFooter(),
                      ],
                    ),
                  ),
                ),
              ),
              _buildBottomBar(l10n),
            ],
          ),
        );
      },
    );
  }

  // ═══ 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('date'),
          value: _today(),
          readOnly: true,
          showArrow: false,
        ),
        const SizedBox(height: 16),
        FormFieldRow(
          label: l10n.get('applyDept'),
          value: _selectedDeptId.isNotEmpty
              ? '$_selectedDeptId/$_selectedDeptName'
              : '',
          hint: l10n.get('pleaseSelect'),
          onTap: _refDataLoading ? null : () => _showDeptPicker(),
        ),
        const SizedBox(height: 16),
        _buildBillTypeRow(l10n),
        const SizedBox(height: 16),
        FormFieldRow(
          label: '业务员',
          value: _selectedSalesmanId.isNotEmpty
              ? '$_selectedSalesmanId/$_selectedSalesmanName'
              : '',
          hint: l10n.get('pleaseSelect'),
          onTap: () => _showSalesmanPicker(),
        ),
        const SizedBox(height: 16),
        FormFieldRow(
          label: '报修客户',
          value: _customerController.text,
          hint: '请输入',
          onTap: () => _showTextInput(
            '报修客户',
            (v) => setState(() {
              _customerController.text = v;
              _customerController.selection = TextSelection.fromPosition(
                TextPosition(offset: v.length),
              );
            }),
            initialText: _customerController.text,
          ),
        ),
        const SizedBox(height: 16),
        FormFieldRow(
          label: '原加班单号',
          value: _origBillNoController.text,
          hint: '请输入',
          onTap: () => _showTextInput(
            '原加班单号',
            (v) => setState(() {
              _origBillNoController.text = v;
              _origBillNoController.selection = TextSelection.fromPosition(
                TextPosition(offset: v.length),
              );
            }),
            initialText: _origBillNoController.text,
          ),
        ),
        const SizedBox(height: 16),
        Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Text(
              '结案',
              style: TextStyle(
                fontSize: AppFontSizes.subtitle,
                color: colors.textSecondary,
              ),
            ),
            TDSwitch(
              isOn: _isClosed,
              onChanged: (v) {
                setState(() => _isClosed = v);
                return false;
              },
            ),
          ],
        ),
        const SizedBox(height: 16),
        _label(l10n.get('reminderTitle')),
        const SizedBox(height: 8),
        TDTextarea(
          controller: _feedbackController,
          hintText: '客户反馈',
          maxLines: 3,
          minLines: 1,
          maxLength: 500,
          indicator: true,
          padding: EdgeInsets.zero,
          bordered: true,
          backgroundColor: colors.bgPage,
        ),
        const SizedBox(height: 16),
        _label(l10n.get('remark')),
        const SizedBox(height: 8),
        TDTextarea(
          controller: _remarkController,
          hintText: l10n.get('enterRemark'),
          maxLines: 3,
          minLines: 1,
          maxLength: 500,
          indicator: true,
          padding: EdgeInsets.zero,
          bordered: true,
          backgroundColor: colors.bgPage,
        ),
      ],
    );
  }

  Widget _buildBillTypeRow(AppLocalizations l10n) {
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    final types = ['工作日加班', '休息日加班', '节假日加班'];
    return Row(
      children: [
        Text(
          '单据类别',
          style: TextStyle(
            fontSize: AppFontSizes.subtitle,
            color: colors.textSecondary,
          ),
        ),
        const SizedBox(width: 8),
        Expanded(
          child: Wrap(
            alignment: WrapAlignment.end,
            crossAxisAlignment: WrapCrossAlignment.center,
            spacing: 12,
            runSpacing: 8,
            children: types.map((t) {
              final sel = _billType == t;
              return GestureDetector(
                behavior: HitTestBehavior.opaque,
                onTap: () => setState(() => _billType = t),
                child: Row(
                  mainAxisSize: MainAxisSize.min,
                  children: [
                    Container(
                      width: 18,
                      height: 18,
                      decoration: BoxDecoration(
                        shape: BoxShape.circle,
                        border: Border.all(
                          color: sel ? colors.primary : colors.textPlaceholder,
                          width: 2,
                        ),
                      ),
                      child: sel
                          ? Center(
                              child: Container(
                                width: 8,
                                height: 8,
                                decoration: BoxDecoration(
                                  shape: BoxShape.circle,
                                  color: colors.primary,
                                ),
                              ),
                            )
                          : null,
                    ),
                    const SizedBox(width: 5),
                    Text(
                      t,
                      style: TextStyle(
                        fontSize: AppFontSizes.subtitle,
                        color: sel ? colors.primary : colors.textPrimary,
                      ),
                    ),
                  ],
                ),
              );
            }).toList(),
          ),
        ),
      ],
    );
  }

  // ═══ 2. 明细 ═══
  Widget _buildDetailsSection(AppLocalizations l10n) {
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    return FormSection(
      title: '加班明细',
      leadingIcon: Icons.receipt_long_outlined,
      showAction: true,
      actionText: '添加',
      onActionTap: _showDetailDialog,
      children: [
        if (_details.isEmpty)
          Padding(
            padding: const EdgeInsets.symmetric(vertical: 8),
            child: Text(
              '请添加加班明细',
              style: TextStyle(
                fontSize: AppFontSizes.subtitle,
                color: colors.textPlaceholder,
              ),
            ),
          )
        else
          ..._details.asMap().entries.map((e) {
            final d = e.value;
            return GestureDetector(
              onTap: () => _showDetailDialog(editIndex: e.key),
              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(
                                  '${d.empCode}${d.shiftType.isNotEmpty ? ' · ${d.shiftType}' : ''}',
                                  maxLines: 1,
                                  overflow: TextOverflow.ellipsis,
                                  style: TextStyle(
                                    fontSize: AppFontSizes.subtitle,
                                    color: colors.textPrimary,
                                  ),
                                ),
                              ),
                              const SizedBox(width: 12),
                              Text(
                                formatAmount(d.approvedHours),
                                style: TextStyle(
                                  fontSize: AppFontSizes.caption,
                                  fontWeight: FontWeight.w600,
                                  color: colors.amountPrimary,
                                ),
                              ),
                            ],
                          ),
                          if (d.startDate.isNotEmpty &&
                              d.endDate.isNotEmpty) ...[
                            const SizedBox(height: 4),
                            Text(
                              '${d.startDate} ~ ${d.endDate}',
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                              style: TextStyle(
                                fontSize: AppFontSizes.caption,
                                color: colors.textSecondary,
                              ),
                            ),
                          ],
                          if (d.reason.isNotEmpty) ...[
                            const SizedBox(height: 4),
                            Text(
                              d.reason,
                              maxLines: 1,
                              overflow: TextOverflow.ellipsis,
                              style: TextStyle(
                                fontSize: AppFontSizes.caption,
                                color: colors.textSecondary,
                              ),
                            ),
                          ],
                          if (d.isApproved == 'Y') ...[
                            const SizedBox(height: 4),
                            Text(
                              '已核准',
                              style: TextStyle(
                                fontSize: AppFontSizes.caption,
                                color: colors.success,
                              ),
                            ),
                          ],
                        ],
                      ),
                    ),
                    const SizedBox(width: 8),
                    GestureDetector(
                      onTap: () => setState(() => _details.removeAt(e.key)),
                      child: Icon(
                        Icons.close,
                        size: 18,
                        color: colors.textSecondary,
                      ),
                    ),
                  ],
                ),
              ),
            );
          }),
        const SizedBox(height: 8),
        Container(
          padding: const EdgeInsets.symmetric(vertical: 8),
          child: Row(
            mainAxisAlignment: MainAxisAlignment.spaceBetween,
            children: [
              Text(
                '合计',
                style: TextStyle(
                  fontSize: AppFontSizes.body,
                  fontWeight: FontWeight.w600,
                  color: colors.textPrimary,
                ),
              ),
              Text(
                formatAmount(
                  _details.fold<double>(0, (s, d) => s + d.approvedHours),
                ),
                style: TextStyle(
                  fontSize: AppFontSizes.subtitle,
                  fontWeight: FontWeight.w700,
                  color: colors.amountPrimary,
                ),
              ),
            ],
          ),
        ),
      ],
    );
  }

  Future<void> _showDetailDialog({int? editIndex}) async {
    if (_addingDetail) return;
    _addingDetail = true;
    try {
      final l10n = AppLocalizations.of(context);
      OvertimeDetailData? initialData;
      if (editIndex != null) {
        initialData = _details[editIndex];
      }
      FocusManager.instance.primaryFocus?.unfocus();
      final result = await OvertimeDetailDialog.show(
        // ignore: use_build_context_synchronously
        context,
        l10n: l10n,
        initialData: initialData,
      );
      if (result != null && mounted) {
        setState(() {
          if (editIndex != null) {
            _details[editIndex] = result;
          } else {
            _details.add(result);
          }
        });
      }
    } finally {
      _addingDetail = false;
    }
  }

  // ═══ 3. 底部操作栏 ═══
  Widget _buildBottomBar(AppLocalizations l10n) {
    return ActionBar(
      showLeft: false,
      centerLabel: l10n.get('saveDraft'),
      rightLabel: l10n.get('submit'),
      centerTextOnly: true,
      onCenterTap: () async {
        FocusScope.of(context).unfocus();
        try {
          await _saveDraftToStorage();
          if (mounted) _forcePop();
        } catch (_) {
          if (mounted) {
            TDToast.showFail(l10n.get('saveFailed'), context: context);
          }
        }
      },
      onRightTap: () async {
        FocusScope.of(context).unfocus();
        LoadingDialog.show(context, text: l10n.get('submitting'));
        try {
          final data = _buildSubmitData();
          final api = ref.read(overtimeApiProvider);
          await api.submit(data);
          await DraftStorage.delete(_draftKey);
          if (mounted) {
            LoadingDialog.hide(context);
            TDToast.showSuccess(l10n.get('submitSuccess'), context: context);
            GoRouter.of(context).go('/overtime/list');
          }
        } catch (e) {
          if (mounted) {
            LoadingDialog.hide(context);
            TDToast.showFail(l10n.get('submitFailedRetry'), context: context);
          }
        }
      },
    );
  }

  Map<String, dynamic> _buildSubmitData() {
    return {
      'HeadData': {
        'BILL_TYPE': _billType,
        'DEP': _selectedDeptId,
        'SALESMAN': _selectedSalesmanId,
        'CUSTOMER': _customerController.text,
        'ORIG_BILL_NO': _origBillNoController.text,
        'IS_CLOSED': _isClosed ? 1 : 0,
        'FEEDBACK': _feedbackController.text,
        'REMARK': _remarkController.text,
        'USR': HostAppChannel.usr,
      },
      'BodyData1': _details.asMap().entries.map((e) {
        final d = e.value;
        return {
          'SEQ_NO': e.key + 1,
          'EMP_CODE': d.empCode,
          'SHIFT_TYPE': d.shiftType,
          'START_DATE': d.startDate,
          'END_DATE': d.endDate,
          'APPROVED_HOURS': d.approvedHours,
          'IS_APPROVED': d.isApproved,
          'DIRECT_OT': d.directOt,
          'OT_QUANTITY': d.otQuantity,
          'REASON': d.reason,
          'HANDLE_METHOD': d.handleMethod,
          'CHARGE_METHOD': d.chargeMethod,
          'REMARK': d.remark,
          'IS_CLOSED': d.isClosed,
          'OUT_BILL_NO': d.outBillNo,
        };
      }).toList(),
    };
  }

  void _doPop() {
    if (_hasUnsaved()) {
      final l10n = AppLocalizations.of(context);
      _showConfirmDialog(
        l10n.get('confirmExit'),
        l10n.get('unsavedContentWarning'),
        l10n.get('continueEditing'),
        l10n.get('discardAndExit'),
        () async {
          await DraftStorage.delete(_draftKey);
          if (!mounted) return;
          setState(() => _clearLocalState());
          _forcePop();
        },
      );
    } else {
      _forcePop();
    }
  }

  void _forcePop() {
    FocusManager.instance.primaryFocus?.unfocus();
    final router = GoRouter.of(context);
    if (router.canPop()) {
      router.pop();
    } else {
      SystemNavigator.pop();
    }
  }

  bool _hasUnsaved() =>
      _customerController.text.isNotEmpty ||
      _origBillNoController.text.isNotEmpty ||
      _feedbackController.text.isNotEmpty ||
      _remarkController.text.isNotEmpty ||
      _details.isNotEmpty ||
      _billType != '工作日加班' ||
      _selectedDeptId.isNotEmpty ||
      _selectedSalesmanId.isNotEmpty ||
      _isClosed;

  void _clearLocalState() {
    _billType = '工作日加班';
    _selectedDeptId = '';
    _selectedDeptName = '';
    _selectedSalesmanId = '';
    _selectedSalesmanName = '';
    _customerController.clear();
    _origBillNoController.clear();
    _isClosed = false;
    _feedbackController.clear();
    _remarkController.clear();
    _details.clear();
  }

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

  void _showConfirmDialog(
    String title,
    String content,
    String leftText,
    String rightText,
    VoidCallback onConfirm,
  ) {
    _unfocus();
    FocusManager.instance.primaryFocus?.unfocus();
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    showDialog(
      context: context,
      useRootNavigator: true,
      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();
          },
        ),
      ),
    );
  }

  // ═══ Picker 方法 ═══

  Future<void> _showDeptPicker() async {
    FocusManager.instance.primaryFocus?.unfocus();
    final l10n = AppLocalizations.of(context);
    final api = ref.read(overtimeApiProvider);
    final result = await showSearchablePicker<DepartmentItem>(
      context,
      title: '${l10n.get('select')}${l10n.get('applyDept')}',
      searchHint: l10n.get('search'),
      loader: (keyword, page) =>
          api.getDepartments(keyword: keyword, page: page, size: 20),
      labelBuilder: (d) => d.name.isEmpty ? d.dep : '${d.dep} ${d.name}',
      onRefresh: () => api.clearRefCache(),
    );
    if (result != null && mounted) {
      setState(() {
        _selectedDeptId = result.dep;
        _selectedDeptName = result.name;
      });
    }
  }

  Future<void> _showSalesmanPicker() async {
    FocusManager.instance.primaryFocus?.unfocus();
    final l10n = AppLocalizations.of(context);
    final api = ref.read(overtimeApiProvider);
    final result = await showSearchablePicker<EmployeeItem>(
      context,
      title: '${l10n.get('select')}业务员',
      searchHint: l10n.get('search'),
      loader: (keyword, page) =>
          api.getEmployees(keyword: keyword, page: page, size: 20),
      labelBuilder: (e) => e.name.isEmpty ? e.salNo : '${e.salNo} ${e.name}',
      onRefresh: () => api.clearRefCache(),
    );
    if (result != null && mounted) {
      setState(() {
        _selectedSalesmanId = result.salNo;
        _selectedSalesmanName = result.name;
      });
    }
  }

  void _showTextInput(
    String title,
    Function(String) onConfirm, {
    String initialText = '',
  }) {
    final l10n = AppLocalizations.of(context);
    _unfocus();
    FocusManager.instance.primaryFocus?.unfocus();
    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);
          },
        ),
      ),
    );
  }

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

  Widget _buildPageFooter() {
    final l10n = AppLocalizations.of(context);
    final colors = Theme.of(context).extension<AppColorsExtension>()!;
    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,
              ),
            ),
          ],
        ),
      ),
    );
  }

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