import 'package:flutter/material.dart';
import 'package:hooks_riverpod/hooks_riverpod.dart';
import 'package:immich_mobile/domain/models/asset/base_asset.model.dart';
import 'package:immich_mobile/extensions/build_context_extensions.dart';
import 'package:immich_mobile/extensions/translate_extensions.dart';
import 'package:immich_mobile/presentation/widgets/images/thumbnail.widget.dart';
import 'package:immich_mobile/providers/album/pending_album_uploads.provider.dart';
import 'package:immich_mobile/providers/backup/asset_upload_progress.provider.dart';

/// Pinned banner sliver that surfaces in-flight album uploads directly under
/// the album app bar. Renders nothing while the queue is empty. Tapping the
/// banner opens a bottom sheet with per-asset progress.
class PendingUploadsBanner extends ConsumerWidget {
  static const double _height = 52;

  final String albumId;

  const PendingUploadsBanner({super.key, required this.albumId});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final pending = ref.watch(pendingAlbumUploadsProvider(albumId));
    if (pending.isEmpty) {
      return const SliverToBoxAdapter(child: SizedBox.shrink());
    }

    final hasFailures = pending.any((p) => p.failed);
    final clamped = pending.map((p) => p.progress.clamp(0.0, 1.0)).toList(growable: false);
    final overallProgress = clamped.isEmpty ? 0.0 : clamped.reduce((a, b) => a + b) / clamped.length;
    final isIndeterminate = overallProgress <= 0.0;

    return SliverPersistentHeader(
      pinned: true,
      delegate: _PendingUploadsBannerDelegate(
        height: _height,
        child: _PendingUploadsBannerContent(
          albumId: albumId,
          previewAsset: pending.first.asset,
          count: pending.length,
          overallProgress: overallProgress,
          isIndeterminate: isIndeterminate,
          hasFailures: hasFailures,
        ),
      ),
    );
  }

  static void _openSheet(BuildContext context, String albumId) {
    showModalBottomSheet(
      context: context,
      showDragHandle: true,
      builder: (_) => _PendingUploadsSheet(albumId: albumId),
    );
  }
}

class _PendingUploadsBannerDelegate extends SliverPersistentHeaderDelegate {
  final double height;
  final Widget child;

  const _PendingUploadsBannerDelegate({required this.height, required this.child});

  @override
  double get minExtent => height;

  @override
  double get maxExtent => height;

  @override
  Widget build(BuildContext context, double shrinkOffset, bool overlapsContent) => child;

  @override
  bool shouldRebuild(covariant _PendingUploadsBannerDelegate oldDelegate) =>
      height != oldDelegate.height || child != oldDelegate.child;
}

class _PendingUploadsBannerContent extends StatelessWidget {
  final String albumId;
  final BaseAsset previewAsset;
  final int count;
  final double overallProgress;
  final bool isIndeterminate;
  final bool hasFailures;

  const _PendingUploadsBannerContent({
    required this.albumId,
    required this.previewAsset,
    required this.count,
    required this.overallProgress,
    required this.isIndeterminate,
    required this.hasFailures,
  });

