import 'package:flutter/material.dart';
import 'package:intl/intl.dart';
import 'package:open_filex/open_filex.dart';
import 'package:url_launcher/url_launcher.dart';
import '../models/customer_model.dart';
import '../models/hash_chain_models.dart';
import '../models/inventory_models.dart';
import '../models/order_models.dart';
import '../models/receivable_models.dart';
import '../models/shipment_models.dart';
import '../services/inventory_service.dart';
import '../services/order_service.dart';
import '../services/receivable_service.dart';
import '../services/shipment_service.dart';
import '../services/shipping_label_service.dart';
import '../widgets/keyboard_inset_wrapper.dart';
import '../widgets/modal_utils.dart';
import '../widgets/screen_id_title.dart';
import 'customer_picker_modal.dart';

class SalesOrdersScreen extends StatefulWidget {
  const SalesOrdersScreen({super.key});

  @override
  State<SalesOrdersScreen> createState() => _SalesOrdersScreenState();
}

class _HashChainVerificationDialog extends StatelessWidget {
  const _HashChainVerificationDialog({required this.result});

  final HashChainVerificationResult result;

  @override
  Widget build(BuildContext context) {
    final isHealthy = result.isHealthy;
    final title = isHealthy ? 'HASHチェーンは正常です' : 'HASHチェーンの破断を検出しました';
    return AlertDialog(
      title: Text(title),
      content: SizedBox(
        width: double.maxFinite,
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Text('検証日時: ${DateFormat('yyyy/MM/dd HH:mm').format(result.verifiedAt)}'),
            Text('検証件数: ${result.checkedCount} 件'),
            Text('破断件数: ${result.breaks.length} 件'),
            const SizedBox(height: 12),
            if (result.breaks.isNotEmpty)
              Expanded(
                child: ListView.builder(
                  shrinkWrap: true,
                  itemCount: result.breaks.length,
                  itemBuilder: (ctx, index) {
                    final item = result.breaks[index];
                    return ListTile(
                      contentPadding: EdgeInsets.zero,
                      title: Text(item.invoiceNumber ?? item.invoiceId),
                      subtitle: Text('${item.issue}\nexpected: ${item.expectedHash ?? '-'}\nactual: ${item.actualHash ?? '-'}'),
                    );
                  },
                ),
              )
            else
              const Text('全てのハッシュが整合しています。'),
          ],
        ),
      ),
      actions: [
        TextButton(onPressed: () => Navigator.of(context).pop(), child: const Text('閉じる')),
      ],
    );
  }
}

class ShipmentEditorPage extends StatefulWidget {
  const ShipmentEditorPage({super.key, required this.service, this.shipment});

  final ShipmentService service;
  final Shipment? shipment;

  @override
  State<ShipmentEditorPage> createState() => _ShipmentEditorPageState();
}

class _ShipmentEditorPageState extends State<ShipmentEditorPage> {
  final TextEditingController _orderIdController = TextEditingController();
  final TextEditingController _orderNumberController = TextEditingController();
  final TextEditingController _customerNameController = TextEditingController();
  final TextEditingController _carrierController = TextEditingController();
  final TextEditingController _trackingController = TextEditingController();
  final TextEditingController _trackingUrlController = TextEditingController();
  final TextEditingController _notesController = TextEditingController();
  final DateFormat _dateFormat = DateFormat('yyyy/MM/dd');

  DateTime? _scheduledDate;
  DateTime? _actualDate;
  bool _isSaving = false;
  final List<_ShipmentLineFormData> _lines = [];

  @override
  void initState() {
    super.initState();
    final shipment = widget.shipment;
    if (shipment != null) {
      _orderIdController.text = shipment.orderId ?? '';
      _orderNumberController.text = shipment.orderNumberSnapshot ?? '';
      _customerNameController.text = shipment.customerNameSnapshot ?? '';
      _carrierController.text = shipment.carrierName ?? '';
      _trackingController.text = shipment.trackingNumber ?? '';
      _trackingUrlController.text = shipment.trackingUrl ?? '';
      _notesController.text = shipment.notes ?? '';
      _scheduledDate = shipment.scheduledShipDate;
      _actualDate = shipment.actualShipDate;
      for (final item in shipment.items) {
        _lines.add(_ShipmentLineFormData(description: item.description, quantity: item.quantity));
      }
    }
    if (_lines.isEmpty) {
      _lines.add(_ShipmentLineFormData());
    }
  }

  @override
  void dispose() {
    _orderIdController.dispose();
    _orderNumberController.dispose();
    _customerNameController.dispose();
    _carrierController.dispose();
    _trackingController.dispose();
    _trackingUrlController.dispose();
    _notesController.dispose();
    for (final line in _lines) {
      line.dispose();
    }
    super.dispose();
  }

  Future<void> _pickScheduledDate() async {
    final now = DateTime.now();
    final picked = await showDatePicker(
      context: context,
      initialDate: _scheduledDate ?? now,
      firstDate: DateTime(now.year - 1),
      lastDate: DateTime(now.year + 2),
    );
    if (picked != null) {
      setState(() => _scheduledDate = picked);
    }
  }

  Future<void> _pickActualDate() async {
    final now = DateTime.now();
    final picked = await showDatePicker(
      context: context,
      initialDate: _actualDate ?? now,
      firstDate: DateTime(now.year - 1),
      lastDate: DateTime(now.year + 2),
    );
    if (picked != null) {
      setState(() => _actualDate = picked);
    }
  }

  void _addLine() {
    setState(() {
      _lines.add(_ShipmentLineFormData());
    });
  }

  void _removeLine(int index) {
    if (_lines.length == 1) return;
    setState(() {
      final line = _lines.removeAt(index);
      line.dispose();
    });
  }

  Future<void> _save() async {
    final orderId = _orderIdController.text.trim().isEmpty ? null : _orderIdController.text.trim();
    final orderNumber = _orderNumberController.text.trim().isEmpty ? null : _orderNumberController.text.trim();
    final customerName = _customerNameController.text.trim().isEmpty ? null : _customerNameController.text.trim();

    final inputs = <ShipmentLineInput>[];
    for (final line in _lines) {
      final desc = line.descriptionController.text.trim();
      final qty = int.tryParse(line.quantityController.text) ?? 0;
      if (desc.isEmpty || qty <= 0) continue;
      inputs.add(ShipmentLineInput(description: desc, quantity: qty));
    }
    if (inputs.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('出荷明細を1件以上入力してください')));
      return;
    }

    setState(() => _isSaving = true);
    try {
      Shipment saved;
      if (widget.shipment == null) {
        saved = await widget.service.createShipment(
          orderId: orderId,
          orderNumberSnapshot: orderNumber,
          customerNameSnapshot: customerName,
          lines: inputs,
          scheduledShipDate: _scheduledDate,
          actualShipDate: _actualDate,
          carrierName: _carrierController.text.trim().isEmpty ? null : _carrierController.text.trim(),
          trackingNumber: _trackingController.text.trim().isEmpty ? null : _trackingController.text.trim(),
          trackingUrl: _trackingUrlController.text.trim().isEmpty ? null : _trackingUrlController.text.trim(),
          notes: _notesController.text.trim().isEmpty ? null : _notesController.text.trim(),
        );
      } else {
        saved = await widget.service.updateShipment(
          widget.shipment!,
          replacedLines: inputs,
          scheduledShipDate: _scheduledDate,
          actualShipDate: _actualDate,
          carrierName: _carrierController.text.trim().isEmpty ? null : _carrierController.text.trim(),
          trackingNumber: _trackingController.text.trim().isEmpty ? null : _trackingController.text.trim(),
          trackingUrl: _trackingUrlController.text.trim().isEmpty ? null : _trackingUrlController.text.trim(),
          notes: _notesController.text.trim().isEmpty ? null : _notesController.text.trim(),
        );
      }
      if (!mounted) return;
      Navigator.pop(context, saved);
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('保存に失敗しました: $e')));
      setState(() => _isSaving = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    final isCreating = widget.shipment == null;
    final appBarTitle = isCreating ? '出荷指示作成' : '出荷情報編集';

    final mediaQuery = MediaQuery.of(context);
    final bottomInset = mediaQuery.viewInsets.bottom;

    return Scaffold(
      resizeToAvoidBottomInset: false,
      appBar: AppBar(
        leading: const BackButton(),
        title: ScreenAppBarTitle(screenId: 'S2', title: appBarTitle),
        actions: [
          TextButton(
            onPressed: _isSaving ? null : _save,
            child: _isSaving
                ? const SizedBox(width: 18, height: 18, child: CircularProgressIndicator(strokeWidth: 2))
                : const Text('保存'),
          ),
        ],
      ),
      body: MediaQuery(
        data: mediaQuery.removeViewInsets(removeBottom: true),
        child: SafeArea(
          top: false,
          child: GestureDetector(
            behavior: HitTestBehavior.opaque,
            onTap: () => FocusScope.of(context).unfocus(),
            child: SingleChildScrollView(
              keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
              padding: EdgeInsets.fromLTRB(20, 20, 20, 20 + 32 + bottomInset),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  TextField(
                    controller: _orderIdController,
                    decoration: const InputDecoration(labelText: '受注ID (任意)', border: OutlineInputBorder()),
                  ),
                  const SizedBox(height: 12),
                  TextField(
                    controller: _orderNumberController,
                    decoration: const InputDecoration(labelText: '受注番号スナップショット', border: OutlineInputBorder()),
                  ),
                  const SizedBox(height: 12),
                  TextField(
                    controller: _customerNameController,
                    decoration: const InputDecoration(labelText: '顧客名スナップショット', border: OutlineInputBorder()),
                  ),
                  const SizedBox(height: 12),
                  Row(
                    children: [
                      Expanded(
                        child: ListTile(
                          contentPadding: EdgeInsets.zero,
                          title: const Text('予定出荷日'),
                          subtitle: Text(_scheduledDate != null ? _dateFormat.format(_scheduledDate!) : '未設定'),
                          trailing: IconButton(
                            icon: const Icon(Icons.calendar_today),
                            onPressed: _pickScheduledDate,
                          ),
                        ),
                      ),
                      Expanded(
                        child: ListTile(
                          contentPadding: EdgeInsets.zero,
                          title: const Text('実績出荷日'),
                          subtitle: Text(_actualDate != null ? _dateFormat.format(_actualDate!) : '未設定'),
                          trailing: IconButton(
                            icon: const Icon(Icons.calendar_month),
                            onPressed: _pickActualDate,
                          ),
                        ),
                      ),
                    ],
                  ),
                  const SizedBox(height: 12),
                  TextField(
                    controller: _carrierController,
                    decoration: const InputDecoration(labelText: '配送業者', border: OutlineInputBorder()),
                  ),
                  const SizedBox(height: 12),
                  TextField(
                    controller: _trackingController,
                    decoration: const InputDecoration(labelText: '追跡番号', border: OutlineInputBorder()),
                  ),
                  const SizedBox(height: 12),
                  TextField(
                    controller: _trackingUrlController,
                    decoration: const InputDecoration(labelText: '追跡URL', border: OutlineInputBorder()),
                  ),
                  const SizedBox(height: 12),
                  TextField(
                    controller: _notesController,
                    maxLines: 3,
                    decoration: const InputDecoration(labelText: 'メモ', border: OutlineInputBorder()),
                  ),
                  const SizedBox(height: 24),
                  const Text('出荷明細', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
                  const SizedBox(height: 12),
                  for (int i = 0; i < _lines.length; i++) _buildLineCard(i),
                  const SizedBox(height: 12),
                  OutlinedButton.icon(
                    onPressed: _addLine,
                    icon: const Icon(Icons.add),
                    label: const Text('明細を追加'),
                  ),
                  const SizedBox(height: 32),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildLineCard(int index) {
    final line = _lines[index];
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text('明細 ${index + 1}', style: const TextStyle(fontWeight: FontWeight.bold)),
                if (_lines.length > 1)
                  IconButton(
                    icon: const Icon(Icons.delete_outline),
                    onPressed: () => _removeLine(index),
                  ),
              ],
            ),
            TextField(
              controller: line.descriptionController,
              decoration: const InputDecoration(labelText: '内容', border: OutlineInputBorder()),
            ),
            const SizedBox(height: 12),
            TextField(
              controller: line.quantityController,
              keyboardType: TextInputType.number,
              decoration: const InputDecoration(labelText: '数量', border: OutlineInputBorder()),
            ),
          ],
        ),
      ),
    );
  }
}

