import 'dart:async';

import 'package:flutter/material.dart';
import 'package:intl/intl.dart' as intl;
import 'package:shadcn_ui/shadcn_ui.dart';

import '../../../../../widgets/components/superport_detail_dialog.dart';
import '../../domain/entities/menu.dart';

/// 메뉴 상세 다이얼로그에서 발생한 액션 종류이다.
enum MenuDetailDialogAction { created, updated, deleted, restored }

/// 메뉴 상세 다이얼로그 결과를 표현한다.
class MenuDetailDialogResult {
  const MenuDetailDialogResult({required this.action, required this.message});

  final MenuDetailDialogAction action;
  final String message;
}

typedef MenuCreateCallback = Future<MenuItem?> Function(MenuInput input);
typedef MenuUpdateCallback =
    Future<MenuItem?> Function(int id, MenuInput input);
typedef MenuDeleteCallback = Future<bool> Function(int id);
typedef MenuRestoreCallback = Future<MenuItem?> Function(int id);

/// 메뉴 상세 다이얼로그를 띄워 CRUD 플로우를 통합한다.
Future<MenuDetailDialogResult?> showMenuDetailDialog({
  required BuildContext context,
  required intl.DateFormat dateFormat,
  MenuItem? menu,
  required List<MenuItem> parents,
  required bool isLoadingParents,
  required MenuCreateCallback onCreate,
  required MenuUpdateCallback onUpdate,
  required MenuDeleteCallback onDelete,
  required MenuRestoreCallback onRestore,
}) {
  final menuValue = menu;
  final isEdit = menuValue != null;
  final title = isEdit ? '메뉴 상세' : '메뉴 등록';
  final description = isEdit
      ? '메뉴 계층과 경로, 권한 관련 메타데이터를 확인합니다.'
      : '신규 메뉴를 등록할 정보를 입력하세요.';
  final parentLabel = menuValue?.parent?.menuName ?? '최상위';

  return showSuperportDetailDialog<MenuDetailDialogResult>(
    context: context,
    title: title,
    description: description,
    summary: menuValue == null
        ? null
        : Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                menuValue.menuName,
                style: ShadTheme.of(context).textTheme.h4,
              ),
              const SizedBox(height: 4),
              Text(
                menuValue.path?.isEmpty ?? true ? '경로 없음' : menuValue.path!,
                style: ShadTheme.of(context).textTheme.muted,
              ),
            ],
          ),
    summaryBadges: menuValue == null
        ? const []
        : [
            ShadBadge.outline(child: Text('상위: $parentLabel')),
            if (menuValue.isActive)
              const ShadBadge(child: Text('사용중'))
            else
              const ShadBadge.outline(child: Text('미사용')),
            if (menuValue.isDeleted)
              const ShadBadge.destructive(child: Text('삭제됨')),
          ],
    metadata: menuValue == null
        ? const []
        : [
            SuperportDetailMetadata.text(
              label: 'ID',
              value: menuValue.id?.toString() ?? '-',
            ),
            SuperportDetailMetadata.text(
              label: '메뉴코드',
              value: menuValue.menuCode,
            ),
            SuperportDetailMetadata.text(
              label: '표시순서',
              value: menuValue.displayOrder?.toString() ?? '-',
            ),
            SuperportDetailMetadata.text(
              label: '비고',
              value: menuValue.note?.isEmpty ?? true ? '-' : menuValue.note!,
            ),
            SuperportDetailMetadata.text(
              label: '생성일시',
              value: menuValue.createdAt == null
                  ? '-'
                  : dateFormat.format(menuValue.createdAt!.toLocal()),
            ),
            SuperportDetailMetadata.text(
              label: '변경일시',
              value: menuValue.updatedAt == null
                  ? '-'
                  : dateFormat.format(menuValue.updatedAt!.toLocal()),
            ),
          ],
    sections: [
      _MenuEditSection(
        id: isEdit ? _MenuDetailSections.edit : _MenuDetailSections.create,
        label: isEdit ? '수정' : '등록',
        menu: menuValue,
        parents: parents,
        isLoadingParents: isLoadingParents,
        onSubmit: (input) async {
          if (menuValue == null) {
            final created = await onCreate(input);
            if (created == null) {
              return null;
            }
            return const MenuDetailDialogResult(
              action: MenuDetailDialogAction.created,
              message: '메뉴를 등록했습니다.',
            );
          }
          final menuId = menuValue.id;
          if (menuId == null) {
            return null;
          }
          final updated = await onUpdate(menuId, input);
          if (updated == null) {
            return null;
          }
          return const MenuDetailDialogResult(
            action: MenuDetailDialogAction.updated,
            message: '메뉴를 수정했습니다.',
          );
        },
      ),
      if (menuValue != null)
        SuperportDetailDialogSection(
          id: menuValue.isDeleted
              ? _MenuDetailSections.restore
              : _MenuDetailSections.delete,
          label: menuValue.isDeleted ? '복구' : '삭제',
          icon: menuValue.isDeleted ? LucideIcons.history : LucideIcons.trash2,
          builder: (_) => _MenuDangerSection(
            menu: menuValue,
            onDelete: () async {
              final menuId = menuValue.id;
              if (menuId == null) {
                return null;
              }
              final success = await onDelete(menuId);
              if (!success) {
                return null;
              }
              return const MenuDetailDialogResult(
                action: MenuDetailDialogAction.deleted,
                message: '메뉴를 삭제했습니다.',
              );
            },
            onRestore: () async {
              final menuId = menuValue.id;
              if (menuId == null) {
                return null;
              }
              final restored = await onRestore(menuId);
              if (restored == null) {
                return null;
              }
              return const MenuDetailDialogResult(
                action: MenuDetailDialogAction.restored,
                message: '메뉴를 복구했습니다.',
              );
            },
          ),
        ),
    ],
    emptyPlaceholder: const Text('표시할 메뉴 정보가 없습니다.'),
    initialSectionId: menuValue == null
        ? _MenuDetailSections.create
        : _MenuDetailSections.edit,
  );
}

