// Copyright 2020 Ben Hills and the project contributors. All rights reserved.
// Use of this source code is governed by a BSD-style license that can be
// found in the LICENSE file.

import 'package:pinepods_mobile/bloc/podcast/queue_bloc.dart';
import 'package:pinepods_mobile/bloc/settings/settings_bloc.dart';
import 'package:pinepods_mobile/l10n/L.dart';
import 'package:pinepods_mobile/state/queue_event_state.dart';
import 'package:pinepods_mobile/ui/podcast/transcript_view.dart';
import 'package:pinepods_mobile/ui/podcast/up_next_view.dart';
import 'package:pinepods_mobile/ui/podcast/pinepods_up_next_view.dart';
import 'package:pinepods_mobile/ui/widgets/slider_handle.dart';
import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

/// This class gives us options that can be dragged up from the bottom of the main player
/// window.
///
/// Currently these options are Up Next & Transcript.
///
/// This class is an initial version and should by much simpler than it is; however,
/// a [NestedScrollView] is the widget we need to implement this UI, there is a current
/// issue whereby the scroll view and [DraggableScrollableSheet] clash and therefore cannot
/// be used together.
///
/// See issues [64157](https://github.com/flutter/flutter/issues/64157)
///            [67219](https://github.com/flutter/flutter/issues/67219)
///
/// If anyone can come up with a more elegant solution (and one that does not throw
/// an overflow error in debug) please raise and issue/submit a PR.
///
class NowPlayingOptionsSelector extends StatefulWidget {
  final double? scrollPos;
  static const baseSize = 68.0;

  const NowPlayingOptionsSelector({super.key, this.scrollPos});

  @override
  State<NowPlayingOptionsSelector> createState() => _NowPlayingOptionsSelectorState();
}

class _NowPlayingOptionsSelectorState extends State<NowPlayingOptionsSelector> {
  DraggableScrollableController? draggableController;

  @override
  Widget build(BuildContext context) {
    final queueBloc = Provider.of<QueueBloc>(context, listen: false);
    final theme = Theme.of(context);
    final windowHeight = MediaQuery.of(context).size.height;
    final minSize = NowPlayingOptionsSelector.baseSize / (windowHeight - NowPlayingOptionsSelector.baseSize);

    return DraggableScrollableSheet(
      initialChildSize: minSize,
      minChildSize: minSize,
      maxChildSize: 1.0,
      controller: draggableController,
      // Snap doesn't work as the sheet and scroll controller just don't get along
      // snap: true,
      // snapSizes: [minSize, maxSize],
      builder: (BuildContext context, ScrollController scrollController) {
        return StreamBuilder<QueueState>(
            initialData: QueueEmptyState(),
            stream: queueBloc.queue,
            builder: (context, queueSnapshot) {
              final hasTranscript = queueSnapshot.hasData &&
                  queueSnapshot.data?.playing != null &&
                  queueSnapshot.data!.playing!.hasTranscripts;
              
              return DefaultTabController(
                animationDuration: !draggableController!.isAttached || draggableController!.size <= minSize
                    ? const Duration(seconds: 0)
                    : kTabScrollDuration,
                length: hasTranscript ? 2 : 1,
          child: LayoutBuilder(builder: (BuildContext ctx, BoxConstraints constraints) {
            return SingleChildScrollView(
              controller: scrollController,
              child: ConstrainedBox(
                constraints: BoxConstraints.expand(
                  height: constraints.maxHeight,
                ),
                child: Material(
                  color: theme.secondaryHeaderColor,
                  shape: RoundedRectangleBorder(
                    side: BorderSide(
                      color: Theme.of(context).highlightColor,
                      width: 0.0,
                    ),
                    borderRadius: const BorderRadius.only(
                      topLeft: Radius.circular(18.0),
                      topRight: Radius.circular(18.0),
                    ),
                  ),
                  child: Column(
                    mainAxisSize: MainAxisSize.min,
                    mainAxisAlignment: MainAxisAlignment.start,
                    crossAxisAlignment: CrossAxisAlignment.center,
                    children: <Widget>[
                      SliderHandle(
                        label: optionsSliderOpen()
                            ? L.of(context)!.semantic_playing_options_collapse_label
                            : L.of(context)!.semantic_playing_options_expand_label,
                        onTap: () {
                          if (draggableController != null) {
                            if (draggableController!.size < 1.0) {
                              draggableController!.animateTo(
                                1.0,
                                duration: const Duration(milliseconds: 150),
                                curve: Curves.easeInOut,
                              );
                            } else {
                              draggableController!.animateTo(
                                0.0,
                                duration: const Duration(milliseconds: 150),
                                curve: Curves.easeInOut,
                              );
                            }
                          }
                        },
                      ),
                      DecoratedBox(
                        decoration: BoxDecoration(
                          color: Colors.white.withOpacity(0.0),
                          border: Border(
                            bottom: draggableController != null &&
                                    (!draggableController!.isAttached || draggableController!.size <= minSize)
                                ? BorderSide.none
                                : BorderSide(color: Colors.grey[800]!, width: 1.0),
                          ),
                        ),
                        child: TabBar(
                          onTap: (index) {
                            DefaultTabController.of(ctx).animateTo(index);

                            if (draggableController != null && draggableController!.size < 1.0) {
                              draggableController!.animateTo(
                                1.0,
                                duration: const Duration(milliseconds: 150),
                                curve: Curves.easeInOut,
                              );
                            }
                          },
                          automaticIndicatorColorAdjustment: false,
                          indicatorPadding: EdgeInsets.zero,

                          /// Little hack to hide the indicator when closed
                          indicatorColor: draggableController != null &&
                                  (!draggableController!.isAttached || draggableController!.size <= minSize)
                              ? Theme.of(context).secondaryHeaderColor
                              : null,
                          tabs: [
                            Padding(
                              padding: const EdgeInsets.only(top: 8.0, bottom: 8.0),
                              child: Text(
                                L.of(context)!.up_next_queue_label.toUpperCase(),
                                style: Theme.of(context).textTheme.labelLarge,
                              ),
                            ),
                            if (hasTranscript)
                              Padding(
                                padding: const EdgeInsets.only(top: 8.0, bottom: 8.0),
                                child: Text(
                                  L.of(context)!.transcript_label.toUpperCase(),
                                  style: Theme.of(context).textTheme.labelLarge,
                                ),
                              ),
                          ],
                        ),
                      ),
                      const Padding(padding: EdgeInsets.only(bottom: 12.0)),
                      Expanded(
                        child: Consumer<SettingsBloc>(
                          builder: (context, settingsBloc, child) {
                            final settings = settingsBloc.currentSettings;
                            final isPinepodsConnected = settings.pinepodsServer != null &&
                                settings.pinepodsApiKey != null &&
                                settings.pinepodsUserId != null;

                            return TabBarView(
                              children: [
                                isPinepodsConnected 
                                  ? const PinepodsUpNextView()
                                  : const UpNextView(),
                                if (hasTranscript)
                                  const TranscriptView(),
                              ],
                            );
                          },
                        ),
                      ),
                    ],
                  ),
                ),
              ),
            );
          }),
        );
            });
      },
    );
  }