class _ShipmentLineFormData {
  _ShipmentLineFormData({String description = '', int quantity = 1})
      : descriptionController = TextEditingController(text: description),
        quantityController = TextEditingController(text: quantity.toString());

  final TextEditingController descriptionController;
  final TextEditingController quantityController;

  void dispose() {
    descriptionController.dispose();
    quantityController.dispose();
  }
}

class _ShipmentDetailSheet extends StatefulWidget {
  const _ShipmentDetailSheet({required this.shipment, required this.service, required this.onEdit});

  final Shipment shipment;
  final ShipmentService service;
  final void Function(Shipment shipment) onEdit;

  @override
  State<_ShipmentDetailSheet> createState() => _ShipmentDetailSheetState();
}

class _ShipmentDetailSheetState extends State<_ShipmentDetailSheet> {
  late Shipment _shipment;
  bool _isProcessing = false;
  bool _isGeneratingLabel = false;
  final DateFormat _dateFormat = DateFormat('yyyy/MM/dd');
  final ShippingLabelService _labelService = ShippingLabelService();

  @override
  void initState() {
    super.initState();
    _shipment = widget.shipment;
  }

  Future<void> _advance() async {
    if (_isProcessing) return;
    setState(() => _isProcessing = true);
    try {
      final updated = await widget.service.advanceStatus(_shipment.id);
      if (!mounted) return;
      setState(() => _shipment = updated);
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('ステータス更新に失敗しました: $e')));
    } finally {
      if (mounted) setState(() => _isProcessing = false);
    }
  }

  Future<void> _transitionTo(ShipmentStatus status) async {
    if (_isProcessing) return;
    setState(() => _isProcessing = true);
    try {
      final updated = await widget.service.transitionStatus(_shipment.id, status, force: true);
      if (!mounted) return;
      setState(() => _shipment = updated);
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('更新に失敗しました: $e')));
    } finally {
      if (mounted) setState(() => _isProcessing = false);
    }
  }

  Future<void> _generateLabel() async {
    if (_isGeneratingLabel) return;
    setState(() => _isGeneratingLabel = true);
    try {
      final path = await _labelService.generateLabel(_shipment);
      if (path == null) {
        if (!mounted) return;
        ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('送り状PDFの生成に失敗しました')));
        return;
      }
      final updated = await widget.service.updateShipment(_shipment, labelPdfPath: path);
      if (!mounted) return;
      setState(() => _shipment = updated);
      await OpenFilex.open(path);
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('送り状PDF生成エラー: $e')));
    } finally {
      if (mounted) setState(() => _isGeneratingLabel = false);
    }
  }

  Future<void> _openLabel() async {
    final path = _shipment.labelPdfPath;
    if (path == null || path.isEmpty) {
      await _generateLabel();
      return;
    }
    await OpenFilex.open(path);
  }

  Future<void> _openTracking() async {
    final url = _shipment.trackingUrl;
    if (url == null || url.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('追跡URLが未設定です')));
      return;
    }
    final uri = Uri.parse(url);
    if (!await canLaunchUrl(uri)) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('追跡URLを開けませんでした')));
      return;
    }
    await launchUrl(uri, mode: LaunchMode.externalApplication);
  }

  String _formatDate(DateTime date) => _dateFormat.format(date);

  Color _statusColor(ShipmentStatus status) {
    switch (status) {
      case ShipmentStatus.pending:
        return Colors.grey.shade500;
      case ShipmentStatus.picking:
        return Colors.orange;
      case ShipmentStatus.ready:
        return Colors.teal;
      case ShipmentStatus.shipped:
        return Colors.blue;
      case ShipmentStatus.delivered:
        return Colors.green;
      case ShipmentStatus.cancelled:
        return Colors.redAccent;
    }
  }

  @override
  Widget build(BuildContext context) {
    final nextStatuses = widget.service.nextStatuses(_shipment.status);
    return DraggableScrollableSheet(
      initialChildSize: 0.85,
      minChildSize: 0.6,
      maxChildSize: 0.95,
      builder: (ctx, controller) {
        return Material(
          borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
          clipBehavior: Clip.antiAlias,
          child: Column(
            children: [
              Container(
                width: 48,
                height: 4,
                margin: const EdgeInsets.only(top: 12, bottom: 8),
                decoration: BoxDecoration(color: Colors.grey.shade300, borderRadius: BorderRadius.circular(999)),
              ),
              ListTile(
                title: Text('出荷指示 ${_shipment.id.substring(0, 6)}', style: const TextStyle(fontWeight: FontWeight.bold)),
                subtitle: Text('${_shipment.customerNameSnapshot ?? '取引先未設定'}\n受注番号: ${_shipment.orderNumberSnapshot ?? '-'}'),
                trailing: IconButton(
                  icon: const Icon(Icons.edit),
                  onPressed: () => widget.onEdit(_shipment),
                ),
              ),
              Expanded(
                child: ListView(
                  controller: controller,
                  padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
                  children: [
                    Wrap(
                      spacing: 8,
                      runSpacing: 8,
                      children: ShipmentStatus.values
                          .map(
                            (status) => Chip(
                              label: Text(status.displayName),
                              backgroundColor: status == _shipment.status ? _statusColor(status) : Colors.grey.shade200,
                              labelStyle: TextStyle(
                                color: status == _shipment.status ? Colors.white : Colors.black87,
                                fontWeight: status == _shipment.status ? FontWeight.bold : FontWeight.normal,
                              ),
                            ),
                          )
                          .toList(),
                    ),
                    const SizedBox(height: 16),
                    _InfoRow(label: '予定出荷日', value: _shipment.scheduledShipDate != null ? _formatDate(_shipment.scheduledShipDate!) : '-'),
                    _InfoRow(label: '出荷日', value: _shipment.actualShipDate != null ? _formatDate(_shipment.actualShipDate!) : '-'),
                    if (_shipment.carrierName?.isNotEmpty == true) _InfoRow(label: '配送業者', value: _shipment.carrierName!),
                    if (_shipment.trackingNumber?.isNotEmpty == true) _InfoRow(label: '追跡番号', value: _shipment.trackingNumber!),
                    if (_shipment.trackingUrl?.isNotEmpty == true)
                      TextButton.icon(
                        onPressed: _openTracking,
                        icon: const Icon(Icons.link),
                        label: const Text('追跡サイトを開く'),
                      ),
                    if (_shipment.notes?.isNotEmpty == true)
                      Card(
                        margin: const EdgeInsets.only(top: 12),
                        child: Padding(
                          padding: const EdgeInsets.all(12),
                          child: Text(_shipment.notes!),
                        ),
                      ),
                    const SizedBox(height: 16),
                    const Text('出荷明細', style: TextStyle(fontWeight: FontWeight.bold)),
                    const SizedBox(height: 8),
                    ..._shipment.items.map(
                      (item) => ListTile(
                        dense: true,
                        title: Text(item.description),
                        trailing: Text('数量 ${item.quantity}'),
                      ),
                    ),
                    const SizedBox(height: 24),
                    FilledButton.icon(
                      onPressed: _isGeneratingLabel ? null : _openLabel,
                      icon: const Icon(Icons.picture_as_pdf),
                      label: Text(_shipment.labelPdfPath == null ? '送り状PDFを生成' : '送り状PDFを開く'),
                    ),
                    const SizedBox(height: 24),
                    FilledButton.icon(
                      onPressed: nextStatuses.isEmpty || _isProcessing ? null : _advance,
                      icon: const Icon(Icons.local_shipping),
                      label: Text(nextStatuses.isEmpty ? '完了済み' : '${nextStatuses.first.displayName} へ進める'),
                    ),
                    const SizedBox(height: 8),
                    TextButton(
                      onPressed: _shipment.status == ShipmentStatus.cancelled || _isProcessing
                          ? null
                          : () => _transitionTo(ShipmentStatus.cancelled),
                      child: const Text('キャンセルに変更'),
                    ),
                  ],
                ),
              ),
            ],
          ),
        );
      },
    );
  }
}

