import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:get_it/get_it.dart';
import 'package:intl/intl.dart' as intl;
import 'package:lucide_icons_flutter/lucide_icons.dart' as lucide;
import 'package:shadcn_ui/shadcn_ui.dart';
import 'package:url_launcher/url_launcher.dart';

import 'package:superport_v2/core/network/failure.dart';
import 'package:superport_v2/core/common/utils/pagination_utils.dart';
import 'package:superport_v2/core/constants/app_sections.dart';
import 'package:superport_v2/core/services/file_saver.dart';
import 'package:superport_v2/features/inventory/lookups/domain/entities/lookup_item.dart';
import 'package:superport_v2/features/inventory/lookups/domain/repositories/inventory_lookup_repository.dart';
import 'package:superport_v2/features/inventory/shared/widgets/employee_autocomplete_field.dart';
import 'package:superport_v2/features/masters/warehouse/domain/entities/warehouse.dart';
import 'package:superport_v2/features/masters/warehouse/domain/repositories/warehouse_repository.dart';
import 'package:superport_v2/features/reporting/domain/entities/report_download_result.dart';
import 'package:superport_v2/features/reporting/domain/entities/report_export_format.dart';
import 'package:superport_v2/features/reporting/domain/entities/report_export_request.dart';
import 'package:superport_v2/features/reporting/domain/repositories/reporting_repository.dart';
import 'package:superport_v2/widgets/app_layout.dart';
import 'package:superport_v2/widgets/components/empty_state.dart';
import 'package:superport_v2/widgets/components/feedback.dart';
import 'package:superport_v2/widgets/components/filter_bar.dart';
import 'package:superport_v2/widgets/components/superport_date_picker.dart';

/// 보고서 다운로드 화면 루트 위젯.
class ReportingPage extends StatefulWidget {
  const ReportingPage({super.key});

  @override
  State<ReportingPage> createState() => _ReportingPageState();
}

/// 보고서 페이지 UI 상태와 필터 조건을 관리하는 상태 클래스.
class _ReportingPageState extends State<ReportingPage> {
  late final WarehouseRepository _warehouseRepository;
  ReportingRepository? _reportingRepository;
  InventoryLookupRepository? _lookupRepository;
  final intl.DateFormat _dateFormat = intl.DateFormat('yyyy.MM.dd');
  final Map<ReportStatusFilter, LookupItem> _transactionStatusLookup = {};
  final Map<ReportStatusFilter, LookupItem> _approvalStatusLookup = {};
  bool _isLoadingLookups = false;
  String? _lookupError;
  bool _isExporting = false;
  String? _exportError;
  ReportDownloadResult? _lastResult;
  ReportExportFormat? _lastFormat;
  final TextEditingController _requesterController = TextEditingController();
  InventoryEmployeeSuggestion? _appliedRequester;
  InventoryEmployeeSuggestion? _pendingRequester;

  static const Map<ReportStatusFilter, List<String>>
  _transactionStatusKeywords = {
    ReportStatusFilter.inProgress: ['작성', '대기', '진행', 'pending'],
    ReportStatusFilter.completed: ['완료', '승인', 'complete', 'approved'],
    ReportStatusFilter.cancelled: ['취소', '반려', 'cancel', 'rejected'],
  };

  static const Map<ReportStatusFilter, List<String>> _approvalStatusKeywords = {
    ReportStatusFilter.inProgress: ['진행', '대기', 'processing'],
    ReportStatusFilter.completed: ['완료', '승인', 'approved'],
    ReportStatusFilter.cancelled: ['취소', '반려', 'cancel'],
  };

  DateTimeRange? _appliedDateRange;
  DateTimeRange? _pendingDateRange;
  ReportTypeFilter _appliedType = ReportTypeFilter.all;
  ReportTypeFilter _pendingType = ReportTypeFilter.all;
  ReportStatusFilter _appliedStatus = ReportStatusFilter.all;
  ReportStatusFilter _pendingStatus = ReportStatusFilter.all;
  WarehouseFilterOption _appliedWarehouse = WarehouseFilterOption.all;
  WarehouseFilterOption _pendingWarehouse = WarehouseFilterOption.all;

