import 'dart:async';

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

import 'superport_dialog.dart';

/// 엔티티 상세 정보를 탭 또는 단일 영역으로 보여주는 다이얼로그 전용 섹션 정의이다.
class SuperportDetailDialogSection {
  const SuperportDetailDialogSection({
    this.key,
    required this.id,
    required this.label,
    required this.builder,
    this.icon,
    this.badge,
    this.scrollable = true,
  });

  /// 탭 식별자. 초기 탭 선택에 사용된다.
  final String id;

  /// 탭 라벨에 사용될 텍스트.
  final String label;

  /// 섹션 컨텐츠를 생성하는 빌더.
  final WidgetBuilder builder;

  /// 라벨 좌측에 배치할 아이콘.
  final IconData? icon;

  /// 라벨 우측에 배치할 보조 배지 위젯.
  final Widget? badge;

  /// `true`면 섹션이 자체 스크롤 뷰를 생성한다.
  final bool scrollable;

  /// 탭 버튼에 부여할 키.
  final Key? key;
}

/// 상세 요약을 표 형식으로 표현할 때 사용하는 메타 필드 정의이다.
class SuperportDetailMetadata {
  const SuperportDetailMetadata({
    required this.label,
    required this.value,
    this.icon,
  });

  /// 항목 이름.
  final String label;

  /// 값 영역에 들어갈 위젯. 기본 텍스트는 [SuperportDetailMetadata.text] 팩토리로 생성한다.
  final Widget value;

  /// 값 좌측에 배치할 아이콘.
  final IconData? icon;

  /// 간단한 문자열 값을 텍스트 위젯으로 감싼 메타데이터 팩토리이다.
  factory SuperportDetailMetadata.text({
    required String label,
    required String value,
    IconData? icon,
    String? tooltip,
    TextStyle? style,
    TextAlign textAlign = TextAlign.start,
  }) {
    final text = Text(value, textAlign: textAlign, style: style);

    final widget = tooltip == null
        ? text
        : Tooltip(message: tooltip, child: text);

    return SuperportDetailMetadata(label: label, value: widget, icon: icon);
  }
}

/// 상세 다이얼로그 본문을 구성하는 레이아웃 위젯이다.
class SuperportDetailDialog extends StatelessWidget {
  const SuperportDetailDialog({
    super.key,
    required this.sections,
    this.summary,
    this.metadata = const [],
    this.summaryBadges = const [],
    this.emptyPlaceholder,
    this.initialSectionId,
    this.initialSectionIndex = 0,
    this.summaryPadding = const EdgeInsets.only(bottom: 16),
    this.metadataPadding = EdgeInsets.zero,
    this.infoPanelPadding = const EdgeInsets.only(bottom: 24),
    this.sectionPadding = const EdgeInsets.symmetric(vertical: 4),
    this.metadataColumns = 2,
  });

  /// 표시할 섹션 목록.
  final List<SuperportDetailDialogSection> sections;

  /// 상단 개요 블록. 이름/설명 등 자유롭게 구성한다.
  final Widget? summary;

  /// 요약 우측 또는 하단에 배치할 배지 목록.
  final List<Widget> summaryBadges;

  /// 개요 하단에 정렬되는 메타 정보 모음.
  final List<SuperportDetailMetadata> metadata;

  /// 섹션 데이터가 없을 때 출력할 플레이스홀더.
  final Widget? emptyPlaceholder;

  /// 최초로 선택할 섹션 ID.
  final String? initialSectionId;

  /// ID가 없을 때 사용할 기본 인덱스.
  final int initialSectionIndex;

  /// 요약 영역 패딩.
  final EdgeInsetsGeometry summaryPadding;

  /// 메타데이터 영역 패딩.
  final EdgeInsetsGeometry metadataPadding;

  /// summary+metadata 정보 블록 외부 패딩.
  final EdgeInsetsGeometry infoPanelPadding;

  /// 섹션 컨텐츠 패딩.
  final EdgeInsetsGeometry sectionPadding;

  /// metadata를 배치할 기본 열 수. 가로폭이 좁으면 자동으로 1열로 조정된다.
  final int metadataColumns;

  @override
  Widget build(BuildContext context) {
    final theme = ShadTheme.of(context);
    return LayoutBuilder(
      builder: (context, constraints) {
        final children = <Widget>[];

        final hasInfoPanel =
            summary != null || summaryBadges.isNotEmpty || metadata.isNotEmpty;

        if (hasInfoPanel) {
          children.add(
            Padding(
              padding: infoPanelPadding,
              child: _InfoPanel(
                summary: summary,
                summaryBadges: summaryBadges,
                metadata: metadata,
                summaryPadding: summaryPadding,
                metadataPadding: metadataPadding,
                metadataColumns: metadataColumns,
              ),
            ),
          );
        }

        final sectionContent = sections.isEmpty
            ? Center(
                child:
                    emptyPlaceholder ??
                    Text(
                      '표시할 세부 정보가 없습니다.',
                      style: theme.textTheme.muted,
                      textAlign: TextAlign.center,
                    ),
              )
            : sections.length == 1
            ? _SectionPane(section: sections.first, padding: sectionPadding)
            : _TabbedSections(
                sections: sections,
                initialSectionId: initialSectionId,
                initialSectionIndex: initialSectionIndex,
                padding: sectionPadding,
              );

        children.add(sectionContent);

        return Column(
          crossAxisAlignment: CrossAxisAlignment.stretch,
          children: children,
        );
      },
    );
  }
}