class _SalesOrdersScreenState extends State<SalesOrdersScreen> {
  final SalesOrderService _service = SalesOrderService();
  final DateFormat _dateFormat = DateFormat('yyyy/MM/dd');
  final NumberFormat _currencyFormat = NumberFormat.currency(locale: 'ja_JP', symbol: '¥');

  bool _isLoading = false;
  List<SalesOrder> _orders = [];

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

  Future<void> _loadOrders() async {
    setState(() => _isLoading = true);
    final orders = await _service.fetchOrders();
    if (!mounted) return;
    setState(() {
      _orders = orders;
      _isLoading = false;
    });
  }

  Future<void> _openOrderEditor({SalesOrder? order}) async {
    final result = await Navigator.of(context).push<SalesOrder?>(
      MaterialPageRoute(
        fullscreenDialog: true,
        builder: (_) => SalesOrderEditorPage(service: _service, order: order),
      ),
    );
    if (result != null) {
      await _loadOrders();
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(order == null ? '受注を登録しました' : '受注を更新しました')),
      );
    }
  }

  Future<void> _openOrderDetails(SalesOrder order) async {
    await showModalBottomSheet<void>(
      context: context,
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      builder: (ctx) => _OrderDetailSheet(
        order: order,
        service: _service,
        onEdit: (current) {
          Navigator.of(ctx).pop();
          _openOrderEditor(order: current);
        },
      ),
    );
    if (mounted) {
      await _loadOrders();
    }
  }

  String _formatDate(DateTime date) => _dateFormat.format(date);

  String _formatCurrency(int amount) => _currencyFormat.format(amount);

  Color _statusColor(SalesOrderStatus status) {
    switch (status) {
      case SalesOrderStatus.draft:
        return Colors.grey.shade500;
      case SalesOrderStatus.confirmed:
        return Colors.indigo;
      case SalesOrderStatus.picking:
        return Colors.orange;
      case SalesOrderStatus.shipped:
        return Colors.blue;
      case SalesOrderStatus.closed:
        return Colors.green;
      case SalesOrderStatus.cancelled:
        return Colors.redAccent;
    }
  }

  Widget _buildOrderTile(SalesOrder order) {
    final subtitle = StringBuffer()
      ..write(_formatDate(order.orderDate))
      ..write(' ・ ')
      ..write(order.orderNumber ?? order.id.substring(0, 6));
    if (order.requestedShipDate != null) {
      subtitle.writeln('\n希望出荷日: ${_formatDate(order.requestedShipDate!)}');
    }
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      child: ListTile(
        onTap: () => _openOrderDetails(order),
        title: Text(order.customerNameSnapshot ?? '取引先未設定', style: const TextStyle(fontWeight: FontWeight.bold)),
        subtitle: Text(subtitle.toString()),
        trailing: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.end,
          children: [
            Chip(
              label: Text(order.status.displayName, style: const TextStyle(color: Colors.white)),
              backgroundColor: _statusColor(order.status),
              visualDensity: VisualDensity.compact,
              materialTapTargetSize: MaterialTapTargetSize.shrinkWrap,
            ),
            const SizedBox(height: 8),
            Text(
              _formatCurrency(order.totalAmount),
              style: const TextStyle(fontWeight: FontWeight.bold),
            ),
          ],
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    Widget body;
    if (_isLoading) {
      body = const Center(child: CircularProgressIndicator());
    } else if (_orders.isEmpty) {
      body = _EmptyState(onCreate: () => _openOrderEditor());
    } else {
      body = RefreshIndicator(
        onRefresh: _loadOrders,
        child: ListView.builder(
          padding: const EdgeInsets.only(top: 8, bottom: 88),
          itemCount: _orders.length,
          itemBuilder: (context, index) => _buildOrderTile(_orders[index]),
        ),
      );
    }

    return Scaffold(
      appBar: AppBar(
        leading: const BackButton(),
        title: const Text('S1:受注管理'),
        actions: [
          IconButton(
            tooltip: '最新の状態に更新',
            onPressed: _isLoading ? null : _loadOrders,
            icon: const Icon(Icons.refresh),
          ),
        ],
      ),
      body: body,
      floatingActionButton: FloatingActionButton.extended(
        onPressed: () => _openOrderEditor(),
        icon: const Icon(Icons.add),
        label: const Text('受注を登録'),
      ),
    );
  }
}

class _EmptyState extends StatelessWidget {
  const _EmptyState({required this.onCreate});

  final VoidCallback onCreate;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Padding(
        padding: const EdgeInsets.all(32),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.assignment_add, size: 64, color: Colors.grey),
            const SizedBox(height: 16),
            const Text('受注がまだ登録されていません', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            const SizedBox(height: 8),
            const Text('プラスボタンから受注を登録し、進捗を管理できます。', textAlign: TextAlign.center),
            const SizedBox(height: 24),
            ElevatedButton.icon(
              onPressed: onCreate,
              icon: const Icon(Icons.add),
              label: const Text('受注を登録'),
            ),
          ],
        ),
      ),
    );
  }
}

class SalesShipmentsScreen extends StatefulWidget {
  const SalesShipmentsScreen({super.key});

  @override
  State<SalesShipmentsScreen> createState() => _SalesShipmentsScreenState();
}

class _SalesShipmentsScreenState extends State<SalesShipmentsScreen> {
  final ShipmentService _service = ShipmentService();
  final DateFormat _dateFormat = DateFormat('yyyy/MM/dd');

  bool _isLoading = false;
  List<Shipment> _shipments = [];

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

  Future<void> _loadShipments() async {
    setState(() => _isLoading = true);
    final shipments = await _service.fetchShipments();
    if (!mounted) return;
    setState(() {
      _shipments = shipments;
      _isLoading = false;
    });
  }