  List<WarehouseFilterOption> _warehouseOptions = const [
    WarehouseFilterOption.all,
  ];
  bool _isLoadingWarehouses = false;
  String? _warehouseError;

  /// 실패 객체에서 사용자 메시지를 추출한다.
  String _failureMessage(Object error, String fallback) {
    final failure = Failure.from(error);
    final description = failure.describe();
    if (description.isEmpty) {
      return fallback;
    }
    return description;
  }

  @override
  void initState() {
    super.initState();
    final getIt = GetIt.I;
    _warehouseRepository = getIt<WarehouseRepository>();
    if (getIt.isRegistered<ReportingRepository>()) {
      _reportingRepository = getIt<ReportingRepository>();
    }
    if (getIt.isRegistered<InventoryLookupRepository>()) {
      _lookupRepository = getIt<InventoryLookupRepository>();
      _loadLookups();
    }
    _loadWarehouses();
  }

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

  /// 활성 창고 목록을 불러와 드롭다운 옵션을 준비한다.
  Future<void> _loadWarehouses() async {
    setState(() {
      _isLoadingWarehouses = true;
      _warehouseError = null;
    });
    try {
      final warehouses = await fetchAllPaginatedItems<Warehouse>(
        request: (page, pageSize) => _warehouseRepository.list(
          page: page,
          pageSize: pageSize,
          isActive: true,
        ),
      );
      if (!mounted) {
        return;
      }
      final seen = <String>{WarehouseFilterOption.all.cacheKey};
      final options = <WarehouseFilterOption>[WarehouseFilterOption.all];
      for (final warehouse in warehouses) {
        final option = WarehouseFilterOption.fromWarehouse(warehouse);
        if (seen.add(option.cacheKey)) {
          options.add(option);
        }
      }
      if (mounted) {
        setState(() {
          _warehouseOptions = options;
          _appliedWarehouse = _resolveWarehouseOption(
            _appliedWarehouse,
            options,
          );
          _pendingWarehouse = _resolveWarehouseOption(
            _pendingWarehouse,
            options,
          );
        });
      }
    } catch (error) {
      if (mounted) {
        final message = _failureMessage(
          error,
          '창고 목록을 불러오지 못했습니다. 잠시 후 다시 시도하세요.',
        );
        setState(() {
          _warehouseError = message;
          _warehouseOptions = const [WarehouseFilterOption.all];
          _appliedWarehouse = WarehouseFilterOption.all;
          _pendingWarehouse = WarehouseFilterOption.all;
        });
        SuperportToast.error(context, message);
      }
    } finally {
      if (mounted) {
        setState(() {
          _isLoadingWarehouses = false;
        });
      }
    }
  }

  Future<void> _loadLookups() async {
    final repository = _lookupRepository;
    if (repository == null) {
      return;
    }
    setState(() {
      _isLoadingLookups = true;
      _lookupError = null;
    });
    try {
      final transactionStatuses = await repository.fetchTransactionStatuses();
      final approvalStatuses = await repository.fetchApprovalStatuses();
      if (!mounted) {
        return;
      }
      setState(() {
        _transactionStatusLookup
          ..clear()
          ..addAll(
            _mapStatusByKeyword(
              transactionStatuses,
              _transactionStatusKeywords,
            ),
          );
        _approvalStatusLookup
          ..clear()
          ..addAll(
            _mapStatusByKeyword(approvalStatuses, _approvalStatusKeywords),
          );
      });
    } catch (error) {
      if (mounted) {
        final message = _failureMessage(
          error,
          '유형/상태 정보를 불러오지 못했습니다. 잠시 후 다시 시도하세요.',
        );
        setState(() {
          _lookupError = message;
        });
        SuperportToast.error(context, message);
      }
    } finally {
      if (mounted) {
        setState(() {
          _isLoadingLookups = false;
        });
      }
    }
  }

  /// 적용된 필터를 초기 상태로 되돌린다.
  void _resetFilters() {
    setState(() {
      _appliedDateRange = null;
      _pendingDateRange = null;
      _appliedType = ReportTypeFilter.all;
      _pendingType = ReportTypeFilter.all;
      _appliedStatus = ReportStatusFilter.all;
      _pendingStatus = ReportStatusFilter.all;
      _appliedWarehouse = WarehouseFilterOption.all;
      _pendingWarehouse = WarehouseFilterOption.all;
      _appliedRequester = null;
      _pendingRequester = null;
      _requesterController.clear();
    });
  }

