import 'dart:async';

import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:forui/forui.dart';
import 'package:go_router/go_router.dart';

import '../../core/contracts/library.dart';
import '../../providers/di_providers.dart';
import '../../providers/session_provider.dart';
import '../../shared/layout/adaptive_card_grid.dart';
import '../../shared/mappers/media_image_url.dart';
import '../../shared/theme/app_theme.dart';
import '../../shared/utils/media_nav.dart';
import '../../shared/constants/layout_constants.dart';
import '../../shared/widgets/app_loading_ring.dart';
import '../../shared/widgets/app_card.dart';
import '../../shared/widgets/app_skeleton.dart';
import '../../shared/widgets/app_sliver_header.dart';
import '../../shared/widgets/empty_state.dart';
import '../../shared/widgets/media_poster_card.dart';
import '../../shared/constants/breakpoints.dart';
import '../../shared/widgets/page_background.dart';
import '../../shared/widgets/section_header.dart';
import '../../shared/widgets/sidebar.dart';
import '../../shared/widgets/warm_gradient_background.dart';


const _kBranchRootLocations = <int, String>{
  0: '/',
  1: '/servers',
  2: '/aggregated',
  3: '/discover',
  4: '/calendar',
};

const _kTypeFilters = <String, String>{
  'Movie': '电影',
  'Series': '剧',
  'Episode': '集',
  'Video': '视频',
  'Channel': '频道',
  'BoxSet': '合集',
  'Person': '演职人员',
};

class GlobalSearchPage extends ConsumerStatefulWidget {
  final bool currentServerOnly;
  const GlobalSearchPage({super.key, this.currentServerOnly = false});

  @override
  ConsumerState<GlobalSearchPage> createState() => _GlobalSearchPageState();
}

class _GlobalSearchPageState extends ConsumerState<GlobalSearchPage> {
  final _controller = TextEditingController();
  StreamSubscription<GlobalSearchServerResult>? _subscription;

  List<GlobalSearchServerResult> _serverResults = [];
  String _activeQuery = '';
  List<String> _history = const [];
  final Set<String> _selectedTypes = {'Movie', 'Series'};
  bool _searching = false;
  bool _switching = false;

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

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

  Future<void> _loadHistory() async {
    final store = ref.read(searchHistoryStoreProvider);
    final list = await store.list();
    if (mounted) setState(() => _history = list);
  }

  void _onValueChanged(TextEditingValue value) {
    if (value.text.trim().isEmpty && _activeQuery.isNotEmpty) {
      _subscription?.cancel();
      setState(() {
        _activeQuery = '';
        _serverResults = [];
        _searching = false;
      });
    }
  }

  void _toggleType(String type) {
    setState(() {
      if (_selectedTypes.contains(type)) {
        if (_selectedTypes.length > 1) _selectedTypes.remove(type);
      } else {
        _selectedTypes.add(type);
      }
    });
    if (_activeQuery.isNotEmpty) {
      _search(_activeQuery);
    }
  }

  String get _typesParam => _selectedTypes.join(',');

  Future<void> _search(String keyword) async {
    final k = keyword.trim();

    _subscription?.cancel();
    _subscription = null;

    if (k.isEmpty) {
      setState(() {
        _activeQuery = '';
        _serverResults = [];
        _searching = false;
      });
      return;
    }

    setState(() {
      _activeQuery = k;
      _searching = true;
      _serverResults = [];
    });

    try {
      final uc = await ref.read(globalKeywordSearchUseCaseProvider.future);
      String? serverId;
      if (widget.currentServerOnly) {
        serverId = ref.read(sessionProvider).value?.activeServerId;
      }
      final stream = uc.executeStream(
        GlobalSearchReq(
          keyword: k,
          includeItemTypes: _typesParam,
          serverId: serverId,
        ),
      );

      _subscription = stream.listen(
        (result) {
          if (mounted) {
            setState(() => _serverResults = [..._serverResults, result]);
          }
        },
        onDone: () async {
          if (!mounted) return;
          setState(() => _searching = false);
          if (_serverResults.isNotEmpty) {
            await ref.read(searchHistoryStoreProvider).add(k);
            await _loadHistory();
          }
        },
        onError: (_) {
          if (mounted) setState(() => _searching = false);
        },
      );
    } catch (_) {
      if (mounted) setState(() => _searching = false);
    }
  }

