import 'dart:math' as math;

import 'package:flutter/material.dart';
import 'package:lucide_icons_flutter/lucide_icons.dart' as lucide;
import 'package:shadcn_ui/shadcn_ui.dart';
import 'package:superport_v2/widgets/components/superport_pagination_controls.dart';

/// 테이블 정렬 상태 정보를 보관하는 모델.
class SuperportTableSortState {
  const SuperportTableSortState({
    required this.columnIndex,
    required this.ascending,
  });

  /// 정렬 대상이 되는 컬럼 인덱스.
  final int columnIndex;

  /// 오름차순 여부. `false`면 내림차순이다.
  final bool ascending;
}

/// 테이블 페이지네이션 정보를 보관하는 모델.
class SuperportTablePagination {
  const SuperportTablePagination({
    required this.currentPage,
    required this.totalPages,
    required this.totalItems,
    required this.pageSize,
    this.pageSizeOptions = const <int>[10, 20, 50],
  });

  /// 현재 페이지 번호(1-base).
  final int currentPage;

  /// 전체 페이지 수.
  final int totalPages;

  /// 전체 데이터 건수.
  final int totalItems;

  /// 현재 페이지네이션에서 선택된 페이지 크기.
  final int pageSize;

  /// 사용자에게 노출할 페이지 크기 옵션 목록.
  final List<int> pageSizeOptions;
}

/// ShadTable.list를 감싼 공통 테이블 래퍼.
class SuperportTable extends StatelessWidget {
  const SuperportTable({
    super.key,
    required List<Widget> columns,
    required List<List<Widget>> rows,
    this.columnSpanExtent,
    this.rowHeight = 56,
    this.maxHeight,
    this.onRowTap,
    this.emptyLabel = '데이터가 없습니다.',
    this.sortableColumns,
    this.sortState,
    this.onSortChanged,
    this.pagination,
    this.onPageChange,
    this.onPageSizeChange,
    this.isLoading = false,
  }) : _columns = columns,
       _rows = rows,
       _headerCells = null,
       _rowCells = null;

  /// 헤더와 행을 [ShadTableCell] 단위로 직접 전달할 때 사용하는 생성자.
  const SuperportTable.fromCells({
    super.key,
    required List<ShadTableCell> header,
    required List<List<ShadTableCell>> rows,
    this.columnSpanExtent,
    this.rowHeight = 56,
    this.maxHeight,
    this.onRowTap,
    this.emptyLabel = '데이터가 없습니다.',
    this.sortableColumns,
    this.sortState,
    this.onSortChanged,
    this.pagination,
    this.onPageChange,
    this.onPageSizeChange,
    this.isLoading = false,
  }) : _columns = null,
       _rows = null,
       _headerCells = header,
       _rowCells = rows;

  final List<Widget>? _columns;
  final List<List<Widget>>? _rows;
  final List<ShadTableCell>? _headerCells;
  final List<List<ShadTableCell>>? _rowCells;
  final TableSpanExtent? Function(int index)? columnSpanExtent;
  final double rowHeight;
  final double? maxHeight;
  final void Function(int index)? onRowTap;
  final String emptyLabel;
  final Set<int>? sortableColumns;
  final SuperportTableSortState? sortState;
  final void Function(int columnIndex, bool ascending)? onSortChanged;
  final SuperportTablePagination? pagination;
  final void Function(int page)? onPageChange;
  final void Function(int pageSize)? onPageSizeChange;
  final bool isLoading;