  /// 대기 중인 필터 값을 실제 적용 상태로 확정한다.
  void _applyFilters() {
    setState(() {
      _appliedDateRange = _pendingDateRange;
      _appliedType = _pendingType;
      _appliedStatus = _pendingStatus;
      _appliedWarehouse = _pendingWarehouse;
      _appliedRequester = _pendingRequester;
    });
  }

  bool get _canExport {
    return _appliedDateRange != null && _appliedType != ReportTypeFilter.all;
  }

  bool get _hasCustomFilters {
    return _appliedDateRange != null ||
        _appliedType != ReportTypeFilter.all ||
        _appliedStatus != ReportStatusFilter.all ||
        _appliedWarehouse != WarehouseFilterOption.all ||
        _appliedRequester != null;
  }

  bool get _hasAppliedFilters => _hasCustomFilters;

  bool get _hasDirtyFilters =>
      !_isSameRange(_pendingDateRange, _appliedDateRange) ||
      _pendingType != _appliedType ||
      _pendingStatus != _appliedStatus ||
      _pendingWarehouse != _appliedWarehouse ||
      !_isSameRequester(_pendingRequester, _appliedRequester);

  bool _isSameRange(DateTimeRange? a, DateTimeRange? b) {
    if (identical(a, b)) {
      return true;
    }
    if (a == null || b == null) {
      return a == b;
    }
    return a.start == b.start && a.end == b.end;
  }

  bool _isSameRequester(
    InventoryEmployeeSuggestion? a,
    InventoryEmployeeSuggestion? b,
  ) {
    if (identical(a, b)) {
      return true;
    }
    if (a == null || b == null) {
      return a == b;
    }
    return a.id == b.id;
  }

  WarehouseFilterOption _resolveWarehouseOption(
    WarehouseFilterOption target,
    List<WarehouseFilterOption> options,
  ) {
    for (final option in options) {
      if (option == target) {
        return option;
      }
    }
    return options.first;
  }

  Map<ReportStatusFilter, LookupItem> _mapStatusByKeyword(
    List<LookupItem> items,
    Map<ReportStatusFilter, List<String>> keywords,
  ) {
    final result = <ReportStatusFilter, LookupItem>{};
    for (final entry in keywords.entries) {
      final matched = _matchLookup(items, entry.value);
      if (matched != null) {
        result[entry.key] = matched;
      }
    }
    return result;
  }

  LookupItem? _matchLookup(List<LookupItem> items, List<String> keywords) {
    final normalized = keywords
        .map((keyword) => keyword.trim().toLowerCase())
        .where((keyword) => keyword.isNotEmpty)
        .toList(growable: false);
    if (normalized.isEmpty) {
      return null;
    }
    for (final item in items) {
      final name = item.name.trim().toLowerCase();
      if (normalized.any((keyword) => name.contains(keyword))) {
        return item;
      }
    }
    return null;
  }

  int? _resolveTransactionStatusId() {
    if (_appliedStatus == ReportStatusFilter.all) {
      return null;
    }
    return _transactionStatusLookup[_appliedStatus]?.id;
  }

  int? _resolveApprovalStatusId() {
    if (_appliedStatus == ReportStatusFilter.all) {
      return null;
    }
    return _approvalStatusLookup[_appliedStatus]?.id;
  }

  String _dateRangeLabel(DateTimeRange? range) {
    if (range == null) {
      return '기간 선택';
    }
    return '${_formatDate(range.start)} ~ ${_formatDate(range.end)}';
  }

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

  String _requesterLabel(InventoryEmployeeSuggestion? suggestion) {
    if (suggestion == null) {
      return '전체 상신자';
    }
    return '${suggestion.name} (${suggestion.employeeNo})';
  }