/// Superport 스타일 상세 다이얼로그를 표시하는 편의 함수이다.
Future<T?> showSuperportDetailDialog<T>({
  required BuildContext context,
  required String title,
  List<SuperportDetailDialogSection> sections = const [],
  Widget? summary,
  List<Widget> summaryBadges = const [],
  List<SuperportDetailMetadata> metadata = const [],
  Widget? emptyPlaceholder,
  String? description,
  List<Widget> actions = const [],
  bool barrierDismissible = true,
  bool mobileFullscreen = true,
  BoxConstraints? constraints,
  EdgeInsetsGeometry? contentPadding,
  EdgeInsetsGeometry infoPanelPadding = const EdgeInsets.only(bottom: 24),
  int metadataColumns = 2,
  String? initialSectionId,
  int initialSectionIndex = 0,
  FutureOr<void> Function()? onSubmit,
  VoidCallback? onClose,
  bool showCloseButton = true,
  bool enableFocusTrap = true,
  List<Widget>? headerActions,
}) {
  return showSuperportDialog<T>(
    context: context,
    title: title,
    description: description,
    body: SuperportDetailDialog(
      sections: sections,
      summary: summary,
      summaryBadges: summaryBadges,
      metadata: metadata,
      emptyPlaceholder: emptyPlaceholder,
      initialSectionId: initialSectionId,
      initialSectionIndex: initialSectionIndex,
      infoPanelPadding: infoPanelPadding,
      metadataColumns: metadataColumns,
    ),
    actions: actions,
    barrierDismissible: barrierDismissible,
    mobileFullscreen: mobileFullscreen,
    constraints:
        constraints ?? const BoxConstraints(maxWidth: 720, minHeight: 320),
    contentPadding:
        contentPadding ??
        const EdgeInsets.symmetric(horizontal: 24, vertical: 20),
    scrollable: true,
    onSubmit: onSubmit,
    onClose: onClose,
    showCloseButton: showCloseButton,
    enableFocusTrap: enableFocusTrap,
    headerActions: headerActions,
  );
}

class _InfoPanel extends StatelessWidget {
  const _InfoPanel({
    required this.summary,
    required this.summaryBadges,
    required this.metadata,
    required this.summaryPadding,
    required this.metadataPadding,
    required this.metadataColumns,
  });

  final Widget? summary;
  final List<Widget> summaryBadges;
  final List<SuperportDetailMetadata> metadata;
  final EdgeInsetsGeometry summaryPadding;
  final EdgeInsetsGeometry metadataPadding;
  final int metadataColumns;

  @override
  Widget build(BuildContext context) {
    final hasSummary = summary != null || summaryBadges.isNotEmpty;
    final hasMetadata = metadata.isNotEmpty;
    final columnChildren = <Widget>[];

    if (hasSummary) {
      columnChildren.add(
        Padding(
          padding: summaryPadding,
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              if (summary != null) summary!,
              if (summary != null && summaryBadges.isNotEmpty)
                const SizedBox(height: 12),
              if (summaryBadges.isNotEmpty)
                Wrap(spacing: 8, runSpacing: 8, children: summaryBadges),
            ],
          ),
        ),
      );
    }

    if (hasSummary && hasMetadata) {
      columnChildren.add(const SizedBox(height: 12));
    }

    if (hasMetadata) {
      columnChildren.add(
        Padding(
          padding: metadataPadding,
          child: _MetadataGrid(metadata: metadata, columns: metadataColumns),
        ),
      );
    }

    return ShadCard(
      padding: const EdgeInsets.all(20),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.stretch,
        children: columnChildren,
      ),
    );
  }
}

class _MetadataGrid extends StatelessWidget {
  const _MetadataGrid({required this.metadata, required this.columns});

  final List<SuperportDetailMetadata> metadata;
  final int columns;

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

    return LayoutBuilder(
      builder: (context, constraints) {
        final mediaWidth = MediaQuery.of(context).size.width;
        final maxWidth = constraints.maxWidth.isFinite
            ? constraints.maxWidth
            : mediaWidth;
        final normalizedColumns = columns <= 0 ? 1 : columns;
        final maxColumns = metadata.isEmpty ? 1 : metadata.length;
        final targetColumns = (normalizedColumns.clamp(1, maxColumns)).toInt();
        final resolvedColumns = maxWidth < 520 ? 1 : targetColumns;
        final spacing = resolvedColumns == 1 ? 0.0 : 16.0;
        final tileWidth = resolvedColumns == 1
            ? maxWidth
            : (maxWidth - spacing * (resolvedColumns - 1)) / resolvedColumns;

        return Wrap(
          spacing: 16,
          runSpacing: 12,
          children: metadata
              .map(
                (item) => SizedBox(
                  width: resolvedColumns == 1 ? maxWidth : tileWidth,
                  child: _MetadataTile(item: item, theme: theme),
                ),
              )
              .toList(),
        );
      },
    );
  }
}