  Future<void> _openShipmentEditor({Shipment? shipment}) async {
    final result = await Navigator.of(context).push<Shipment?>(
      MaterialPageRoute(
        fullscreenDialog: true,
        builder: (_) => ShipmentEditorPage(service: _service, shipment: shipment),
      ),
    );
    if (result != null) {
      await _loadShipments();
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(content: Text(shipment == null ? '出荷指示を登録しました' : '出荷情報を更新しました')),
      );
    }
  }

  Future<void> _openShipmentDetails(Shipment shipment) async {
    await showModalBottomSheet<void>(
      context: context,
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      builder: (ctx) => _ShipmentDetailSheet(
        shipment: shipment,
        service: _service,
        onEdit: (current) {
          Navigator.of(ctx).pop();
          _openShipmentEditor(shipment: current);
        },
      ),
    );
    if (mounted) {
      await _loadShipments();
    }
  }

  Color _statusColor(ShipmentStatus status) {
    switch (status) {
      case ShipmentStatus.pending:
        return Colors.grey.shade500;
      case ShipmentStatus.picking:
        return Colors.orange;
      case ShipmentStatus.ready:
        return Colors.teal;
      case ShipmentStatus.shipped:
        return Colors.blue;
      case ShipmentStatus.delivered:
        return Colors.green;
      case ShipmentStatus.cancelled:
        return Colors.redAccent;
    }
  }

  Widget _buildShipmentTile(Shipment shipment) {
    final subtitle = StringBuffer()
      ..write(shipment.orderNumberSnapshot ?? '未連携')
      ..write(' ・ ')
      ..write(shipment.customerNameSnapshot ?? '取引先未設定');
    if (shipment.scheduledShipDate != null) {
      subtitle.write('\n予定日: ${_dateFormat.format(shipment.scheduledShipDate!)}');
    }
    if (shipment.actualShipDate != null) {
      subtitle.write('\n出荷日: ${_dateFormat.format(shipment.actualShipDate!)}');
    }
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      child: ListTile(
        onTap: () => _openShipmentDetails(shipment),
        title: Text('出荷指示 ${shipment.id.substring(0, 6)}', style: const TextStyle(fontWeight: FontWeight.bold)),
        subtitle: Text(subtitle.toString()),
        trailing: Chip(
          label: Text(shipment.status.displayName, style: const TextStyle(color: Colors.white)),
          backgroundColor: _statusColor(shipment.status),
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    Widget body;
    if (_isLoading) {
      body = const Center(child: CircularProgressIndicator());
    } else if (_shipments.isEmpty) {
      body = _EmptyState(onCreate: () => _openShipmentEditor());
    } else {
      body = RefreshIndicator(
        onRefresh: _loadShipments,
        child: ListView.builder(
          padding: const EdgeInsets.only(top: 8, bottom: 88),
          itemCount: _shipments.length,
          itemBuilder: (context, index) => _buildShipmentTile(_shipments[index]),
        ),
      );
    }

    return Scaffold(
      appBar: AppBar(
        leading: const BackButton(),
        title: const Text('S3:出荷管理'),
        actions: [
          IconButton(
            tooltip: '更新',
            onPressed: _isLoading ? null : _loadShipments,
            icon: const Icon(Icons.refresh),
          ),
        ],
      ),
      body: body,
      floatingActionButton: FloatingActionButton.extended(
        onPressed: () => _openShipmentEditor(),
        icon: const Icon(Icons.local_shipping),
        label: const Text('出荷指示'),
      ),
    );
  }
}

class SalesInventoryScreen extends StatefulWidget {
  const SalesInventoryScreen({super.key});

  @override
  State<SalesInventoryScreen> createState() => _SalesInventoryScreenState();
}

class _SalesInventoryScreenState extends State<SalesInventoryScreen> {
  final InventoryService _service = InventoryService();
  final DateFormat _dateFormat = DateFormat('yyyy/MM/dd HH:mm');

  bool _isLoading = false;
  List<InventorySummary> _summaries = [];

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

  Future<void> _loadSummaries() async {
    setState(() => _isLoading = true);
    final data = await _service.fetchSummaries();
    if (!mounted) return;
    setState(() {
      _summaries = data;
      _isLoading = false;
    });
  }

  Future<void> _openDetail(InventorySummary summary) async {
    await showModalBottomSheet<void>(
      context: context,
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      builder: (ctx) => _InventoryDetailSheet(
        summary: summary,
        service: _service,
        onUpdated: () {
          Navigator.of(ctx).pop();
          _loadSummaries();
        },
      ),
    );
  }

  Widget _buildTile(InventorySummary summary) {
    final subtitle = <String>[];
    if (summary.category?.isNotEmpty == true) {
      subtitle.add('カテゴリ: ${summary.category}');
    }
    if (summary.lastMovementAt != null) {
      subtitle.add('最終更新: ${_dateFormat.format(summary.lastMovementAt!)}');
    }
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      child: ListTile(
        onTap: () => _openDetail(summary),
        leading: const Icon(Icons.inventory_2_outlined),
        title: Text(summary.productName, style: const TextStyle(fontWeight: FontWeight.bold)),
        subtitle: subtitle.isEmpty ? null : Text(subtitle.join('\n')),
        trailing: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.end,
          children: [
            const Text('在庫', style: TextStyle(fontSize: 12, color: Colors.grey)),
            Text('${summary.stockQuantity}', style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
          ],
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    Widget body;
    if (_isLoading) {
      body = const Center(child: CircularProgressIndicator());
    } else if (_summaries.isEmpty) {
      body = _InventoryEmptyState(onNavigateToProducts: () => Navigator.of(context).pop());
    } else {
      body = RefreshIndicator(
        onRefresh: _loadSummaries,
        child: ListView.builder(
          padding: const EdgeInsets.only(top: 8, bottom: 88),
          itemCount: _summaries.length,
          itemBuilder: (context, index) => _buildTile(_summaries[index]),
        ),
      );
    }

    return Scaffold(
      appBar: AppBar(
        leading: const BackButton(),
        title: const ScreenAppBarTitle(screenId: 'S4', title: '在庫管理'),
        actions: [
          IconButton(
            tooltip: '更新',
            onPressed: _isLoading ? null : _loadSummaries,
            icon: const Icon(Icons.refresh),
          ),
        ],
      ),
      body: body,
    );
  }
}

class _InventoryEmptyState extends StatelessWidget {
  const _InventoryEmptyState({required this.onNavigateToProducts});

  final VoidCallback onNavigateToProducts;

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Padding(
        padding: const EdgeInsets.all(32),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: [
            const Icon(Icons.inventory_2, size: 64, color: Colors.grey),
            const SizedBox(height: 16),
            const Text('商品マスターに在庫対象がありません', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            const SizedBox(height: 8),
            const Text('商品マスターで商品を登録すると在庫が表示されます。', textAlign: TextAlign.center),
            const SizedBox(height: 24),
            OutlinedButton.icon(
              onPressed: onNavigateToProducts,
              icon: const Icon(Icons.open_in_new),
              label: const Text('商品マスターへ移動'),
            ),
          ],
        ),
      ),
    );
  }
}

class _InventoryDetailSheet extends StatefulWidget {
  const _InventoryDetailSheet({required this.summary, required this.service, required this.onUpdated});

  final InventorySummary summary;
  final InventoryService service;
  final VoidCallback onUpdated;

  @override
  State<_InventoryDetailSheet> createState() => _InventoryDetailSheetState();
}

class _InventoryDetailSheetState extends State<_InventoryDetailSheet> {
  late InventorySummary _summary;
  final DateFormat _dateFormat = DateFormat('yyyy/MM/dd HH:mm');
  final NumberFormat _numberFormat = NumberFormat.decimalPattern('ja_JP');

  bool _isLoadingMovements = true;
  bool _isRecording = false;
  List<InventoryMovement> _movements = [];

  @override
  void initState() {
    super.initState();
    _summary = widget.summary;
    _loadMovements();
  }

  Future<void> _loadMovements() async {
    setState(() => _isLoadingMovements = true);
    final movements = await widget.service.fetchMovements(_summary.productId, limit: 100);
    if (!mounted) return;
    setState(() {
      _movements = movements;
      _isLoadingMovements = false;
    });
  }

  Future<void> _recordMovement() async {
    final result = await _MovementFormDialog.show(context);
    if (result == null) return;
    setState(() => _isRecording = true);
    try {
      final updated = await widget.service.recordManualMovement(
        productId: _summary.productId,
        type: result.type,
        quantity: result.quantity,
        reference: result.reference,
        notes: result.notes,
      );
      if (!mounted) return;
      setState(() => _summary = updated);
      await _loadMovements();
      widget.onUpdated();
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('在庫履歴を登録しました')));
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('登録に失敗しました: $e')));
    } finally {
      if (mounted) setState(() => _isRecording = false);
    }
  }

  Color _movementColor(InventoryMovementType type) {
    switch (type) {
      case InventoryMovementType.receipt:
        return Colors.teal;
      case InventoryMovementType.issue:
        return Colors.redAccent;
      case InventoryMovementType.adjustment:
        return Colors.blueGrey;
    }
  }

  @override
  Widget build(BuildContext context) {
    return DraggableScrollableSheet(
      initialChildSize: 0.85,
      minChildSize: 0.6,
      maxChildSize: 0.95,
      builder: (ctx, controller) {
        return Material(
          borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
          clipBehavior: Clip.antiAlias,
          child: SafeArea(
            top: false,
            child: Column(
              children: [
                Container(
                  width: 48,
                  height: 4,
                  margin: const EdgeInsets.only(top: 12, bottom: 8),
                  decoration: BoxDecoration(color: Colors.grey.shade300, borderRadius: BorderRadius.circular(999)),
                ),
                ListTile(
                  title: Text(_summary.productName, style: const TextStyle(fontWeight: FontWeight.bold)),
                  subtitle: Text(_summary.category?.isNotEmpty == true ? _summary.category! : 'カテゴリ未設定'),
                  trailing: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      const Text('在庫数', style: TextStyle(fontSize: 12, color: Colors.grey)),
                      Text(_numberFormat.format(_summary.stockQuantity), style: const TextStyle(fontSize: 20, fontWeight: FontWeight.bold)),
                    ],
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 20),
                  child: Row(
                    children: [
                      Expanded(
                        child: Text(
                          _summary.lastMovementAt != null
                              ? '最終更新: ${_dateFormat.format(_summary.lastMovementAt!)}'
                              : '最終更新: -',
                          style: const TextStyle(color: Colors.grey),
                        ),
                      ),
                      FilledButton.icon(
                        onPressed: _isRecording ? null : _recordMovement,
                        icon: _isRecording
                            ? const SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2))
                            : const Icon(Icons.add),
                        label: const Text('入出庫を記録'),
                      ),
                    ],
                  ),
                ),
                const SizedBox(height: 12),
                Expanded(
                  child: _isLoadingMovements
                      ? const Center(child: CircularProgressIndicator())
                      : _movements.isEmpty
                          ? const Center(child: Text('入出庫履歴がまだありません'))
                          : ListView.builder(
                              controller: controller,
                              padding: const EdgeInsets.fromLTRB(16, 0, 16, 24),
                              itemCount: _movements.length,
                              itemBuilder: (context, index) {
                                final movement = _movements[index];
                                final color = _movementColor(movement.type);
                                final delta = movement.quantityDelta;
                                final deltaSign = delta > 0 ? '+${movement.quantityDelta}' : movement.quantityDelta.toString();
                                return Card(
                                  child: ListTile(
                                    leading: CircleAvatar(
                                      backgroundColor: color.withValues(alpha: 0.15),
                                      child: Icon(
                                        movement.type == InventoryMovementType.receipt
                                            ? Icons.call_received
                                            : movement.type == InventoryMovementType.issue
                                                ? Icons.call_made
                                                : Icons.inventory_outlined,
                                        color: color,
                                      ),
                                    ),
                                    title: Text(movement.type.displayName),
                                    subtitle: Text(_dateFormat.format(movement.createdAt)),
                                    trailing: Column(
                                      mainAxisAlignment: MainAxisAlignment.center,
                                      crossAxisAlignment: CrossAxisAlignment.end,
                                      children: [
                                        Text(deltaSign, style: TextStyle(color: color, fontWeight: FontWeight.bold, fontSize: 16)),
                                        if (movement.reference?.isNotEmpty == true)
                                          Text(
                                            movement.reference!,
                                            style: const TextStyle(fontSize: 12, color: Colors.grey),
                                          ),
                                      ],
                                    ),
                                  ),
                                );
                              },
                            ),
                ),
              ],
            ),
          ),
        );
      },
    );
  }
}