  Future<void> _handleExport(ReportExportFormat format) async {
    if (_isExporting) {
      return;
    }
    final repository = _reportingRepository;
    final range = _appliedDateRange;
    if (repository == null) {
      SuperportToast.error(context, '보고서 다운로드 리포지토리가 초기화되지 않았습니다.');
      return;
    }
    if (range == null) {
      SuperportToast.error(context, '기간을 먼저 선택하세요.');
      return;
    }
    setState(() {
      _isExporting = true;
      _exportError = null;
    });
    final request = ReportExportRequest(
      from: range.start,
      to: range.end,
      format: format,
      transactionStatusId: _resolveTransactionStatusId(),
      approvalStatusId: _resolveApprovalStatusId(),
      requestedById: _appliedRequester?.id,
    );
    try {
      final result = _appliedType == ReportTypeFilter.approval
          ? await repository.exportApprovals(request)
          : await repository.exportTransactions(request);
      if (!mounted) {
        return;
      }
      setState(() {
        _lastResult = result;
        _lastFormat = format;
      });
      if (result.hasDownloadUrl) {
        SuperportToast.success(context, '다운로드 링크가 준비되었습니다.');
      } else if (result.hasBytes) {
        await _saveBinaryResult(result, format);
      } else {
        SuperportToast.info(context, '다운로드 결과를 확인했지만 추가 처리 항목이 없습니다.');
      }
    } catch (error) {
      if (!mounted) {
        return;
      }
      final message = _failureMessage(
        error,
        '보고서 다운로드에 실패했습니다. 잠시 후 다시 시도하세요.',
      );
      setState(() {
        _exportError = message;
      });
      SuperportToast.error(context, message);
    } finally {
      if (mounted) {
        setState(() {
          _isExporting = false;
        });
      }
    }
  }

  Future<void> _saveBinaryResult(
    ReportDownloadResult result,
    ReportExportFormat format,
  ) async {
    final bytes = result.bytes;
    if (bytes == null || bytes.isEmpty) {
      return;
    }
    final filename = result.filename ?? 'report.${format.apiValue}';
    final mimeType = result.mimeType ?? _mimeTypeForFormat(format);
    try {
      await saveFileBytes(bytes: bytes, filename: filename, mimeType: mimeType);
      if (!mounted) {
        return;
      }
      SuperportToast.success(context, '보고서 파일 다운로드가 시작되었습니다.');
    } on UnsupportedError {
      if (!mounted) {
        return;
      }
      SuperportToast.info(
        context,
        '현재 환경에서는 자동 저장을 지원하지 않습니다. 다운로드 링크 요청 기능을 이용하세요.',
      );
    } catch (_) {
      if (!mounted) {
        return;
      }
      SuperportToast.error(context, '파일을 저장하는 중 문제가 발생했습니다. 잠시 후 다시 시도하세요.');
    }
  }

  void _notifyPdfUnavailable() {
    SuperportToast.info(context, 'PDF 다운로드는 현재 지원되지 않습니다.');
  }

  String _mimeTypeForFormat(ReportExportFormat format) {
    switch (format) {
      case ReportExportFormat.xlsx:
        return 'application/vnd.openxmlformats-officedocument.spreadsheetml.sheet';
      case ReportExportFormat.pdf:
        return 'application/pdf';
    }
  }

  Future<void> _launchDownloadUrl(Uri url) async {
    try {
      final opened = await launchUrl(url, mode: LaunchMode.externalApplication);
      if (!opened && mounted) {
        SuperportToast.error(context, '다운로드 링크를 열 수 없습니다.');
      }
    } catch (_) {
      if (mounted) {
        SuperportToast.error(context, '다운로드 링크를 열 수 없습니다.');
      }
    }
  }

  Future<void> _copyDownloadUrl(Uri url) async {
    await Clipboard.setData(ClipboardData(text: url.toString()));
    if (mounted) {
      SuperportToast.success(context, '다운로드 URL을 복사했습니다.');
    }
  }