/// 메뉴 상세 다이얼로그 섹션 식별자 모음이다.
class _MenuDetailSections {
  static const edit = 'edit';
  static const delete = 'delete';
  static const restore = 'restore';
  static const create = 'create';
}

/// 메뉴 입력 섹션을 정의한다.
class _MenuEditSection extends SuperportDetailDialogSection {
  _MenuEditSection({
    required super.id,
    required super.label,
    required MenuItem? menu,
    required List<MenuItem> parents,
    required bool isLoadingParents,
    required Future<MenuDetailDialogResult?> Function(MenuInput input) onSubmit,
  }) : super(
         icon: LucideIcons.pencil,
         builder: (context) => _MenuForm(
           menu: menu,
           parents: parents,
           isLoadingParents: isLoadingParents,
           onSubmit: onSubmit,
         ),
       );
}

/// 메뉴 삭제/복구 경고 및 실행을 담당한다.
class _MenuDangerSection extends StatelessWidget {
  const _MenuDangerSection({
    required this.menu,
    required this.onDelete,
    required this.onRestore,
  });

  final MenuItem menu;
  final Future<MenuDetailDialogResult?> Function() onDelete;
  final Future<MenuDetailDialogResult?> Function() onRestore;

  @override
  Widget build(BuildContext context) {
    final theme = ShadTheme.of(context);
    final description = menu.isDeleted
        ? '복구하면 메뉴가 다시 탐색 트리에 노출됩니다.'
        : '삭제하면 메뉴가 숨겨지지만 하위 데이터는 유지됩니다.';

    return Padding(
      padding: const EdgeInsets.only(top: 8),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text(description, style: theme.textTheme.small),
          const SizedBox(height: 16),
          if (menu.isDeleted)
            ShadButton(
              onPressed: () async {
                final navigator = Navigator.of(context, rootNavigator: true);
                final result = await onRestore();
                if (result != null && navigator.mounted) {
                  navigator.pop(result);
                }
              },
              child: const Text('복구'),
            )
          else
            ShadButton.destructive(
              onPressed: () async {
                final navigator = Navigator.of(context, rootNavigator: true);
                final result = await onDelete();
                if (result != null && navigator.mounted) {
                  navigator.pop(result);
                }
              },
              child: const Text('삭제'),
            ),
        ],
      ),
    );
  }
}