class _MovementFormResult {
  _MovementFormResult({
    required this.type,
    required this.quantity,
    this.reference,
    this.notes,
  });

  final InventoryMovementType type;
  final int quantity;
  final String? reference;
  final String? notes;
}

class _MovementFormDialog extends StatefulWidget {
  const _MovementFormDialog();

  static Future<_MovementFormResult?> show(BuildContext context) {
    return showFeatureModalBottomSheet<_MovementFormResult>(
      context: context,
      builder: (_) => const _MovementFormDialog(),
    );
  }

  @override
  State<_MovementFormDialog> createState() => _MovementFormDialogState();
}

class _MovementFormDialogState extends State<_MovementFormDialog> {
  final TextEditingController _quantityController = TextEditingController(text: '1');
  final TextEditingController _referenceController = TextEditingController();
  final TextEditingController _notesController = TextEditingController();
  InventoryMovementType _type = InventoryMovementType.receipt;

  @override
  void dispose() {
    _quantityController.dispose();
    _referenceController.dispose();
    _notesController.dispose();
    super.dispose();
  }

  void _submit() {
    final raw = _quantityController.text.trim();
    int? parsed = int.tryParse(raw);
    if (parsed == null || parsed == 0) {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('数量を正しく入力してください')));
      return;
    }
    if (_type != InventoryMovementType.adjustment) {
      parsed = parsed.abs();
    }
    Navigator.of(context).pop(
      _MovementFormResult(
        type: _type,
        quantity: parsed,
        reference: _referenceController.text.trim().isEmpty ? null : _referenceController.text.trim(),
        notes: _notesController.text.trim().isEmpty ? null : _notesController.text.trim(),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final isAdjustment = _type == InventoryMovementType.adjustment;
    return SafeArea(
      child: ClipRRect(
        borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
        child: Scaffold(
          resizeToAvoidBottomInset: false,
          backgroundColor: Colors.white,
          appBar: AppBar(
            automaticallyImplyLeading: false,
            leading: IconButton(
              icon: const Icon(Icons.close),
              onPressed: () => Navigator.pop(context),
            ),
            title: const ScreenAppBarTitle(screenId: 'S4', title: '入出庫を記録'),
            actions: [
              TextButton(onPressed: _submit, child: const Text('登録')),
            ],
          ),
          body: KeyboardInsetWrapper(
            safeAreaTop: false,
            basePadding: const EdgeInsets.fromLTRB(20, 16, 20, 16),
            extraBottom: 24,
            child: ListView(
              children: [
                DropdownButtonFormField<InventoryMovementType>(
                  value: _type,
                  decoration: const InputDecoration(labelText: '区分', border: OutlineInputBorder()),
                  onChanged: (val) => setState(() => _type = val ?? InventoryMovementType.receipt),
                  items: InventoryMovementType.values
                      .map((type) => DropdownMenuItem(value: type, child: Text(type.displayName)))
                      .toList(),
                ),
                const SizedBox(height: 16),
                TextField(
                  controller: _quantityController,
                  keyboardType: TextInputType.number,
                  decoration: InputDecoration(
                    labelText: isAdjustment ? '数量差分 (マイナス可)' : '数量',
                    border: const OutlineInputBorder(),
                  ),
                ),
                const SizedBox(height: 16),
                TextField(
                  controller: _referenceController,
                  decoration: const InputDecoration(labelText: '参照 (任意)', border: OutlineInputBorder()),
                ),
                const SizedBox(height: 16),
                TextField(
                  controller: _notesController,
                  maxLines: 3,
                  decoration: const InputDecoration(labelText: 'メモ', border: OutlineInputBorder()),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class SalesReceivablesScreen extends StatefulWidget {
  const SalesReceivablesScreen({super.key});

  @override
  State<SalesReceivablesScreen> createState() => _SalesReceivablesScreenState();
}

class _SalesReceivablesScreenState extends State<SalesReceivablesScreen> {
  final ReceivableService _service = ReceivableService();
  final DateFormat _dateFormat = DateFormat('yyyy/MM/dd');
  final NumberFormat _currencyFormat = NumberFormat.currency(locale: 'ja_JP', symbol: '¥');

  bool _includeSettled = false;
  bool _isLoading = false;
  bool _isVerifyingChain = false;
  List<ReceivableInvoiceSummary> _summaries = [];

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

  Future<void> _loadSummaries() async {
    setState(() => _isLoading = true);
    final list = await _service.fetchSummaries(includeSettled: _includeSettled);
    if (!mounted) return;
    setState(() {
      _summaries = list;
      _isLoading = false;
    });
  }

  void _toggleSettled(bool value) {
    setState(() => _includeSettled = value);
    _loadSummaries();
  }

  Future<void> _openDetail(ReceivableInvoiceSummary summary) async {
    await showModalBottomSheet<void>(
      context: context,
      isScrollControlled: true,
      backgroundColor: Colors.transparent,
      builder: (ctx) => _ReceivableDetailSheet(
        summary: summary,
        service: _service,
        onUpdated: () async {
          Navigator.of(ctx).pop();
          await _loadSummaries();
        },
      ),
    );
  }

  Future<void> _verifyHashChain() async {
    setState(() => _isVerifyingChain = true);
    try {
      final result = await _service.verifyHashChain();
      if (!mounted) return;
      await showDialog<void>(
        context: context,
        builder: (ctx) => _HashChainVerificationDialog(result: result),
      );
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('検証に失敗しました: $e')));
    } finally {
      if (mounted) setState(() => _isVerifyingChain = false);
    }
  }

  Color _statusColor(ReceivableInvoiceSummary summary) {
    if (summary.isSettled) {
      return Colors.green;
    }
    if (summary.isOverdue) {
      return Colors.redAccent;
    }
    return Colors.orange;
  }

  Widget _buildTile(ReceivableInvoiceSummary summary) {
    final chipColor = _statusColor(summary);
    final statusLabel = summary.isSettled
        ? '入金済'
        : summary.isOverdue
            ? '期限超過'
            : '入金待ち';
    final subtitle = [
      '請求日: ${_dateFormat.format(summary.invoiceDate)}',
      '期日: ${_dateFormat.format(summary.dueDate)}',
    ];
    return Card(
      margin: const EdgeInsets.symmetric(horizontal: 16, vertical: 8),
      child: ListTile(
        onTap: () => _openDetail(summary),
        title: Text(summary.invoiceNumber, style: const TextStyle(fontWeight: FontWeight.bold)),
        subtitle: Text('${summary.customerName}\n${subtitle.join(' / ')}'),
        trailing: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          crossAxisAlignment: CrossAxisAlignment.end,
          children: [
            Text(_currencyFormat.format(summary.outstandingAmount), style: const TextStyle(fontWeight: FontWeight.bold)),
            const SizedBox(height: 6),
            Chip(
              label: Text(statusLabel, style: const TextStyle(color: Colors.white)),
              backgroundColor: chipColor,
              padding: EdgeInsets.zero,
            ),
          ],
        ),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    Widget body;
    if (_isLoading) {
      body = const Center(child: CircularProgressIndicator());
    } else if (_summaries.isEmpty) {
      body = const _ReceivablesEmptyState();
    } else {
      body = RefreshIndicator(
        onRefresh: _loadSummaries,
        child: ListView.builder(
          padding: const EdgeInsets.only(top: 8, bottom: 88),
          itemCount: _summaries.length,
          itemBuilder: (context, index) => _buildTile(_summaries[index]),
        ),
      );
    }

    return Scaffold(
      appBar: AppBar(
        leading: const BackButton(),
        title: const Text('S5:回収・入金管理'),
        actions: [
          IconButton(
            tooltip: 'HASHチェーンを検証',
            onPressed: _isVerifyingChain ? null : _verifyHashChain,
            icon: _isVerifyingChain
                ? const SizedBox(
                    width: 18,
                    height: 18,
                    child: CircularProgressIndicator(strokeWidth: 2),
                  )
                : const Icon(Icons.verified_outlined),
          ),
          IconButton(onPressed: _isLoading ? null : _loadSummaries, icon: const Icon(Icons.refresh)),
        ],
      ),
      body: Column(
        children: [
          SwitchListTile(
            title: const Text('入金済みも表示'),
            value: _includeSettled,
            onChanged: _toggleSettled,
            secondary: const Icon(Icons.filter_alt),
          ),
          const Divider(height: 1),
          Expanded(child: body),
        ],
      ),
    );
  }
}

class _ReceivablesEmptyState extends StatelessWidget {
  const _ReceivablesEmptyState();

  @override
  Widget build(BuildContext context) {
    return Center(
      child: Padding(
        padding: const EdgeInsets.all(32),
        child: Column(
          mainAxisAlignment: MainAxisAlignment.center,
          children: const [
            Icon(Icons.account_balance_wallet_outlined, size: 64, color: Colors.grey),
            SizedBox(height: 16),
            Text('請求書データがありません', style: TextStyle(fontSize: 18, fontWeight: FontWeight.bold)),
            SizedBox(height: 8),
            Text('請求書を正式発行すると売掛リストに表示されます。', textAlign: TextAlign.center),
          ],
        ),
      ),
    );
  }
}

class _ReceivableDetailSheet extends StatefulWidget {
  const _ReceivableDetailSheet({required this.summary, required this.service, required this.onUpdated});

  final ReceivableInvoiceSummary summary;
  final ReceivableService service;
  final VoidCallback onUpdated;

  @override
  State<_ReceivableDetailSheet> createState() => _ReceivableDetailSheetState();
}

class _ReceivableDetailSheetState extends State<_ReceivableDetailSheet> {
  late ReceivableInvoiceSummary _summary;
  final NumberFormat _currencyFormat = NumberFormat.currency(locale: 'ja_JP', symbol: '¥');
  final DateFormat _dateFormat = DateFormat('yyyy/MM/dd');

  bool _isLoading = true;
  bool _isProcessing = false;
  List<ReceivablePayment> _payments = [];

  @override
  void initState() {
    super.initState();
    _summary = widget.summary;
    _refreshData();
  }

  Future<void> _refreshData() async {
    setState(() => _isLoading = true);
    final latestSummary = await widget.service.findSummary(_summary.invoiceId);
    final payments = await widget.service.fetchPayments(_summary.invoiceId);
    if (!mounted) return;
    setState(() {
      _summary = latestSummary ?? _summary;
      _payments = payments;
      _isLoading = false;
    });
  }

  Future<void> _addPayment() async {
    final result = await _PaymentFormDialog.show(context);
    if (result == null) return;
    setState(() => _isProcessing = true);
    try {
      await widget.service.addPayment(
        invoiceId: _summary.invoiceId,
        amount: result.amount,
        paymentDate: result.paymentDate,
        method: result.method,
        notes: result.notes,
      );
      await _refreshData();
      widget.onUpdated();
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('入金を登録しました')));
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('登録に失敗しました: $e')));
    } finally {
      if (mounted) setState(() => _isProcessing = false);
    }
  }

  Future<void> _deletePayment(ReceivablePayment payment) async {
    final confirmed = await showDialog<bool>(
      context: context,
      builder: (ctx) => AlertDialog(
        title: const Text('入金を削除'),
        content: Text('${_currencyFormat.format(payment.amount)} を削除しますか？'),
        actions: [
          TextButton(onPressed: () => Navigator.pop(ctx, false), child: const Text('キャンセル')),
          TextButton(onPressed: () => Navigator.pop(ctx, true), child: const Text('削除', style: TextStyle(color: Colors.red))),
        ],
      ),
    );
    if (confirmed != true) return;
    setState(() => _isProcessing = true);
    await widget.service.deletePayment(payment.id);
    await _refreshData();
    widget.onUpdated();
    if (mounted) {
      setState(() => _isProcessing = false);
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('入金を削除しました')));
    }
  }

  Color _progressColor() {
    if (_summary.isSettled) return Colors.green;
    if (_summary.isOverdue) return Colors.redAccent;
    return Colors.orange;
  }

  @override
  Widget build(BuildContext context) {
    return DraggableScrollableSheet(
      initialChildSize: 0.9,
      minChildSize: 0.6,
      maxChildSize: 0.98,
      builder: (ctx, controller) {
        return Material(
          borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
          clipBehavior: Clip.antiAlias,
          child: SafeArea(
            top: false,
            child: Column(
              children: [
                Container(
                  width: 48,
                  height: 4,
                  margin: const EdgeInsets.only(top: 12, bottom: 8),
                  decoration: BoxDecoration(color: Colors.grey.shade300, borderRadius: BorderRadius.circular(999)),
                ),
                ListTile(
                  title: Text(_summary.invoiceNumber, style: const TextStyle(fontWeight: FontWeight.bold)),
                  subtitle: Text(_summary.customerName),
                  trailing: Column(
                    mainAxisAlignment: MainAxisAlignment.center,
                    crossAxisAlignment: CrossAxisAlignment.end,
                    children: [
                      Text('残高 ${_currencyFormat.format(_summary.outstandingAmount)}'),
                      const SizedBox(height: 4),
                      Text('総額 ${_currencyFormat.format(_summary.totalAmount)}', style: const TextStyle(fontSize: 12, color: Colors.grey)),
                    ],
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 20),
                  child: Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      Text('請求日: ${_dateFormat.format(_summary.invoiceDate)}'),
                      Text('期日: ${_dateFormat.format(_summary.dueDate)}'),
                      const SizedBox(height: 12),
                      LinearProgressIndicator(
                        value: _summary.collectionProgress,
                        minHeight: 8,
                        backgroundColor: Colors.grey.shade200,
                        color: _progressColor(),
                      ),
                      const SizedBox(height: 4),
                      Text('回収率 ${(100 * _summary.collectionProgress).toStringAsFixed(1)}%'),
                    ],
                  ),
                ),
                Padding(
                  padding: const EdgeInsets.symmetric(horizontal: 20, vertical: 12),
                  child: FilledButton.icon(
                    onPressed: _isProcessing ? null : _addPayment,
                    icon: _isProcessing
                        ? const SizedBox(width: 16, height: 16, child: CircularProgressIndicator(strokeWidth: 2))
                        : const Icon(Icons.add),
                    label: const Text('入金を登録'),
                  ),
                ),
                Expanded(
                  child: _isLoading
                      ? const Center(child: CircularProgressIndicator())
                      : ListView.builder(
                          controller: controller,
                          padding: const EdgeInsets.fromLTRB(16, 0, 16, 24),
                          itemCount: _payments.length,
                          itemBuilder: (context, index) {
                            final payment = _payments[index];
                            return Card(
                              child: ListTile(
                                title: Text(_currencyFormat.format(payment.amount), style: const TextStyle(fontWeight: FontWeight.bold)),
                                subtitle: Text('${_dateFormat.format(payment.paymentDate)} / ${payment.method.displayName}${payment.notes?.isNotEmpty == true ? '\n${payment.notes}' : ''}'),
                                trailing: IconButton(
                                  icon: const Icon(Icons.delete_outline, color: Colors.redAccent),
                                  onPressed: _isProcessing ? null : () => _deletePayment(payment),
                                ),
                              ),
                            );
                          },
                        ),
                ),
              ],
            ),
          ),
        );
      },
    );
  }
}