  Widget _buildPreview(ShadThemeData theme) {
    if (_isExporting) {
      return const Center(child: CircularProgressIndicator());
    }
    if (_exportError != null) {
      return Center(
        child: Text(
          _exportError!,
          style: theme.textTheme.small.copyWith(
            color: theme.colorScheme.destructive,
          ),
        ),
      );
    }
    final result = _lastResult;
    if (result == null) {
      return SuperportEmptyState(
        icon: lucide.LucideIcons.chartBar,
        title: '미리보기 데이터가 없습니다.',
        description: '필터를 적용하거나 보고서를 다운로드하면 이 영역에 요약이 표시됩니다.',
      );
    }
    final rows = <Widget>[
      if (_lastFormat != null)
        _SummaryRow(label: '형식', value: _lastFormat!.label),
      if (result.filename != null)
        _SummaryRow(label: '파일명', value: result.filename!),
      if (result.mimeType != null)
        _SummaryRow(label: 'MIME', value: result.mimeType!),
      if (result.expiresAt != null)
        _SummaryRow(
          label: '만료 시각',
          value: intl.DateFormat('yyyy-MM-dd HH:mm').format(result.expiresAt!),
        ),
      if (result.downloadUrl != null)
        _SummaryRow(label: '다운로드 URL', value: result.downloadUrl!.toString()),
      if (result.hasBytes && (result.downloadUrl == null))
        const _SummaryRow(label: '상태', value: '바이너리 응답을 받아 자동 다운로드를 실행했습니다.'),
    ];

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        ...rows,
        const SizedBox(height: 12),
        Wrap(
          spacing: 12,
          runSpacing: 12,
          children: [
            if (result.downloadUrl != null)
              ShadButton(
                onPressed: () => _launchDownloadUrl(result.downloadUrl!),
                leading: const Icon(lucide.LucideIcons.externalLink, size: 16),
                child: const Text('다운로드 열기'),
              ),
            if (result.downloadUrl != null)
              ShadButton.outline(
                onPressed: () => _copyDownloadUrl(result.downloadUrl!),
                leading: const Icon(lucide.LucideIcons.copy, size: 16),
                child: const Text('URL 복사'),
              ),
          ],
        ),
      ],
    );
  }

  @override
  Widget build(BuildContext context) {
    final theme = ShadTheme.of(context);

    return AppLayout(
      title: '보고서',
      subtitle: '조건을 선택해 입·출고와 결재 데이터를 내려받을 수 있도록 준비 중입니다.',
      breadcrumbs: const [
        AppBreadcrumbItem(label: '대시보드', path: dashboardRoutePath),
        AppBreadcrumbItem(label: '보고', path: '/reports'),
        AppBreadcrumbItem(label: '보고서'),
      ],
      actions: [
        ShadButton(
          onPressed: _canExport
              ? () => _handleExport(ReportExportFormat.xlsx)
              : null,
          leading: const Icon(lucide.LucideIcons.fileDown, size: 16),
          child: const Text('XLSX 다운로드'),
        ),
        ShadButton.outline(
          onPressed: _canExport ? _notifyPdfUnavailable : null,
          leading: const Icon(lucide.LucideIcons.fileText, size: 16),
          child: const Text('PDF 다운로드'),
        ),
      ],
      toolbar: FilterBar(
        actionConfig: FilterBarActionConfig(
          onApply: _applyFilters,
          onReset: _resetFilters,
          hasPendingChanges: _hasDirtyFilters,
          hasActiveFilters: _hasAppliedFilters,
        ),
        children: [
          SizedBox(
            width: 220,
            child: SuperportDateRangePickerButton(
              value: _pendingDateRange ?? _appliedDateRange,
              dateFormat: _dateFormat,
              firstDate: DateTime(DateTime.now().year - 5),
              lastDate: DateTime(DateTime.now().year + 2),
              initialDateRange:
                  _pendingDateRange ??
                  _appliedDateRange ??
                  DateTimeRange(
                    start: DateTime.now().subtract(const Duration(days: 6)),
                    end: DateTime.now(),
                  ),
              onChanged: (range) {
                setState(() {
                  _pendingDateRange = range;
                });
              },
            ),
          ),
          SizedBox(
            width: 200,
            child: ShadSelect<ReportTypeFilter>(
              key: ValueKey(_pendingType),
              initialValue: _pendingType,
              selectedOptionBuilder: (context, value) {
                final theme = ShadTheme.of(context);
                if (_lookupError != null) {
                  return Text(
                    _lookupError!,
                    style: theme.textTheme.small.copyWith(
                      color: theme.colorScheme.destructive,
                    ),
                  );
                }
                return Text(value.label);
              },
              onChanged: _isLoadingLookups
                  ? null
                  : (value) {
                      if (value == null) return;
                      setState(() {
                        _pendingType = value;
                      });
                    },
              options: [
                for (final type in ReportTypeFilter.values)
                  ShadOption(value: type, child: Text(type.label)),
              ],
            ),
          ),
          SizedBox(
            width: 220,
            child: ShadSelect<WarehouseFilterOption>(
              key: ValueKey(
                '${_pendingWarehouse.cacheKey}-${_warehouseOptions.length}',
              ),
              initialValue: _pendingWarehouse,
              selectedOptionBuilder: (_, value) => Text(value.label),
              onChanged: (value) {
                if (value == null) return;
                setState(() {
                  _pendingWarehouse = value;
                });
              },
              options: [
                for (final option in _warehouseOptions)
                  ShadOption(value: option, child: Text(option.label)),
              ],
            ),
          ),
          SizedBox(
            width: 200,
            child: ShadSelect<ReportStatusFilter>(
              key: ValueKey(_pendingStatus),
              initialValue: _pendingStatus,
              selectedOptionBuilder: (context, value) {
                final theme = ShadTheme.of(context);
                if (_lookupError != null) {
                  return Text(
                    _lookupError!,
                    style: theme.textTheme.small.copyWith(
                      color: theme.colorScheme.destructive,
                    ),
                  );
                }
                return Text(value.label);
              },
              onChanged: _isLoadingLookups
                  ? null
                  : (value) {
                      if (value == null) return;
                      setState(() {
                        _pendingStatus = value;
                      });
                    },
              options: [
                for (final status in ReportStatusFilter.values)
                  ShadOption(value: status, child: Text(status.label)),
              ],
            ),
          ),
          SizedBox(
            width: 260,
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                Text(
                  '상신자',
                  style: theme.textTheme.small.copyWith(
                    fontWeight: FontWeight.w600,
                  ),
                ),
                const SizedBox(height: 4),
                InventoryEmployeeAutocompleteField(
                  key: ValueKey(_pendingRequester?.id ?? 'none'),
                  controller: _requesterController,
                  initialSuggestion: _pendingRequester,
                  placeholder: '상신자 이름 또는 사번 검색',
                  onSuggestionSelected: (suggestion) {
                    setState(() {
                      _pendingRequester = suggestion;
                    });
                  },
                  onChanged: () {
                    if (_requesterController.text.trim().isEmpty &&
                        _pendingRequester != null) {
                      setState(() {
                        _pendingRequester = null;
                      });
                    }
                  },
                ),
              ],
            ),
          ),
        ],
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          if (_warehouseError != null)
            Padding(
              padding: const EdgeInsets.only(bottom: 16),
              child: Row(
                children: [
                  Icon(
                    lucide.LucideIcons.circleAlert,
                    size: 16,
                    color: theme.colorScheme.destructive,
                  ),
                  const SizedBox(width: 8),
                  Expanded(
                    child: Text(
                      _warehouseError!,
                      style: theme.textTheme.small.copyWith(
                        color: theme.colorScheme.destructive,
                      ),
                    ),
                  ),
                  const SizedBox(width: 8),
                  ShadButton.ghost(
                    onPressed: _isLoadingWarehouses ? null : _loadWarehouses,
                    leading: const Icon(lucide.LucideIcons.refreshCw, size: 16),
                    child: const Text('재시도'),
                  ),
                ],
              ),
            )
          else if (_isLoadingWarehouses)
            Padding(
              padding: const EdgeInsets.only(bottom: 16),
              child: Row(
                children: const [
                  SuperportSkeleton(width: 180, height: 20),
                  SizedBox(width: 12),
                  SuperportSkeleton(width: 140, height: 20),
                  SizedBox(width: 12),
                  SuperportSkeleton(width: 120, height: 20),
                ],
              ),
            ),
          ShadCard(
            title: Text('선택된 조건', style: theme.textTheme.h3),
            description: Text(
              '다운로드 전 사용자 조건을 빠르게 검토하세요.',
              style: theme.textTheme.muted,
            ),
            child: Column(
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                _SummaryRow(
                  label: '기간',
                  value: _appliedDateRange == null
                      ? '기간을 선택하세요.'
                      : _dateRangeLabel(_appliedDateRange),
                ),
                _SummaryRow(label: '유형', value: _appliedType.label),
                _SummaryRow(label: '창고', value: _appliedWarehouse.label),
                _SummaryRow(label: '상태', value: _appliedStatus.label),
                _SummaryRow(
                  label: '상신자',
                  value: _requesterLabel(_appliedRequester),
                ),
                if (!_canExport)
                  Padding(
                    padding: const EdgeInsets.only(top: 12),
                    child: Text(
                      '기간과 유형을 선택하면 다운로드 버튼이 활성화됩니다.',
                      style: theme.textTheme.small.copyWith(
                        color: theme.colorScheme.mutedForeground,
                      ),
                    ),
                  ),
              ],
            ),
          ),
          const SizedBox(height: 24),
          ShadCard(
            title: Text('보고서 미리보기', style: theme.textTheme.h3),
            description: Text(
              '다운로드 상태와 결과 요약을 확인하세요.',
              style: theme.textTheme.muted,
            ),
            child: AnimatedSize(
              duration: const Duration(milliseconds: 200),
              curve: Curves.easeOut,
              child: ConstrainedBox(
                constraints: const BoxConstraints(minHeight: 200),
                child: Padding(
                  padding: const EdgeInsets.symmetric(vertical: 8),
                  child: _buildPreview(theme),
                ),
              ),
            ),
          ),
        ],
      ),
    );
  }
}

