import 'dart:io';

import 'package:dio/dio.dart';
import 'package:dismissible_page/dismissible_page.dart';
import 'package:easy_localization/easy_localization.dart';
import 'package:file_saver/file_saver.dart';
import 'package:flutter/foundation.dart';
import 'package:flutter/material.dart';
import 'package:gal/gal.dart';
import 'package:gap/gap.dart';
import 'package:google_fonts/google_fonts.dart';
import 'package:material_symbols_icons/symbols.dart';
import 'package:path/path.dart' show extension;
import 'package:photo_view/photo_view.dart';
import 'package:photo_view/photo_view_gallery.dart';
import 'package:provider/provider.dart';
import 'package:styled_widget/styled_widget.dart';
import 'package:surface/providers/sn_network.dart';
import 'package:surface/providers/user_directory.dart';
import 'package:surface/types/attachment.dart';
import 'package:surface/widgets/account/account_image.dart';
import 'package:surface/widgets/dialog.dart';
import 'package:surface/widgets/universal_image.dart';
import 'package:url_launcher/url_launcher_string.dart';
import 'package:uuid/uuid.dart';

class AttachmentZoomView extends StatefulWidget {
  final Iterable<SnAttachment> data;
  final int? initialIndex;
  final List<String?>? heroTags;

  const AttachmentZoomView({
    super.key,
    required this.data,
    this.initialIndex,
    this.heroTags,
  });

  @override
  State<AttachmentZoomView> createState() => _AttachmentZoomViewState();
}

class _AttachmentZoomViewState extends State<AttachmentZoomView> {
  late final PageController _pageController = PageController(initialPage: widget.initialIndex ?? 0);

  void _updatePage() {
    setState(() {
      if (_isCompletedDownload) {
        setState(() => _isCompletedDownload = false);
      }
    });
  }

  bool _isDownloading = false;
  bool _isCompletedDownload = false;
  double? _progressOfDownload = 0;

  Future<void> _saveToAlbum(int idx) async {
    final sn = context.read<SnNetworkProvider>();
    final item = widget.data.elementAt(idx);
    final url = sn.getAttachmentUrl(item.rid);

    if (kIsWeb || Platform.isLinux) {
      await launchUrlString(url);
      return;
    }

    setState(() => _isDownloading = true);

    var extName = extension(item.name);
    if (extName.isEmpty) extName = '.png';
    final imagePath = '${Directory.systemTemp.path}/${item.uuid}$extName';
    await Dio().download(
      url,
      imagePath,
      onReceiveProgress: (count, total) {
        setState(() => _progressOfDownload = count / total);
      },
    );

    bool isSuccess = false;
    try {
      if (!kIsWeb && (Platform.isAndroid || Platform.isIOS)) {
        if (!await Gal.hasAccess(toAlbum: true)) {
          if (!await Gal.requestAccess(toAlbum: true)) return;
        }
        await Gal.putImage(imagePath, album: 'Solar Network');
      } else {
        await FileSaver.instance.saveFile(
          name: item.name,
          file: File(imagePath),
        );
      }
      setState(() {
        isSuccess = true;
        _isDownloading = false;
        _isCompletedDownload = isSuccess;
      });
    } catch (e) {
      if (!mounted) return;
      context.showErrorDialog(e);
    }

    if (!mounted) return;
    context.showSnackbar(
      (!kIsWeb && (Platform.isIOS || Platform.isAndroid)) ? 'attachmentSaved'.tr() : 'attachmentSavedDesktop'.tr(),
      action: (!kIsWeb && (Platform.isIOS || Platform.isAndroid))
          ? SnackBarAction(
              label: 'openInAlbum'.tr(),
              onPressed: () async => Gal.open(),
            )
          : null,
    );
  }

  @override
  void initState() {
    super.initState();
    _pageController.addListener(_updatePage);
    Future.delayed(const Duration(milliseconds: 100), _updatePage);
  }

  @override
  void dispose() {
    _pageController.removeListener(_updatePage);
    _pageController.dispose();
    super.dispose();
  }

  Color get _unFocusColor => Theme.of(context).colorScheme.onSurface.withOpacity(0.75);