class _PaymentFormResult {
  const _PaymentFormResult({
    required this.amount,
    required this.paymentDate,
    required this.method,
    this.notes,
  });

  final int amount;
  final DateTime paymentDate;
  final PaymentMethod method;
  final String? notes;
}

class _PaymentFormDialog extends StatefulWidget {
  const _PaymentFormDialog();

  static Future<_PaymentFormResult?> show(BuildContext context) {
    return showFeatureModalBottomSheet<_PaymentFormResult>(
      context: context,
      builder: (ctx) => const _PaymentFormDialog(),
    );
  }

  @override
  State<_PaymentFormDialog> createState() => _PaymentFormDialogState();
}

class _PaymentFormDialogState extends State<_PaymentFormDialog> {
  final TextEditingController _amountController = TextEditingController();
  final TextEditingController _notesController = TextEditingController();
  DateTime _paymentDate = DateTime.now();
  PaymentMethod _method = PaymentMethod.bankTransfer;
  bool _isSubmitting = false;

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

  Future<void> _pickDate() async {
    final picked = await showDatePicker(
      context: context,
      initialDate: _paymentDate,
      firstDate: DateTime(DateTime.now().year - 2),
      lastDate: DateTime(DateTime.now().year + 2),
    );
    if (picked != null) {
      setState(() => _paymentDate = picked);
    }
  }