class _SummaryRow extends StatelessWidget {
  const _SummaryRow({required this.label, required this.value});

  final String label;
  final String value;

  @override
  Widget build(BuildContext context) {
    final theme = ShadTheme.of(context);
    return Padding(
      padding: const EdgeInsets.symmetric(vertical: 6),
      child: Row(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          SizedBox(
            width: 72,
            child: Text(
              label,
              style: theme.textTheme.small.copyWith(
                fontWeight: FontWeight.w600,
              ),
            ),
          ),
          const SizedBox(width: 12),
          Expanded(child: Text(value, style: theme.textTheme.p)),
        ],
      ),
    );
  }
}

enum ReportTypeFilter { all, inbound, outbound, rental, approval }

extension ReportTypeFilterX on ReportTypeFilter {
  String get label {
    switch (this) {
      case ReportTypeFilter.all:
        return '전체 유형';
      case ReportTypeFilter.inbound:
        return '입고';
      case ReportTypeFilter.outbound:
        return '출고';
      case ReportTypeFilter.rental:
        return '대여';
      case ReportTypeFilter.approval:
        return '결재';
    }
  }
}

enum ReportStatusFilter { all, inProgress, completed, cancelled }

extension ReportStatusFilterX on ReportStatusFilter {
  String get label {
    switch (this) {
      case ReportStatusFilter.all:
        return '전체 상태';
      case ReportStatusFilter.inProgress:
        return '진행중';
      case ReportStatusFilter.completed:
        return '완료';
      case ReportStatusFilter.cancelled:
        return '취소';
    }
  }
}

class WarehouseFilterOption {
  const WarehouseFilterOption({this.id, required this.label});

  final int? id;
  final String label;

  static const WarehouseFilterOption all = WarehouseFilterOption(
    id: null,
    label: '전체 창고',
  );

  factory WarehouseFilterOption.fromWarehouse(Warehouse warehouse) {
    final id = warehouse.id;
    final name = warehouse.warehouseName;
    final code = warehouse.warehouseCode;
    return WarehouseFilterOption(
      id: id,
      label: id == null ? name : '$name ($code)',
    );
  }

  String get cacheKey => id?.toString() ?? label;

  @override
  bool operator ==(Object other) {
    if (identical(this, other)) {
      return true;
    }
    if (other is! WarehouseFilterOption) {
      return false;
    }
    if (id != null && other.id != null) {
      return id == other.id;
    }
    return label == other.label;
  }

  @override
  int get hashCode => cacheKey.hashCode;
}
