import 'package:flutter/material.dart';
import 'package:finamp/l10n/app_localizations.dart';
import 'package:get_it/get_it.dart';
import 'package:hive/hive.dart';
import 'package:logging/logging.dart';

import '../models/finamp_models.dart';
import '../services/finamp_settings_helper.dart';
import '../services/audio_service_helper.dart';
import '../services/finamp_user_helper.dart';
import '../components/MusicScreen/music_screen_tab_view.dart';
import '../components/MusicScreen/music_screen_drawer.dart';
import '../components/MusicScreen/sort_by_menu_button.dart';
import '../components/MusicScreen/sort_order_button.dart';
import '../components/now_playing_bar.dart';
import '../components/error_snackbar.dart';
import '../services/jellyfin_api_helper.dart';

class MusicScreen extends StatefulWidget {
  const MusicScreen({Key? key}) : super(key: key);

  static const routeName = "/music";

  @override
  State<MusicScreen> createState() => _MusicScreenState();
}

class _MusicScreenState extends State<MusicScreen>
    with TickerProviderStateMixin {
  bool isSearching = false;
  bool _showShuffleFab = false;
  TextEditingController textEditingController = TextEditingController();
  String? searchQuery;
  final _musicScreenLogger = Logger("MusicScreen");

  TabController? _tabController;

  final _audioServiceHelper = GetIt.instance<AudioServiceHelper>();
  final _finampUserHelper = GetIt.instance<FinampUserHelper>();
  final _jellyfinApiHelper = GetIt.instance<JellyfinApiHelper>();

  void _stopSearching() {
    setState(() {
      textEditingController.clear();
      searchQuery = null;
      isSearching = false;
    });
  }

  void _tabIndexCallback() {
    var tabKey = FinampSettingsHelper.finampSettings.showTabs.entries
        .where((element) => element.value)
        .elementAt(_tabController!.index)
        .key;
    setState(() {});
    if (_tabController != null &&
        (tabKey == TabContentType.songs ||
            tabKey == TabContentType.artists ||
            tabKey == TabContentType.albums)) {
      setState(() {
        _showShuffleFab = true;
      });
    } else {
      if (_showShuffleFab) {
        setState(() {
          _showShuffleFab = false;
        });
      }
    }
  }

  void _buildTabController() {
    _tabController?.removeListener(_tabIndexCallback);

    _tabController = TabController(
      length: FinampSettingsHelper.finampSettings.showTabs.entries
          .where((element) => element.value)
          .length,
      vsync: this,
    );

    _tabController!.addListener(_tabIndexCallback);
  }

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

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

  FloatingActionButton? getFloatingActionButton() {
    var tabList = FinampSettingsHelper.finampSettings.showTabs.entries
        .where((element) => element.value)
        .map((e) => e.key)
        .toList();

    // Show the floating action button only on the albums, artists and songs tab.
    if (_tabController!.index == tabList.indexOf(TabContentType.songs)) {
      return FloatingActionButton(
        tooltip: AppLocalizations.of(context)!.shuffleAll,
        onPressed: () async {
          try {
            await _audioServiceHelper
                .shuffleAll(FinampSettingsHelper.finampSettings.isFavourite);
          } catch (e) {
            errorSnackbar(e, context);
          }
        },
        child: const Icon(Icons.shuffle),
      );
    } else if (_tabController!.index ==
        tabList.indexOf(TabContentType.artists)) {
      return FloatingActionButton(
          tooltip: AppLocalizations.of(context)!.startMix,
          onPressed: () async {
            try {
              if (_jellyfinApiHelper.selectedMixArtistsIds.isEmpty) {
                ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                    content: Text(
                        AppLocalizations.of(context)!.startMixNoSongsArtist)));
              } else {
                await _audioServiceHelper.startInstantMixForArtists(
                    _jellyfinApiHelper.selectedMixArtistsIds);
              }
            } catch (e) {
              errorSnackbar(e, context);
            }
          },
          child: const Icon(Icons.explore));
    } else if (_tabController!.index ==
        tabList.indexOf(TabContentType.albums)) {
      return FloatingActionButton(
          tooltip: AppLocalizations.of(context)!.startMix,
          onPressed: () async {
            try {
              if (_jellyfinApiHelper.selectedMixAlbumIds.isEmpty) {
                ScaffoldMessenger.of(context).showSnackBar(SnackBar(
                    content: Text(
                        AppLocalizations.of(context)!.startMixNoSongsAlbum)));
              } else {
                await _audioServiceHelper.startInstantMixForAlbums(
                    _jellyfinApiHelper.selectedMixAlbumIds);
              }
            } catch (e) {
              errorSnackbar(e, context);
            }
          },
          child: const Icon(Icons.explore));
    } else {
      return null;
    }
  }

  @override
  Widget build(BuildContext context) {
    return ValueListenableBuilder<Box<FinampUser>>(
      valueListenable: _finampUserHelper.finampUsersListenable,
      builder: (context, value, _) {
        return ValueListenableBuilder<Box<FinampSettings>>(
          valueListenable: FinampSettingsHelper.finampSettingsListener,
          builder: (context, value, _) {
            final finampSettings = value.get("FinampSettings");

            // Get the tabs from the user's tab order, and filter them to only
            // include enabled tabs
            final tabs = finampSettings!.tabOrder.where((e) =>
                FinampSettingsHelper.finampSettings.showTabs[e] ?? false);

            if (tabs.length != _tabController?.length) {
              _musicScreenLogger.info(
                  "Rebuilding MusicScreen tab controller (${tabs.length} != ${_tabController?.length})");
              _buildTabController();
            }

            return WillPopScope(
              onWillPop: () async {
                if (isSearching) {
                  _stopSearching();
                  return false;
                }
                return true;
              },
              child: Scaffold(
                extendBody: true,
                appBar: AppBar(
                  elevation: 0,
                  scrolledUnderElevation: 0,
                  backgroundColor: Colors.transparent,
                  title: isSearching
                      ? TextField(
                          controller: textEditingController,
                          autofocus: true,
                          onChanged: (value) => setState(() {
                            searchQuery = value;
                          }),
                          decoration: InputDecoration(
                            border: InputBorder.none,
                            hintText: MaterialLocalizations.of(context)
                                .searchFieldLabel,
                          ),
                        )
                      : null,
                  leading: isSearching
                      ? BackButton(
                          onPressed: () => _stopSearching(),
                        )
                      : Builder(
                          builder: (context) => IconButton.filledTonal(
                            icon: const Icon(Icons.menu_rounded),
                            onPressed: () => Scaffold.of(context).openDrawer(),
                            tooltip: MaterialLocalizations.of(context)
                                .openAppDrawerTooltip,
                          ),
                        ),
                  actions: isSearching
                      ? [
                          IconButton(
                            icon: Icon(
                              Icons.cancel,
                              color: Theme.of(context).colorScheme.onSurface,
                            ),
                            onPressed: () => setState(() {
                              textEditingController.clear();
                              searchQuery = null;
                            }),
                            tooltip: AppLocalizations.of(context)!.clear,
                          )
                        ]
                      : [
                          SortOrderButton(
                            tabs.elementAt(_tabController!.index),
                          ),
                          SortByMenuButton(
                            tabs.elementAt(_tabController!.index),
                          ),
                          IconButton(
                            icon: finampSettings.isFavourite
                                ? const Icon(Icons.favorite_rounded)
                                : const Icon(Icons.favorite_outline_rounded),
                            onPressed: finampSettings.isOffline
                                ? null
                                : () => FinampSettingsHelper.setIsFavourite(
                                    !finampSettings.isFavourite),
                            tooltip: AppLocalizations.of(context)!.favourites,
                          ),
                          IconButton(
                            icon: const Icon(Icons.search_rounded),
                            onPressed: () => setState(() {
                              isSearching = true;
                            }),
                            tooltip: MaterialLocalizations.of(context)
                                .searchFieldLabel,
                          ),
                        ],
                ),
                bottomNavigationBar: const NowPlayingBar(),
                drawer: const MusicScreenDrawer(),
                floatingActionButton: Padding(
                  padding: const EdgeInsets.only(right: 8.0),
                  child: getFloatingActionButton(),
                ),
                body: DecoratedBox(
                  decoration: BoxDecoration(
                    gradient: LinearGradient(
                      begin: Alignment.topLeft,
                      end: Alignment.bottomRight,
                      colors: [
                        Theme.of(context)
                            .colorScheme
                            .primaryContainer
                            .withOpacity(0.45),
                        Theme.of(context).colorScheme.surface,
                        Theme.of(context).colorScheme.surface,
                      ],
                    ),
                  ),
                  child: SafeArea(
                    top: false,
                    child: Column(
                      children: [
                        if (!isSearching)
                          _MusicHeroHeader(
                            title: _finampUserHelper
                                    .currentUser?.currentView?.name ??
                                AppLocalizations.of(context)!.music,
                            activeTab: tabs
                                .elementAt(_tabController!.index)
                                .toLocalisedString(context),
                            isFavourite: finampSettings.isFavourite,
                            isOffline: finampSettings.isOffline,
                            onShuffle: () async {
                              try {
                                await _audioServiceHelper.shuffleAll(
                                  FinampSettingsHelper
                                      .finampSettings.isFavourite,
                                );
                              } catch (e) {
                                errorSnackbar(e, context);
                              }
                            },
                          ),
                        _ModernMusicTabBar(
                          controller: _tabController!,
                          tabs: tabs.toList(),
                        ),
                        Expanded(
                          child: Container(
                            margin: const EdgeInsets.fromLTRB(12, 8, 12, 0),
                            decoration: BoxDecoration(
                              color: Theme.of(context).colorScheme.surface,
                              borderRadius: const BorderRadius.vertical(
                                top: Radius.circular(28),
                              ),
                              boxShadow: [
                                BoxShadow(
                                  color: Theme.of(context)
                                      .colorScheme
                                      .shadow
                                      .withOpacity(0.08),
                                  blurRadius: 24,
                                  offset: const Offset(0, -6),
                                ),
                              ],
                            ),
                            clipBehavior: Clip.antiAlias,
                            child: TabBarView(
                              controller: _tabController,
                              children: tabs
                                  .map((tabType) => MusicScreenTabView(
                                        tabContentType: tabType,
                                        searchTerm: searchQuery,
                                        isFavourite: finampSettings.isFavourite,
                                        sortBy: finampSettings
                                            .getTabSortBy(tabType),
                                        sortOrder: finampSettings
                                            .getSortOrder(tabType),
                                        view: _finampUserHelper
                                            .currentUser?.currentView,
                                      ))
                                  .toList(),
                            ),
                          ),
                        ),
                      ],
                    ),
                  ),
                ),
              ),
            );
          },
        );
      },
    );
  }
}