  void _submit() {
    if (_isSubmitting) return;
    final amount = int.tryParse(_amountController.text.trim());
    if (amount == null || amount <= 0) {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('金額を入力してください')));
      return;
    }
    setState(() => _isSubmitting = true);
    Navigator.of(context).pop(
      _PaymentFormResult(
        amount: amount,
        paymentDate: _paymentDate,
        method: _method,
        notes: _notesController.text.trim().isEmpty ? null : _notesController.text.trim(),
      ),
    );
  }

  @override
  Widget build(BuildContext context) {
    final dateLabel = DateFormat('yyyy/MM/dd').format(_paymentDate);
    return SafeArea(
      child: ClipRRect(
        borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
        child: Scaffold(
          backgroundColor: Colors.white,
          appBar: AppBar(
            automaticallyImplyLeading: false,
            leading: IconButton(
              icon: const Icon(Icons.close),
              onPressed: _isSubmitting ? null : () => Navigator.pop(context),
            ),
            title: const ScreenAppBarTitle(screenId: 'S5', title: '入金登録'),
            actions: [
              TextButton(
                onPressed: _isSubmitting ? null : _submit,
                child: _isSubmitting
                    ? const SizedBox(width: 18, height: 18, child: CircularProgressIndicator(strokeWidth: 2))
                    : const Text('保存'),
              ),
            ],
          ),
          body: KeyboardInsetWrapper(
            safeAreaTop: false,
            basePadding: const EdgeInsets.fromLTRB(20, 16, 20, 16),
            extraBottom: 24,
            child: ListView(
              children: [
                TextField(
                  controller: _amountController,
                  keyboardType: TextInputType.number,
                  textInputAction: TextInputAction.next,
                  decoration: const InputDecoration(labelText: '入金額 (円)', border: OutlineInputBorder()),
                ),
                const SizedBox(height: 16),
                InputDecorator(
                  decoration: const InputDecoration(labelText: '入金日', border: OutlineInputBorder()),
                  child: InkWell(
                    onTap: _pickDate,
                    child: Padding(
                      padding: const EdgeInsets.symmetric(vertical: 4),
                      child: Row(
                        mainAxisAlignment: MainAxisAlignment.spaceBetween,
                        children: [
                          Text(dateLabel),
                          const Icon(Icons.calendar_today, size: 18),
                        ],
                      ),
                    ),
                  ),
                ),
                const SizedBox(height: 16),
                DropdownButtonFormField<PaymentMethod>(
                  value: _method,
                  decoration: const InputDecoration(labelText: '入金方法', border: OutlineInputBorder()),
                  onChanged: (val) => setState(() => _method = val ?? PaymentMethod.bankTransfer),
                  items: PaymentMethod.values
                      .map((method) => DropdownMenuItem(value: method, child: Text(method.displayName)))
                      .toList(),
                ),
                const SizedBox(height: 16),
                TextField(
                  controller: _notesController,
                  maxLines: 3,
                  decoration: const InputDecoration(labelText: 'メモ (任意)', border: OutlineInputBorder()),
                ),
                const SizedBox(height: 24),
                FilledButton(
                  onPressed: _isSubmitting ? null : _submit,
                  child: const Text('入金を登録'),
                ),
              ],
            ),
          ),
        ),
      ),
    );
  }
}

class SalesOrderEditorPage extends StatefulWidget {
  const SalesOrderEditorPage({super.key, required this.service, this.order});

  final SalesOrderService service;
  final SalesOrder? order;

  @override
  State<SalesOrderEditorPage> createState() => _SalesOrderEditorPageState();
}

class _SalesOrderEditorPageState extends State<SalesOrderEditorPage> {
  final TextEditingController _notesController = TextEditingController();
  final TextEditingController _assigneeController = TextEditingController();
  final DateFormat _dateFormat = DateFormat('yyyy/MM/dd');

  String? _customerId;
  String? _customerName;
  DateTime? _requestedShipDate;
  bool _isSaving = false;
  final List<_OrderLineFormData> _lines = [];

  @override
  void initState() {
    super.initState();
    final order = widget.order;
    if (order != null) {
      _customerId = order.customerId;
      _customerName = order.customerNameSnapshot;
      _requestedShipDate = order.requestedShipDate;
      _notesController.text = order.notes ?? '';
      _assigneeController.text = order.assignedTo ?? '';
      for (final item in order.items) {
        _lines.add(
          _OrderLineFormData(
            description: item.description,
            quantity: item.quantity,
            unitPrice: item.unitPrice,
          ),
        );
      }
    }
    if (_lines.isEmpty) {
      _lines.add(_OrderLineFormData());
    }
  }

  @override
  void dispose() {
    _notesController.dispose();
    _assigneeController.dispose();
    for (final line in _lines) {
      line.dispose();
    }
    super.dispose();
  }

  Future<void> _pickCustomer() async {
    final selected = await showFeatureModalBottomSheet<Customer?>(
      context: context,
      builder: (ctx) => CustomerPickerModal(
        onCustomerSelected: (customer) {
          Navigator.pop(ctx, customer);
        },
      ),
    );
    if (selected != null) {
      setState(() {
        _customerId = selected.id;
        _customerName = selected.formalName;
      });
    }
  }

  Future<void> _pickDate() async {
    final now = DateTime.now();
    final initial = _requestedShipDate ?? now;
    final picked = await showDatePicker(
      context: context,
      initialDate: initial,
      firstDate: DateTime(now.year - 1),
      lastDate: DateTime(now.year + 2),
    );
    if (picked != null) {
      setState(() => _requestedShipDate = picked);
    }
  }

  void _addLine() {
    setState(() {
      _lines.add(_OrderLineFormData());
    });
  }

  void _removeLine(int index) {
    if (_lines.length == 1) return;
    setState(() {
      final line = _lines.removeAt(index);
      line.dispose();
    });
  }

  Future<void> _save() async {
    if (_customerId == null || _customerName == null) {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('取引先を選択してください')));
      return;
    }

    final inputs = <SalesOrderLineInput>[];
    for (final line in _lines) {
      final desc = line.descriptionController.text.trim();
      final qty = int.tryParse(line.quantityController.text) ?? 0;
      final price = int.tryParse(line.unitPriceController.text) ?? 0;
      if (desc.isEmpty || qty <= 0) continue;
      inputs.add(SalesOrderLineInput(description: desc, quantity: qty, unitPrice: price));
    }
    if (inputs.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(const SnackBar(content: Text('明細を1件以上入力してください')));
      return;
    }

    setState(() => _isSaving = true);
    try {
      SalesOrder saved;
      if (widget.order == null) {
        saved = await widget.service.createOrder(
          customerId: _customerId!,
          customerName: _customerName!,
          lines: inputs,
          requestedShipDate: _requestedShipDate,
          notes: _notesController.text.trim().isEmpty ? null : _notesController.text.trim(),
          assignedTo: _assigneeController.text.trim().isEmpty ? null : _assigneeController.text.trim(),
        );
      } else {
        saved = await widget.service.updateOrder(
          widget.order!,
          replacedLines: inputs,
          requestedShipDate: _requestedShipDate,
          notes: _notesController.text.trim().isEmpty ? null : _notesController.text.trim(),
          assignedTo: _assigneeController.text.trim().isEmpty ? null : _assigneeController.text.trim(),
        );
      }
      if (!mounted) return;
      Navigator.pop(context, saved);
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('保存に失敗しました: $e')));
      setState(() => _isSaving = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    final title = widget.order == null ? '受注の新規登録' : '受注を編集';
    final screenTitle = widget.order == null ? '受注登録' : '受注編集';
    final mediaQuery = MediaQuery.of(context);
    final bottomInset = mediaQuery.viewInsets.bottom;

    return Scaffold(
      backgroundColor: Colors.grey.shade200,
      resizeToAvoidBottomInset: false,
      appBar: AppBar(
        leading: const BackButton(),
        title: ScreenAppBarTitle(screenId: 'S6', title: screenTitle),
        actions: [
          TextButton(
            onPressed: _isSaving ? null : _save,
            child: _isSaving
                ? const SizedBox(width: 18, height: 18, child: CircularProgressIndicator(strokeWidth: 2))
                : const Text('保存'),
          ),
        ],
      ),
      body: MediaQuery(
        data: mediaQuery.removeViewInsets(removeBottom: true),
        child: SafeArea(
          top: false,
          child: GestureDetector(
            behavior: HitTestBehavior.opaque,
            onTap: () => FocusScope.of(context).unfocus(),
            child: SingleChildScrollView(
              keyboardDismissBehavior: ScrollViewKeyboardDismissBehavior.onDrag,
              padding: EdgeInsets.fromLTRB(20, 20, 20, 20 + 32 + bottomInset),
              child: Column(
                crossAxisAlignment: CrossAxisAlignment.start,
                children: [
                  ListTile(
                    contentPadding: EdgeInsets.zero,
                    title: const Text('取引先'),
                    subtitle: Text(_customerName ?? '未選択'),
                    trailing: OutlinedButton.icon(
                      onPressed: _pickCustomer,
                      icon: const Icon(Icons.search),
                      label: Text(_customerName == null ? '選択' : '変更'),
                    ),
                  ),
                  const SizedBox(height: 12),
                  ListTile(
                    contentPadding: EdgeInsets.zero,
                    title: const Text('希望出荷日'),
                    subtitle: Text(_requestedShipDate != null ? _dateFormat.format(_requestedShipDate!) : '未設定'),
                    trailing: IconButton(
                      icon: const Icon(Icons.calendar_today),
                      onPressed: _pickDate,
                    ),
                  ),
                  const SizedBox(height: 12),
                  TextField(
                    controller: _assigneeController,
                    decoration: const InputDecoration(labelText: '担当者 (任意)', border: OutlineInputBorder()),
                  ),
                  const SizedBox(height: 12),
                  TextField(
                    controller: _notesController,
                    maxLines: 3,
                    decoration: const InputDecoration(labelText: 'メモ / 特記事項', border: OutlineInputBorder()),
                  ),
                  const SizedBox(height: 24),
                  const Text('受注明細', style: TextStyle(fontSize: 16, fontWeight: FontWeight.bold)),
                  const SizedBox(height: 12),
                  for (int i = 0; i < _lines.length; i++) _buildLineCard(i),
                  const SizedBox(height: 12),
                  OutlinedButton.icon(
                    onPressed: _addLine,
                    icon: const Icon(Icons.add),
                    label: const Text('明細を追加'),
                  ),
                  const SizedBox(height: 32),
                ],
              ),
            ),
          ),
        ),
      ),
    );
  }

  Widget _buildLineCard(int index) {
    final line = _lines[index];
    return Card(
      margin: const EdgeInsets.only(bottom: 12),
      child: Padding(
        padding: const EdgeInsets.all(16),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Row(
              mainAxisAlignment: MainAxisAlignment.spaceBetween,
              children: [
                Text('明細 ${index + 1}', style: const TextStyle(fontWeight: FontWeight.bold)),
                if (_lines.length > 1)
                  IconButton(
                    icon: const Icon(Icons.delete_outline),
                    onPressed: () => _removeLine(index),
                  ),
              ],
            ),
            TextField(
              controller: line.descriptionController,
              decoration: const InputDecoration(labelText: '内容', border: OutlineInputBorder()),
            ),
            const SizedBox(height: 12),
            Row(
              children: [
                Expanded(
                  child: TextField(
                    controller: line.quantityController,
                    keyboardType: TextInputType.number,
                    decoration: const InputDecoration(labelText: '数量', border: OutlineInputBorder()),
                  ),
                ),
                const SizedBox(width: 12),
                Expanded(
                  child: TextField(
                    controller: line.unitPriceController,
                    keyboardType: TextInputType.number,
                    decoration: const InputDecoration(labelText: '単価 (円)', border: OutlineInputBorder()),
                  ),
                ),
              ],
            ),
          ],
        ),
      ),
    );
  }
}