  @override
  Widget build(BuildContext context) {
    final percentLabel = isIndeterminate ? '' : ' · ${(overallProgress * 100).toInt()}%';
    return Material(
      color: hasFailures ? context.colorScheme.errorContainer : context.colorScheme.surfaceContainerHigh,
      child: InkWell(
        onTap: () => PendingUploadsBanner._openSheet(context, albumId),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            Expanded(
              child: Padding(
                padding: const EdgeInsets.symmetric(horizontal: 16),
                child: Row(
                  children: [
                    ClipRRect(
                      borderRadius: const BorderRadius.all(Radius.circular(4)),
                      child: SizedBox(width: 32, height: 32, child: Thumbnail.fromAsset(asset: previewAsset)),
                    ),
                    const SizedBox(width: 12),
                    Expanded(
                      child: Text(
                        '${'uploading'.t(context: context)} $count$percentLabel',
                        maxLines: 1,
                        overflow: TextOverflow.ellipsis,
                        style: context.textTheme.bodyMedium?.copyWith(fontWeight: FontWeight.w500),
                      ),
                    ),
                    if (hasFailures)
                      Padding(
                        padding: const EdgeInsets.only(left: 8),
                        child: Icon(Icons.error_outline, color: context.colorScheme.error, size: 20),
                      ),
                    Icon(Icons.chevron_right_rounded, color: context.colorScheme.onSurfaceVariant),
                  ],
                ),
              ),
            ),
            SizedBox(
              height: 3,
              child: LinearProgressIndicator(
                value: isIndeterminate ? null : overallProgress,
                backgroundColor: context.colorScheme.surfaceContainerHighest,
                valueColor: AlwaysStoppedAnimation<Color>(
                  hasFailures ? context.colorScheme.error : context.colorScheme.primary,
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _PendingUploadsSheet extends ConsumerWidget {
  final String albumId;

  const _PendingUploadsSheet({required this.albumId});

  @override
  Widget build(BuildContext context, WidgetRef ref) {
    final pending = ref.watch(pendingAlbumUploadsProvider(albumId));

    // Auto-dismiss when the queue empties.
    if (pending.isEmpty) {
      WidgetsBinding.instance.addPostFrameCallback((_) {
        if (Navigator.of(context).canPop()) {
          Navigator.of(context).pop();
        }
      });
      return const SizedBox.shrink();
    }

    final failedCount = pending.where((p) => p.failed).length;
    final inFlightCount = pending.length - failedCount;
    final canAbort = inFlightCount > 0 && ref.watch(manualUploadCancelTokenProvider) != null;

    return SafeArea(
      child: Padding(
        padding: const EdgeInsets.fromLTRB(16, 0, 16, 16),
        child: Column(
          mainAxisSize: MainAxisSize.min,
          crossAxisAlignment: CrossAxisAlignment.start,
          children: [
            Padding(
              padding: const EdgeInsets.only(bottom: 12),
              child: Row(
                children: [
                  Expanded(
                    child: Text(
                      '${'uploading'.t(context: context)} (${pending.length})',
                      style: context.textTheme.titleMedium,
                    ),
                  ),
                  if (canAbort)
                    TextButton.icon(
                      onPressed: () {
                        final cancelToken = ref.read(manualUploadCancelTokenProvider);
                        if (cancelToken != null && !cancelToken.isCompleted) {
                          cancelToken.complete();
                        }
                        ref.read(manualUploadCancelTokenProvider.notifier).state = null;
                        ref.read(pendingAlbumUploadsProvider(albumId).notifier).clear();
                      },
                      icon: const Icon(Icons.stop_circle_outlined, size: 18),
                      label: Text('cancel'.t(context: context)),
                      style: TextButton.styleFrom(foregroundColor: context.colorScheme.error),
                    )
                  else if (failedCount > 0)
                    TextButton.icon(
                      onPressed: () => ref.read(pendingAlbumUploadsProvider(albumId).notifier).clearFailed(),
                      icon: const Icon(Icons.clear_rounded, size: 18),
                      label: Text('clear_failed_count'.t(context: context, args: {'count': failedCount})),
                      style: TextButton.styleFrom(foregroundColor: context.colorScheme.error),
                    ),
                ],
              ),
            ),
            SizedBox(
              height: 96,
              child: ListView.separated(
                scrollDirection: Axis.horizontal,
                itemCount: pending.length,
                separatorBuilder: (_, __) => const SizedBox(width: 8),
                itemBuilder: (_, index) => _PendingUploadTile(entry: pending[index]),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _PendingUploadTile extends StatelessWidget {
  final PendingAlbumUpload entry;

  const _PendingUploadTile({required this.entry});

  @override
  Widget build(BuildContext context) {
    return ClipRRect(
      borderRadius: const BorderRadius.all(Radius.circular(8)),
      child: SizedBox(
        width: 96,
        height: 96,
        child: Stack(
          fit: StackFit.expand,
          children: [
            Thumbnail.fromAsset(asset: entry.asset),
            Positioned.fill(
              child: ColoredBox(
                color: entry.failed ? Colors.red.withValues(alpha: 0.6) : Colors.black54,
                child: Center(
                  child: entry.failed
                      ? const Icon(Icons.error_outline, color: Colors.white, size: 28)
                      : SizedBox(
                          width: 32,
                          height: 32,
                          child: CircularProgressIndicator(
                            value: entry.progress > 0 ? entry.progress : null,
                            strokeWidth: 2.5,
                            backgroundColor: Colors.white24,
                            valueColor: const AlwaysStoppedAnimation<Color>(Colors.white),
                          ),
                        ),
                ),
              ),
            ),
          ],
        ),
      ),
    );
  }
}