  bool optionsSliderOpen() {
    return (draggableController != null && draggableController!.isAttached && draggableController!.size == 1.0);
  }

  @override
  void initState() {
    draggableController = DraggableScrollableController();
    super.initState();
  }
}

class NowPlayingOptionsScaffold extends StatelessWidget {
  const NowPlayingOptionsScaffold({super.key});

  @override
  Widget build(BuildContext context) {
    return const SizedBox(
      height: NowPlayingOptionsSelector.baseSize - 8.0,
    );
  }
}

/// This implementation displays the additional options in a tab set outside of a
/// draggable sheet.
///
/// Currently these options are Up Next & Transcript.
class NowPlayingOptionsSelectorWide extends StatefulWidget {
  final double? scrollPos;
  static const baseSize = 68.0;

  const NowPlayingOptionsSelectorWide({super.key, this.scrollPos});

  @override
  State<NowPlayingOptionsSelectorWide> createState() => _NowPlayingOptionsSelectorWideState();
}

class _NowPlayingOptionsSelectorWideState extends State<NowPlayingOptionsSelectorWide> {
  DraggableScrollableController? draggableController;

  @override
  Widget build(BuildContext context) {
    final queueBloc = Provider.of<QueueBloc>(context, listen: false);
    final theme = Theme.of(context);
    final scrollController = ScrollController();

    return StreamBuilder<QueueState>(
        initialData: QueueEmptyState(),
        stream: queueBloc.queue,
        builder: (context, queueSnapshot) {
          final hasTranscript = queueSnapshot.hasData &&
              queueSnapshot.data?.playing != null &&
              queueSnapshot.data!.playing!.hasTranscripts;
          
          return DefaultTabController(
            length: hasTranscript ? 2 : 1,
      child: LayoutBuilder(builder: (BuildContext ctx, BoxConstraints constraints) {
        return SingleChildScrollView(
          controller: scrollController,
          child: ConstrainedBox(
            constraints: BoxConstraints.expand(
              height: constraints.maxHeight,
            ),
            child: Material(
              color: theme.secondaryHeaderColor,
              child: Column(
                mainAxisSize: MainAxisSize.min,
                mainAxisAlignment: MainAxisAlignment.start,
                crossAxisAlignment: CrossAxisAlignment.center,
                children: <Widget>[
                  DecoratedBox(
                    decoration: BoxDecoration(
                      color: Colors.white.withOpacity(0.0),
                      border: Border(
                        bottom: BorderSide(color: Colors.grey[800]!, width: 1.0),
                      ),
                    ),
                    child: TabBar(
                      automaticIndicatorColorAdjustment: false,
                      tabs: [
                        Padding(
                          padding: const EdgeInsets.only(top: 16.0, bottom: 16.0),
                          child: Text(
                            L.of(context)!.up_next_queue_label.toUpperCase(),
                            style: Theme.of(context).textTheme.labelLarge,
                          ),
                        ),
                        if (hasTranscript)
                          Padding(
                            padding: const EdgeInsets.only(top: 16.0, bottom: 16.0),
                            child: Text(
                              L.of(context)!.transcript_label.toUpperCase(),
                              style: Theme.of(context).textTheme.labelLarge,
                            ),
                          ),
                      ],
                    ),
                  ),
                  Expanded(
                    child: TabBarView(
                      children: [
                        const UpNextView(),
                        if (hasTranscript)
                          const TranscriptView(),
                      ],
                    ),
                  ),
                ],
              ),
            ),
          ),
        );
      }),
        );
        });
  }
}