class _OrderLineFormData {
  _OrderLineFormData({String description = '', int quantity = 1, int unitPrice = 0})
      : descriptionController = TextEditingController(text: description),
        quantityController = TextEditingController(text: quantity.toString()),
        unitPriceController = TextEditingController(text: unitPrice.toString());

  final TextEditingController descriptionController;
  final TextEditingController quantityController;
  final TextEditingController unitPriceController;

  void dispose() {
    descriptionController.dispose();
    quantityController.dispose();
    unitPriceController.dispose();
  }
}

class _OrderDetailSheet extends StatefulWidget {
  const _OrderDetailSheet({required this.order, required this.service, required this.onEdit});

  final SalesOrder order;
  final SalesOrderService service;
  final void Function(SalesOrder order) onEdit;

  @override
  State<_OrderDetailSheet> createState() => _OrderDetailSheetState();
}

class _OrderDetailSheetState extends State<_OrderDetailSheet> {
  late SalesOrder _order;
  bool _isProcessing = false;
  final NumberFormat _currencyFormat = NumberFormat.currency(locale: 'ja_JP', symbol: '¥');
  final DateFormat _dateFormat = DateFormat('yyyy/MM/dd');

  @override
  void initState() {
    super.initState();
    _order = widget.order;
  }

  Future<void> _advance() async {
    if (_isProcessing) return;
    setState(() => _isProcessing = true);
    try {
      final updated = await widget.service.advanceStatus(_order.id);
      if (!mounted) return;
      setState(() => _order = updated);
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('ステータス更新に失敗しました: $e')));
    } finally {
      if (mounted) setState(() => _isProcessing = false);
    }
  }

  Future<void> _cancelOrder() async {
    if (_order.status == SalesOrderStatus.cancelled || _isProcessing) return;
    setState(() => _isProcessing = true);
    try {
      final updated = await widget.service.transitionStatus(_order.id, SalesOrderStatus.cancelled, force: true);
      if (!mounted) return;
      setState(() => _order = updated);
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text('キャンセルに失敗しました: $e')));
    } finally {
      if (mounted) setState(() => _isProcessing = false);
    }
  }

  String _formatDate(DateTime date) => _dateFormat.format(date);

  Color _statusColor(SalesOrderStatus status) {
    switch (status) {
      case SalesOrderStatus.draft:
        return Colors.grey.shade500;
      case SalesOrderStatus.confirmed:
        return Colors.indigo;
      case SalesOrderStatus.picking:
        return Colors.orange;
      case SalesOrderStatus.shipped:
        return Colors.blue;
      case SalesOrderStatus.closed:
        return Colors.green;
      case SalesOrderStatus.cancelled:
        return Colors.redAccent;
    }
  }

  @override
  Widget build(BuildContext context) {
    final nextStatuses = widget.service.nextStatuses(_order.status);
    return DraggableScrollableSheet(
      initialChildSize: 0.85,
      minChildSize: 0.6,
      maxChildSize: 0.95,
      builder: (ctx, controller) {
        return Material(
          borderRadius: const BorderRadius.vertical(top: Radius.circular(24)),
          clipBehavior: Clip.antiAlias,
          child: Column(
            children: [
              Container(
                width: 48,
                height: 4,
                margin: const EdgeInsets.only(top: 12, bottom: 8),
                decoration: BoxDecoration(color: Colors.grey.shade300, borderRadius: BorderRadius.circular(999)),
              ),
              ListTile(
                title: Text(_order.customerNameSnapshot ?? '取引先未設定', style: const TextStyle(fontWeight: FontWeight.bold)),
                subtitle: Text('受注番号: ${_order.orderNumber ?? _order.id.substring(0, 6)}'),
                trailing: IconButton(
                  icon: const Icon(Icons.edit),
                  onPressed: () => widget.onEdit(_order),
                ),
              ),
              Expanded(
                child: ListView(
                  controller: controller,
                  padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
                  children: [
                    Wrap(
                      spacing: 8,
                      runSpacing: 8,
                      children: SalesOrderStatus.values
                          .map(
                            (status) => Chip(
                              label: Text(status.displayName),
                              backgroundColor: status == _order.status ? _statusColor(status) : Colors.grey.shade200,
                              labelStyle: TextStyle(
                                color: status == _order.status ? Colors.white : Colors.black87,
                                fontWeight: status == _order.status ? FontWeight.bold : FontWeight.normal,
                              ),
                            ),
                          )
                          .toList(),
                    ),
                    const SizedBox(height: 16),
                    _InfoRow(label: '受注日', value: _formatDate(_order.orderDate)),
                    if (_order.requestedShipDate != null)
                      _InfoRow(label: '希望出荷日', value: _formatDate(_order.requestedShipDate!)),
                    if (_order.assignedTo?.isNotEmpty == true) _InfoRow(label: '担当者', value: _order.assignedTo!),
                    if (_order.notes?.isNotEmpty == true)
                      Card(
                        margin: const EdgeInsets.only(top: 12),
                        child: Padding(
                          padding: const EdgeInsets.all(12),
                          child: Text(_order.notes!),
                        ),
                      ),
                    const SizedBox(height: 16),
                    const Text('明細', style: TextStyle(fontWeight: FontWeight.bold)),
                    const SizedBox(height: 8),
                    ..._order.items.map(
                      (item) => ListTile(
                        dense: true,
                        title: Text(item.description),
                        subtitle: Text('数量 ${item.quantity} / 単価 ${item.unitPrice} 円'),
                        trailing: Text('${item.lineTotal} 円'),
                      ),
                    ),
                    const Divider(height: 24),
                    _InfoRow(label: '小計', value: _currencyFormat.format(_order.subtotal)),
                    _InfoRow(label: '税額', value: _currencyFormat.format(_order.taxAmount)),
                    _InfoRow(label: '合計', value: _currencyFormat.format(_order.totalAmount), emphasized: true),
                    const SizedBox(height: 24),
                    FilledButton.icon(
                      onPressed: nextStatuses.isEmpty || _isProcessing ? null : _advance,
                      icon: const Icon(Icons.playlist_add_check),
                      label: Text(nextStatuses.isEmpty ? '完了済み' : '${nextStatuses.first.displayName} へ進める'),
                    ),
                    const SizedBox(height: 8),
                    TextButton(
                      onPressed:
                          _order.status == SalesOrderStatus.cancelled || _isProcessing ? null : _cancelOrder,
                      child: const Text('キャンセルに変更'),
                    ),
                  ],
                ),
              ),
            ],
          ),
        );
      },
    );
  }
}

class _InfoRow extends StatelessWidget {
  const _InfoRow({required this.label, required this.value, this.emphasized = false});

  final String label;
  final String value;
  final bool emphasized;

  @override
  Widget build(BuildContext context) {
    final textStyle = emphasized
        ? Theme.of(context).textTheme.titleMedium?.copyWith(fontWeight: FontWeight.bold)
        : Theme.of(context).textTheme.bodyMedium;
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 4),
      child: Row(
        mainAxisAlignment: MainAxisAlignment.spaceBetween,
        children: [
          Text(label, style: Theme.of(context).textTheme.bodySmall),
          const SizedBox(width: 16),
          Expanded(
            child: Text(
              value,
              style: textStyle,
              textAlign: TextAlign.end,
            ),
          ),
        ],
      ),
    );
  }
}