class _MusicHeroHeader extends StatelessWidget {
  const _MusicHeroHeader({
    required this.title,
    required this.activeTab,
    required this.isFavourite,
    required this.isOffline,
    required this.onShuffle,
  });

  final String title;
  final String activeTab;
  final bool isFavourite;
  final bool isOffline;
  final VoidCallback onShuffle;

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

    return Padding(
      padding: const EdgeInsets.fromLTRB(20, 86, 20, 12),
      child: DecoratedBox(
        decoration: BoxDecoration(
          borderRadius: BorderRadius.circular(32),
          gradient: LinearGradient(
            begin: Alignment.topLeft,
            end: Alignment.bottomRight,
            colors: [
              colorScheme.primary.withOpacity(0.95),
              colorScheme.tertiary.withOpacity(0.78),
            ],
          ),
          boxShadow: [
            BoxShadow(
              color: colorScheme.primary.withOpacity(0.28),
              blurRadius: 34,
              offset: const Offset(0, 18),
            ),
          ],
        ),
        child: Padding(
          padding: const EdgeInsets.all(24),
          child: Column(
            crossAxisAlignment: CrossAxisAlignment.start,
            children: [
              Text(
                isOffline ? 'Offline library' : 'Your Jellyfin music',
                style: theme.textTheme.labelLarge?.copyWith(
                  color: colorScheme.onPrimary.withOpacity(0.76),
                  letterSpacing: 0.6,
                ),
              ),
              const SizedBox(height: 8),
              Text(
                title,
                maxLines: 2,
                overflow: TextOverflow.ellipsis,
                style: theme.textTheme.headlineMedium?.copyWith(
                  color: colorScheme.onPrimary,
                  fontWeight: FontWeight.w800,
                  height: 1.04,
                ),
              ),
              const SizedBox(height: 20),
              Row(
                children: [
                  FilledButton.icon(
                    onPressed: onShuffle,
                    icon: const Icon(Icons.shuffle_rounded),
                    label: const Text('Shuffle'),
                    style: FilledButton.styleFrom(
                      backgroundColor: colorScheme.onPrimary,
                      foregroundColor: colorScheme.primary,
                    ),
                  ),
                  const SizedBox(width: 10),
                  _HeroChip(
                    icon: isFavourite
                        ? Icons.favorite_rounded
                        : Icons.library_music_rounded,
                    label: isFavourite ? 'Favourites' : activeTab,
                  ),
                ],
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class _HeroChip extends StatelessWidget {
  const _HeroChip({required this.icon, required this.label});

  final IconData icon;
  final String label;

  @override
  Widget build(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;

    return Container(
      padding: const EdgeInsets.symmetric(horizontal: 14, vertical: 10),
      decoration: BoxDecoration(
        color: colorScheme.onPrimary.withOpacity(0.14),
        borderRadius: BorderRadius.circular(999),
        border: Border.all(color: colorScheme.onPrimary.withOpacity(0.16)),
      ),
      child: Row(
        mainAxisSize: MainAxisSize.min,
        children: [
          Icon(icon, color: colorScheme.onPrimary, size: 18),
          const SizedBox(width: 8),
          Text(
            label,
            style: TextStyle(
              color: colorScheme.onPrimary,
              fontWeight: FontWeight.w700,
            ),
          ),
        ],
      ),
    );
  }
}

class _ModernMusicTabBar extends StatelessWidget {
  const _ModernMusicTabBar({required this.controller, required this.tabs});

  final TabController controller;
  final List<TabContentType> tabs;

  @override
  Widget build(BuildContext context) {
    final colorScheme = Theme.of(context).colorScheme;

    return Padding(
      padding: const EdgeInsets.symmetric(horizontal: 12),
      child: DecoratedBox(
        decoration: BoxDecoration(
          color: colorScheme.surface.withOpacity(0.7),
          borderRadius: BorderRadius.circular(999),
          border:
              Border.all(color: colorScheme.outlineVariant.withOpacity(0.4)),
        ),
        child: TabBar(
          controller: controller,
          tabs: tabs
              .map((tabType) => Tab(text: tabType.toLocalisedString(context)))
              .toList(),
          isScrollable: true,
          tabAlignment: TabAlignment.start,
          dividerColor: Colors.transparent,
          indicatorSize: TabBarIndicatorSize.tab,
          indicator: BoxDecoration(
            borderRadius: BorderRadius.circular(999),
            color: colorScheme.primary,
          ),
          labelColor: colorScheme.onPrimary,
          unselectedLabelColor: colorScheme.onSurfaceVariant,
          labelStyle: Theme.of(context).textTheme.labelLarge?.copyWith(
                fontWeight: FontWeight.w800,
              ),
          unselectedLabelStyle:
              Theme.of(context).textTheme.labelLarge?.copyWith(
                    fontWeight: FontWeight.w600,
                  ),
          padding: const EdgeInsets.all(4),
          labelPadding: const EdgeInsets.symmetric(horizontal: 18),
        ),
      ),
    );
  }
}