/// 메뉴 입력 폼을 구성하는 위젯이다.
class _MenuForm extends StatefulWidget {
  const _MenuForm({
    required this.menu,
    required this.parents,
    required this.isLoadingParents,
    required this.onSubmit,
  });

  final MenuItem? menu;
  final List<MenuItem> parents;
  final bool isLoadingParents;
  final Future<MenuDetailDialogResult?> Function(MenuInput input) onSubmit;

  bool get _isEdit => menu != null;

  @override
  State<_MenuForm> createState() => _MenuFormState();
}

class _MenuFormState extends State<_MenuForm> {
  late final TextEditingController _codeController;
  late final TextEditingController _nameController;
  late final TextEditingController _pathController;
  late final TextEditingController _orderController;
  late final TextEditingController _noteController;
  late bool _isActive;
  int? _selectedParent;
  String? _codeError;
  String? _nameError;
  String? _orderError;
  String? _submitError;
  bool _isSubmitting = false;

  bool get _isEdit => widget._isEdit;

  @override
  void initState() {
    super.initState();
    final menu = widget.menu;
    _codeController = TextEditingController(text: menu?.menuCode ?? '');
    _nameController = TextEditingController(text: menu?.menuName ?? '');
    _pathController = TextEditingController(text: menu?.path ?? '');
    _orderController = TextEditingController(
      text: menu?.displayOrder?.toString() ?? '',
    );
    _noteController = TextEditingController(text: menu?.note ?? '');
    _isActive = menu?.isActive ?? true;
    _selectedParent = menu?.parent?.id;
  }