class _MetadataTile extends StatelessWidget {
  const _MetadataTile({required this.item, required this.theme});

  final SuperportDetailMetadata item;
  final ShadThemeData theme;

  @override
  Widget build(BuildContext context) {
    final labelStyle = theme.textTheme.small.copyWith(
      fontWeight: FontWeight.w600,
      color: theme.colorScheme.mutedForeground,
    );

    final valueStyle = theme.textTheme.small;

    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Row(
          crossAxisAlignment: CrossAxisAlignment.center,
          children: [
            if (item.icon != null)
              Padding(
                padding: const EdgeInsets.only(right: 6),
                child: Icon(
                  item.icon,
                  size: 16,
                  color: theme.colorScheme.mutedForeground,
                ),
              ),
            Flexible(child: Text(item.label, style: labelStyle)),
          ],
        ),
        const SizedBox(height: 4),
        DefaultTextStyle.merge(style: valueStyle, child: item.value),
      ],
    );
  }
}

class _SectionPane extends StatefulWidget {
  const _SectionPane({required this.section, required this.padding});

  final SuperportDetailDialogSection section;
  final EdgeInsetsGeometry padding;

  @override
  State<_SectionPane> createState() => _SectionPaneState();
}

class _SectionPaneState extends State<_SectionPane> {
  ScrollController? _controller;

  @override
  void initState() {
    super.initState();
    if (widget.section.scrollable) {
      _controller = ScrollController();
    }
  }

  @override
  void didUpdateWidget(covariant _SectionPane oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.section.scrollable && _controller == null) {
      _controller = ScrollController();
    } else if (!widget.section.scrollable && _controller != null) {
      _controller!.dispose();
      _controller = null;
    }
  }

  @override
  void dispose() {
    _controller?.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final content = Padding(
      padding: widget.padding,
      child: widget.section.builder(context),
    );

    if (!widget.section.scrollable) {
      return content;
    }

    final controller = _controller ??= ScrollController();

    return Scrollbar(
      controller: controller,
      thumbVisibility: true,
      child: SingleChildScrollView(
        controller: controller,
        primary: false,
        padding: const EdgeInsets.only(right: 4),
        physics: const ClampingScrollPhysics(),
        child: content,
      ),
    );
  }
}

class _TabbedSections extends StatefulWidget {
  const _TabbedSections({
    required this.sections,
    required this.initialSectionId,
    required this.initialSectionIndex,
    required this.padding,
  });

  final List<SuperportDetailDialogSection> sections;
  final String? initialSectionId;
  final int initialSectionIndex;
  final EdgeInsetsGeometry padding;

  @override
  State<_TabbedSections> createState() => _TabbedSectionsState();
}

class _TabbedSectionsState extends State<_TabbedSections> {
  late ShadTabsController<String> _controller;

  @override
  void initState() {
    super.initState();
    _controller = ShadTabsController<String>(value: _resolveInitialSectionId());
  }

  @override
  void didUpdateWidget(covariant _TabbedSections oldWidget) {
    super.didUpdateWidget(oldWidget);
    if (widget.sections.isEmpty) {
      return;
    }

    final selected = _controller.selected;
    final exists = widget.sections.any((section) => section.id == selected);
    if (!exists) {
      _controller.select(_resolveInitialSectionId());
      return;
    }

    final nextInitial = widget.initialSectionId;
    if (nextInitial != null && nextInitial != oldWidget.initialSectionId) {
      final hasTarget = widget.sections.any(
        (section) => section.id == nextInitial,
      );
      if (hasTarget) {
        _controller.select(nextInitial);
      }
    }
  }

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

  @override
  Widget build(BuildContext context) {
    return ShadTabs<String>(
      controller: _controller,
      expandContent: false,
      gap: 12,
      tabs: widget.sections
          .map(
            (section) => ShadTab<String>(
              key: section.key,
              value: section.id,
              content: _SectionPane(section: section, padding: widget.padding),
              child: Row(
                mainAxisSize: MainAxisSize.min,
                children: [
                  if (section.icon != null)
                    Padding(
                      padding: const EdgeInsets.only(right: 6),
                      child: Icon(section.icon, size: 16),
                    ),
                  Text(section.label),
                  if (section.badge != null) ...[
                    const SizedBox(width: 6),
                    section.badge!,
                  ],
                ],
              ),
            ),
          )
          .toList(),
    );
  }

  String _resolveInitialSectionId() {
    if (widget.sections.isEmpty) {
      return '';
    }

    if (widget.initialSectionId != null) {
      final match = widget.sections.firstWhere(
        (section) => section.id == widget.initialSectionId,
        orElse: () => widget.sections.first,
      );
      return match.id;
    }

    final index = widget.initialSectionIndex.clamp(
      0,
      widget.sections.length - 1,
    );
    return widget.sections[index].id;
  }
}