  @override
  Widget build(BuildContext context) {
    late final List<ShadTableCell> headerCells;
    late final List<List<ShadTableCell>> tableRows;

    if (_rowCells case final rows?) {
      if (rows.isEmpty) {
        final theme = ShadTheme.of(context);
        return Padding(
          padding: const EdgeInsets.all(32),
          child: Center(child: Text(emptyLabel, style: theme.textTheme.muted)),
        );
      }
      final header = _headerCells;
      if (header == null) {
        throw StateError('header cells must not be null when using fromCells');
      }
      headerCells = [...header];
      tableRows = rows;
    } else {
      final rows = _rows;
      if (rows == null || rows.isEmpty) {
        final theme = ShadTheme.of(context);
        return Padding(
          padding: const EdgeInsets.all(32),
          child: Center(child: Text(emptyLabel, style: theme.textTheme.muted)),
        );
      }
      final columns = _columns!;
      final sortable = sortableColumns ?? const <int>{};
      headerCells = <ShadTableCell>[];
      for (var i = 0; i < columns.length; i++) {
        final columnWidget = columns[i];
        if (columnWidget is ShadTableCell) {
          headerCells.add(columnWidget);
          continue;
        }
        final shouldAttachSorter =
            onSortChanged != null && sortable.contains(i);
        final headerChild = shouldAttachSorter
            ? _SortableHeader(
                isActive: sortState?.columnIndex == i,
                ascending: sortState?.ascending ?? true,
                onTap: () {
                  final isActive = sortState?.columnIndex == i;
                  final nextAscending = isActive
                      ? !(sortState?.ascending ?? true)
                      : true;
                  onSortChanged!(i, nextAscending);
                },
                child: columnWidget,
              )
            : columnWidget;
        headerCells.add(ShadTableCell.header(child: headerChild));
      }
      tableRows = [
        for (final row in rows)
          row
              .map(
                (cell) =>
                    cell is ShadTableCell ? cell : ShadTableCell(child: cell),
              )
              .toList(),
      ];
    }

    final estimatedHeight = (tableRows.length + 1) * rowHeight;
    final minHeight = rowHeight * 2;
    final effectiveHeight = math.max(
      minHeight,
      maxHeight == null
          ? estimatedHeight
          : math.min(estimatedHeight, maxHeight!),
    );

    final hasHeaderRow = _headerCells != null || _columns != null;
    final headerCount = hasHeaderRow ? 1 : 0;

    void Function(int index)? handleRowTap;
    if (onRowTap != null) {
      handleRowTap = (index) {
        final dataIndex = index - headerCount;
        if (dataIndex < 0 || dataIndex >= tableRows.length) {
          return;
        }
        onRowTap!(dataIndex);
      };
    }

    final tableView = SizedBox(
      height: effectiveHeight,
      child: ShadTable.list(
        header: headerCells,
        columnSpanExtent: columnSpanExtent,
        rowSpanExtent: (_) => FixedTableSpanExtent(rowHeight),
        onRowTap: handleRowTap,
        primary: false,
        children: tableRows,
      ),
    );

    final pagination = this.pagination;
    if (pagination == null) {
      return tableView;
    }

    return Column(
      mainAxisSize: MainAxisSize.min,
      crossAxisAlignment: CrossAxisAlignment.stretch,
      children: [
        tableView,
        const SizedBox(height: 12),
        _PaginationFooter(
          pagination: pagination,
          onPageChange: onPageChange,
          onPageSizeChange: onPageSizeChange,
          isLoading: isLoading,
        ),
      ],
    );
  }
}

/// 정렬 상태와 토글 동작을 제공하는 테이블 헤더 셀.
class _SortableHeader extends StatelessWidget {
  const _SortableHeader({
    required this.child,
    required this.onTap,
    required this.isActive,
    required this.ascending,
  });

  final Widget child;
  final VoidCallback onTap;
  final bool isActive;
  final bool ascending;

  @override
  Widget build(BuildContext context) {
    final theme = ShadTheme.of(context);
    final icon = isActive
        ? (ascending
              ? lucide.LucideIcons.arrowUp
              : lucide.LucideIcons.arrowDown)
        : lucide.LucideIcons.arrowUpDown;
    final color = isActive
        ? theme.colorScheme.foreground
        : theme.colorScheme.mutedForeground;

    return InkWell(
      onTap: onTap,
      borderRadius: BorderRadius.circular(6),
      child: Padding(
        padding: const EdgeInsets.symmetric(horizontal: 8, vertical: 6),
        child: Row(
          mainAxisAlignment: MainAxisAlignment.spaceBetween,
          children: [
            Flexible(child: child),
            const SizedBox(width: 8),
            Icon(icon, size: 14, color: color),
          ],
        ),
      ),
    );
  }
}

/// 페이지 이동 및 페이지 사이즈 변경을 처리하는 푸터 UI.
class _PaginationFooter extends StatelessWidget {
  const _PaginationFooter({
    required this.pagination,
    required this.onPageChange,
    required this.onPageSizeChange,
    required this.isLoading,
  });

  final SuperportTablePagination pagination;
  final void Function(int page)? onPageChange;
  final void Function(int pageSize)? onPageSizeChange;
  final bool isLoading;

  @override
  Widget build(BuildContext context) {
    final theme = ShadTheme.of(context);
    final int totalPages = pagination.totalPages <= 0
        ? 1
        : pagination.totalPages;
    final int currentPage = pagination.currentPage < 1
        ? 1
        : (pagination.currentPage > totalPages
              ? totalPages
              : pagination.currentPage);

    return Row(
      mainAxisAlignment: MainAxisAlignment.spaceBetween,
      children: [
        SizedBox(
          width: 170,
          child: ShadSelect<int>(
            key: ValueKey(pagination.pageSize),
            initialValue: pagination.pageSize,
            selectedOptionBuilder: (_, value) => Text('$value개 / 페이지'),
            onChanged: isLoading
                ? null
                : (value) {
                    if (value == null || value == pagination.pageSize) {
                      return;
                    }
                    onPageSizeChange?.call(value);
                  },
            options: [
              for (final option in pagination.pageSizeOptions)
                ShadOption(value: option, child: Text('$option개 / 페이지')),
            ],
          ),
        ),
        Row(
          children: [
            Text(
              '${pagination.totalItems}건 · 페이지 $currentPage / $totalPages',
              style: theme.textTheme.small,
            ),
            const SizedBox(width: 12),
            SuperportPaginationControls(
              currentPage: currentPage,
              totalPages: totalPages,
              onPageSelected: onPageChange,
              isBusy: isLoading,
            ),
          ],
        ),
      ],
    );
  }
}