  @override
  void dispose() {
    _codeController.dispose();
    _nameController.dispose();
    _pathController.dispose();
    _orderController.dispose();
    _noteController.dispose();
    super.dispose();
  }

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

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        _MenuFormField(
          label: '메뉴코드',
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              ShadInput(
                controller: _codeController,
                readOnly: _isEdit,
                onChanged: (_) {
                  if (_codeController.text.trim().isNotEmpty) {
                    setState(() {
                      _codeError = null;
                    });
                  }
                },
              ),
              if (_codeError != null)
                Padding(
                  padding: const EdgeInsets.only(top: 6),
                  child: Text(
                    _codeError!,
                    style: theme.textTheme.small.copyWith(
                      color: theme.colorScheme.destructive,
                    ),
                  ),
                ),
            ],
          ),
        ),
        const SizedBox(height: 16),
        _MenuFormField(
          label: '메뉴명',
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              ShadInput(
                controller: _nameController,
                onChanged: (_) {
                  if (_nameController.text.trim().isNotEmpty) {
                    setState(() {
                      _nameError = null;
                    });
                  }
                },
              ),
              if (_nameError != null)
                Padding(
                  padding: const EdgeInsets.only(top: 6),
                  child: Text(
                    _nameError!,
                    style: theme.textTheme.small.copyWith(
                      color: theme.colorScheme.destructive,
                    ),
                  ),
                ),
            ],
          ),
        ),
        const SizedBox(height: 16),
        _MenuFormField(
          label: '상위메뉴',
          child: ShadSelect<int?>(
            initialValue: _selectedParent,
            placeholder: Text(widget.isLoadingParents ? '상위 로딩중...' : '최상위'),
            selectedOptionBuilder: (_, value) {
              if (value == null) {
                return Text(widget.isLoadingParents ? '상위 로딩중...' : '최상위');
              }
              final menu = widget.parents.firstWhere(
                (item) => item.id == value,
                orElse: () => MenuItem(id: value, menuCode: '', menuName: ''),
              );
              final label = menu.menuName.isEmpty ? '최상위' : menu.menuName;
              return Text(label);
            },
            onChanged: _isSubmitting || widget.isLoadingParents
                ? null
                : (next) {
                    setState(() {
                      _selectedParent = next;
                    });
                  },
            options: [
              const ShadOption<int?>(value: null, child: Text('최상위')),
              ...widget.parents
                  .where((item) => item.id != widget.menu?.id)
                  .map(
                    (item) => ShadOption<int?>(
                      value: item.id,
                      child: Text(item.menuName),
                    ),
                  ),
            ],
          ),
        ),
        const SizedBox(height: 16),
        _MenuFormField(
          label: '경로',
          child: ShadInput(controller: _pathController),
        ),
        const SizedBox(height: 16),
        _MenuFormField(
          label: '표시순서',
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              ShadInput(
                controller: _orderController,
                keyboardType: TextInputType.number,
              ),
              if (_orderError != null)
                Padding(
                  padding: const EdgeInsets.only(top: 6),
                  child: Text(
                    _orderError!,
                    style: theme.textTheme.small.copyWith(
                      color: theme.colorScheme.destructive,
                    ),
                  ),
                ),
            ],
          ),
        ),
        const SizedBox(height: 16),
        _MenuFormField(
          label: '사용 여부',
          child: Row(
            children: [
              ShadSwitch(
                value: _isActive,
                onChanged: _isSubmitting
                    ? null
                    : (next) {
                        setState(() {
                          _isActive = next;
                        });
                      },
              ),
              const SizedBox(width: 8),
              Text(_isActive ? '사용' : '미사용'),
            ],
          ),
        ),
        const SizedBox(height: 16),
        _MenuFormField(
          label: '비고',
          child: ShadTextarea(
            controller: _noteController,
            minHeight: 96,
            maxHeight: 220,
          ),
        ),
        if (_submitError != null) ...[
          const SizedBox(height: 16),
          Text(
            _submitError!,
            style: theme.textTheme.small.copyWith(
              color: theme.colorScheme.destructive,
            ),
          ),
        ],
        const SizedBox(height: 20),
        Align(
          alignment: Alignment.centerRight,
          child: ShadButton(
            onPressed: _isSubmitting ? null : _handleSubmit,
            child: Text(_isEdit ? '저장' : '등록'),
          ),
        ),
      ],
    );
  }

  Future<void> _handleSubmit() async {
    final code = _codeController.text.trim();
    final name = _nameController.text.trim();
    final orderText = _orderController.text.trim();

    int? orderValue;
    if (orderText.isNotEmpty) {
      orderValue = int.tryParse(orderText);
    }

    setState(() {
      _codeError = code.isEmpty ? '메뉴코드를 입력하세요.' : null;
      _nameError = name.isEmpty ? '메뉴명을 입력하세요.' : null;
      _orderError = orderText.isEmpty || orderValue != null
          ? null
          : '표시순서는 숫자여야 합니다.';
      _submitError = null;
    });

    if (_codeError != null || _nameError != null || _orderError != null) {
      return;
    }

    setState(() {
      _isSubmitting = true;
    });

    final path = _pathController.text.trim();
    final note = _noteController.text.trim();
    final input = MenuInput(
      menuCode: code,
      menuName: name,
      parentMenuId: _selectedParent,
      path: path.isEmpty ? null : path,
      displayOrder: orderValue,
      isActive: _isActive,
      note: note.isEmpty ? null : note,
    );
    final navigator = Navigator.of(context, rootNavigator: true);
    final result = await widget.onSubmit(input);

    if (!mounted) {
      return;
    }

    setState(() {
      _isSubmitting = false;
      _submitError = result == null ? '요청 처리에 실패했습니다.' : null;
    });

    if (result != null && navigator.mounted) {
      navigator.pop(result);
    }
  }
}

/// 메뉴 폼 필드 레이아웃을 제공한다.
class _MenuFormField extends StatelessWidget {
  const _MenuFormField({required this.label, required this.child});

  final String label;
  final Widget child;

  @override
  Widget build(BuildContext context) {
    final theme = ShadTheme.of(context);
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text(label, style: theme.textTheme.small),
        const SizedBox(height: 6),
        child,
      ],
    );
  }
}

/// 개요 섹션에서 사용하는 키-값 구조체이다.