  @override
  Widget build(BuildContext context) {
    final sn = context.read<SnNetworkProvider>();
    final uuid = Uuid();

    final metaTextStyle = GoogleFonts.roboto(
      fontSize: 12,
      color: _unFocusColor,
      height: 1,
    );

    return DismissiblePage(
      onDismissed: () {
        Navigator.of(context).pop();
      },
      direction: DismissiblePageDismissDirection.down,
      backgroundColor: Colors.transparent,
      isFullScreen: true,
      child: Scaffold(
        body: Stack(
          children: [
            Builder(builder: (context) {
              if (widget.data.length == 1) {
                final heroTag = widget.heroTags?.first ?? uuid.v4();
                return Hero(
                  tag: 'attachment-${widget.data.first.rid}-$heroTag',
                  child: PhotoView(
                    key: Key('attachment-detail-${widget.data.first.rid}-$heroTag'),
                    backgroundDecoration: BoxDecoration(color: Colors.transparent),
                    imageProvider: UniversalImage.provider(
                      sn.getAttachmentUrl(widget.data.first.rid),
                    ),
                  ),
                );
              }

              return PhotoViewGallery.builder(
                pageController: _pageController,
                scrollPhysics: const BouncingScrollPhysics(),
                builder: (context, idx) {
                  final heroTag = widget.heroTags?.elementAt(idx) ?? uuid.v4();
                  return PhotoViewGalleryPageOptions(
                    imageProvider: UniversalImage.provider(
                      sn.getAttachmentUrl(widget.data.elementAt(idx).rid),
                    ),
                    heroAttributes: PhotoViewHeroAttributes(
                      tag: 'attachment-${widget.data.first.rid}-$heroTag',
                    ),
                  );
                },
                itemCount: widget.data.length,
                loadingBuilder: (context, event) => Center(
                  child: SizedBox(
                    width: 20.0,
                    height: 20.0,
                    child: CircularProgressIndicator(
                      value: event == null ? 0 : event.cumulativeBytesLoaded / (event.expectedTotalBytes ?? 1),
                    ),
                  ),
                ),
                backgroundDecoration: BoxDecoration(color: Colors.transparent),
              );
            }),
            Align(
              alignment: Alignment.bottomCenter,
              child: IgnorePointer(
                child: Container(
                  height: 300,
                  decoration: BoxDecoration(
                    gradient: LinearGradient(
                      begin: Alignment.bottomCenter,
                      end: Alignment.topCenter,
                      colors: [
                        Theme.of(context).colorScheme.surface,
                        Colors.transparent,
                      ],
                    ),
                  ),
                ),
              ),
            ),
            Positioned(
              left: 16,
              right: 16,
              bottom: 16 + MediaQuery.of(context).padding.bottom,
              child: Material(
                color: Colors.transparent,
                child: Builder(builder: (context) {
                  final ud = context.read<UserDirectoryProvider>();
                  final item = widget.data.elementAt(
                    widget.data.length > 1 ? _pageController.page?.round() ?? 0 : 0,
                  );
                  final account = ud.getAccountFromCache(item.accountId);

                  return Column(
                    crossAxisAlignment: CrossAxisAlignment.start,
                    children: [
                      if (item.accountId > 0)
                        Row(
                          children: [
                            IgnorePointer(
                              child: AccountImage(
                                content: account!.avatar,
                                radius: 19,
                              ),
                            ),
                            const Gap(8),
                            Expanded(
                              child: IgnorePointer(
                                child: Column(
                                  crossAxisAlignment: CrossAxisAlignment.start,
                                  children: [
                                    Text(
                                      'attachmentUploadBy'.tr(),
                                      style: Theme.of(context).textTheme.bodySmall,
                                    ),
                                    Text(
                                      account.nick,
                                      style: Theme.of(context).textTheme.bodyMedium,
                                    ),
                                  ],
                                ),
                              ),
                            ),
                            if (widget.data.length > 1)
                              IgnorePointer(
                                child: Text(
                                  '${(_pageController.page?.round() ?? 0) + 1}/${widget.data.length}',
                                  style: GoogleFonts.robotoMono(fontSize: 13),
                                ).padding(right: 8),
                              ),
                            InkWell(
                              borderRadius: const BorderRadius.all(Radius.circular(16)),
                              onTap: _isDownloading
                                  ? null
                                  : () => _saveToAlbum(widget.data.length > 1 ? _pageController.page?.round() ?? 0 : 0),
                              child: Container(
                                padding: const EdgeInsets.all(6),
                                child: !_isDownloading
                                    ? !_isCompletedDownload
                                        ? const Icon(Symbols.save_alt)
                                        : const Icon(Symbols.download_done)
                                    : SizedBox(
                                        width: 24,
                                        height: 24,
                                        child: CircularProgressIndicator(
                                          value: _progressOfDownload,
                                          strokeWidth: 3,
                                        ),
                                      ),
                              ),
                            ),
                          ],
                        ),
                      const Gap(4),
                      IgnorePointer(
                        child: Text(
                          item.alt,
                          maxLines: 2,
                          overflow: TextOverflow.ellipsis,
                          style: const TextStyle(
                            fontSize: 15,
                            fontWeight: FontWeight.w500,
                          ),
                        ),
                      ),
                      const Gap(2),
                      IgnorePointer(
                        child: Wrap(
                          spacing: 6,
                          children: [
                            if (item.metadata['exif'] == null)
                              Text(
                                '#${item.rid}',
                                style: metaTextStyle,
                              ),
                            if (item.metadata['exif']?['Model'] != null)
                              Text(
                                'attachmentShotOn'.tr(args: [
                                  item.metadata['exif']?['Model'],
                                ]),
                                style: metaTextStyle,
                              ).padding(right: 2),
                            if (item.metadata['exif']?['ShutterSpeed'] != null)
                              Text(
                                item.metadata['exif']?['ShutterSpeed'],
                                style: metaTextStyle,
                              ).padding(right: 2),
                            if (item.metadata['exif']?['ISO'] != null)
                              Text(
                                'ISO${item.metadata['exif']?['ISO']}',
                                style: metaTextStyle,
                              ).padding(right: 2),
                            if (item.metadata['exif']?['Aperture'] != null)
                              Text(
                                'f/${item.metadata['exif']?['Aperture']}',
                                style: metaTextStyle,
                              ).padding(right: 2),
                            if (item.metadata['exif']?['Megapixels'] != null && item.metadata['exif']?['Model'] != null)
                              Text(
                                '${item.metadata['exif']?['Megapixels']}MP',
                                style: metaTextStyle,
                              )
                            else
                              Text(
                                '${item.size} Bytes',
                                style: metaTextStyle,
                              ),
                            if (item.metadata['width'] != null && item.metadata['height'] != null)
                              Text(
                                '${item.metadata['width']}x${item.metadata['height']}',
                                style: metaTextStyle,
                              ),
                            if (item.metadata['ratio'] != null)
                              Text(
                                (item.metadata['ratio'] as num).toStringAsFixed(2),
                                style: metaTextStyle,
                              ),
                            Text(
                              item.mimetype,
                              style: metaTextStyle,
                            ),
                          ],
                        ),
                      ),
                    ],
                  );
                }),
              ),
            ),
          ],
        ),
      ),
    );
  }
}