  Future<void> _onItemTap(
    BuildContext context,
    GlobalSearchServerResult serverResult,
    EmbyRawItem item,
  ) async {
    if (_switching) return;
    setState(() => _switching = true);
    try {
      await goMediaDetailOnServer(
        context,
        ref,
        serverId: serverResult.serverId,
        item: item,
      );
    } finally {
      if (mounted) setState(() => _switching = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    final sessions = ref.watch(sessionProvider).value;
    final activeServerId = sessions?.activeServerId;

    final isCompact = MediaQuery.sizeOf(context).width < Breakpoints.compact;
    final canPop = Navigator.of(context).canPop();

    final searchScaffold = Scaffold(
      backgroundColor: Colors.transparent,
      extendBodyBehindAppBar: true,
      body: CustomScrollView(
        slivers: [
          AppSliverHeader(
            title: '搜索',

            automaticallyImplyLeading: canPop || isCompact,
          ),
          SliverToBoxAdapter(child: _buildSearchBar()),
          SliverToBoxAdapter(child: _buildTypeFilters()),
          ..._buildBodySlivers(context, activeServerId),
        ],
      ),
    );


    final body = isCompact
        ? searchScaffold
        : Row(
            crossAxisAlignment: CrossAxisAlignment.stretch,
            children: [
              Sidebar(
                selectedBranchIndex: -1,
                onNavigateBranch: (index, {initialLocation = false}) {
                  final root = _kBranchRootLocations[index];
                  if (root != null) context.go(root);
                },
                location: '/global-search',
              ),
              Expanded(child: searchScaffold),
            ],
          );

    return Stack(
      fit: StackFit.expand,
      children: [
        Positioned.fill(
          child: isCompact
              ? const WarmGradientBackground()
              : const PageBackground(),
        ),
        body,
        if (_switching)
          const Positioned.fill(
            child: ColoredBox(
              color: Color(0x44000000),
              child: Center(child: AppLoadingRing()),
            ),
          ),
      ],
    );
  }

  Widget _buildSearchBar() {
    final isCompact = MediaQuery.sizeOf(context).width < Breakpoints.compact;
    final horizontalPadding = isCompact ? 16.0 : 24.0;
    return Padding(
      padding: EdgeInsets.fromLTRB(horizontalPadding, 12, horizontalPadding, 4),
      child: FTextField(
        control: FTextFieldControl.managed(
          controller: _controller,
          onChange: _onValueChanged,
        ),
        hint: widget.currentServerOnly
            ? '搜索当前服务器媒体...'
            : '在所有服务器中搜索...',
        autofocus: true,
        prefixBuilder: (ctx, style, variants) =>
            FTextField.prefixIconBuilder(
              ctx, style, variants, const Icon(Icons.search)),
        clearable: (v) => v.text.isNotEmpty,
        onSubmit: _search,
      ),
    );
  }

  Widget _buildTypeFilters() {
    final isCompact = MediaQuery.sizeOf(context).width < Breakpoints.compact;
    final horizontalPadding = isCompact ? 16.0 : 24.0;
    return Padding(
      padding: EdgeInsets.fromLTRB(horizontalPadding, 6, horizontalPadding, 4),
      child: SingleChildScrollView(
        scrollDirection: Axis.horizontal,
        child: Row(
          children: [
            for (final entry in _kTypeFilters.entries)
              Padding(
                padding: const EdgeInsets.only(right: 8),
                child: FButton(
                  variant: _selectedTypes.contains(entry.key)
                      ? FButtonVariant.primary
                      : FButtonVariant.outline,
                  size: FButtonSizeVariant.sm,
                  onPress: () => _toggleType(entry.key),
                  child: Text(entry.value),
                ),
              ),
          ],
        ),
      ),
    );
  }

  List<Widget> _buildBodySlivers(BuildContext context, String? activeServerId) {
    if (_activeQuery.isEmpty) {
      return _buildHistorySlivers();
    }
    if (_serverResults.isEmpty && !_searching) {
      return const [
        SliverFillRemaining(
          hasScrollBody: false,
          child: EmptyState(icon: Icons.search_off, title: '没有匹配的结果'),
        ),
      ];
    }
    if (_serverResults.isEmpty && _searching) {
      return [
        SliverToBoxAdapter(
          child: SkeletonGrid(
            itemCount: 8,
            itemHeight: 240,
            minCardWidth: kPosterCardMinWidth,
            padding: const EdgeInsets.fromLTRB(24, 8, 24, 0),
          ),
        ),
      ];
    }
    final slivers = <Widget>[];
    for (final sr in _serverResults) {
      slivers.addAll(
        _buildServerSlivers(context, sr, sr.serverId == activeServerId),
      );
    }
    slivers.add(const SliverToBoxAdapter(child: SizedBox(height: 24)));
    return slivers;
  }

  List<Widget> _buildServerSlivers(
    BuildContext context,
    GlobalSearchServerResult serverResult,
    bool isActive,
  ) {
    final tokens = context.appTokens;
    final headers = buildEmbyImageHeaders(
      ref,
      token: serverResult.token,
      userId: serverResult.userId,
    );

    return [
      if (!widget.currentServerOnly)
        SliverToBoxAdapter(
          child: Padding(
            padding: const EdgeInsets.fromLTRB(24, 12, 24, 0),
            child: SectionHeader(
              label: serverResult.serverName,
              count: serverResult.items.length,
            ),
          ),
        ),
      SliverPadding(
        padding: const EdgeInsets.fromLTRB(24, 0, 24, 8),
        sliver: SliverGrid(
          gridDelegate: mediaGridDelegate,
          delegate: SliverChildBuilderDelegate((_, j) {
            final item = serverResult.items[j];
            return AppCard(
              filled: false,
              radius: tokens.radiusCard,
              padding: EdgeInsets.zero,
              child: MediaPosterCard(
                item: item,
                width: 132,
                imageUrl: EmbyImageUrl.primary(
                  baseUrl: serverResult.serverUrl,
                  token: serverResult.token,
                  item: item,
                  maxHeight: 300,
                ),
                imageHeaders: headers,
                onTap: () => _onItemTap(context, serverResult, item),
              ),
            );
          }, childCount: serverResult.items.length),
        ),
      ),
    ];
  }

  List<Widget> _buildHistorySlivers() {
    if (_history.isEmpty) {
      return [
        SliverFillRemaining(
          hasScrollBody: false,
          child: EmptyState(
            icon: Icons.search,
            title: widget.currentServerOnly ? '搜索当前服务器中的内容' : '搜索所有服务器中的内容',
          ),
        ),
      ];
    }
    final isCompact = MediaQuery.sizeOf(context).width < Breakpoints.compact;
    final horizontalPadding = isCompact ? 16.0 : 24.0;
    final content = Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        SectionHeader(
          label: '搜索历史',
          trailing: FButton(
            variant: FButtonVariant.ghost,
            size: FButtonSizeVariant.sm,
            onPress: () async {
              await ref.read(searchHistoryStoreProvider).clear();
              _loadHistory();
            },
            prefix: const Icon(Icons.delete_outline, size: 16),
            child: const Text('清空'),
          ),
        ),
        const SizedBox(height: 12),
        Wrap(
          spacing: 8,
          runSpacing: 8,
          children: _history
              .map(
                (kw) => FButton(
                  variant: FButtonVariant.outline,
                  size: FButtonSizeVariant.sm,
                  mainAxisSize: MainAxisSize.min,
                  onPress: () {
                    _controller.text = kw;
                    _controller.selection = TextSelection.collapsed(
                      offset: kw.length,
                    );
                    _search(kw);
                  },
                  suffix: GestureDetector(
                    behavior: HitTestBehavior.opaque,
                    onTap: () async {
                      await ref.read(searchHistoryStoreProvider).remove(kw);
                      _loadHistory();
                    },
                    child: const Icon(Icons.close, size: 14),
                  ),
                  child: Text(kw),
                ),
              )
              .toList(),
        ),
      ],
    );
    return [
      SliverPadding(
        padding: EdgeInsets.fromLTRB(
            horizontalPadding, 16, horizontalPadding, 24),
        sliver: SliverList(
          delegate: SliverChildListDelegate([
            if (isCompact)
              content
            else
              AppCard(
                filled: true,
                enableHover: false,
                padding: const EdgeInsets.all(16),
                child: content,
              ),
          ]),
        ),
      ),
    ];
  }
}

