/*
 * @Author: XianKaiQun
 * @Date: 2020-08-31 11:44:00
 * @LastEditors: ChenYaJin
 * @LastEditTime: 2022-11-16 17:31:43
 * @Description: 
 */

import 'dart:io';
import 'package:flutter/material.dart';
import 'package:flutter/services.dart';
import 'package:photo_manager/photo_manager.dart';
import 'package:wisdom_cli/wisdom_cli.dart';

///File实体类
///
///之后本地文件的选择有很多不可预料的东西，
///创建一个实体类之后能够达到兼容的效果。
class FileEntity {
  final File? file;

  FileEntity({this.file});
  static Future<FileEntity> formAssetFile(AssetEntity assetFile) async {
    return FileEntity(file: await assetFile.file);
  }
}

///让子组件获取到父级State
class _Scope extends InheritedWidget {
  _Scope({
    Key? key,
    required this.child,
    this.state,
  }) : super(key: key, child: child);

  final Widget child;
  final _WAlbumViewState? state;
  @override
  bool updateShouldNotify(_Scope oldWidget) {
    return oldWidget.state!.values != state!.values;
  }
}

///相册视图
class WAlbumView extends StatefulWidget {
  WAlbumView({
    Key? key,
    this.maxCount = 9,
  })  : assert(maxCount > 0),
        super(key: key);

  final int maxCount;

  ///推进路由栈
  static Future<List<FileEntity>?> pushRoute({
    int maxCount = 9,
  }) =>
      WNavUtil.instance!.push<List<FileEntity>>(
        MaterialPageRoute(
          builder: (_) => WAlbumView(
            maxCount: maxCount,
          ),
        ),
      );

  static _WAlbumViewState? _of(BuildContext context) {
    return context.dependOnInheritedWidgetOfExactType<_Scope>()!.state;
  }

  @override
  _WAlbumViewState createState() => _WAlbumViewState();
}

class _WAlbumViewState extends State<WAlbumView> {
  ///是否多选
  bool get multi => widget.maxCount > 1;

  ///目录
  List<AssetPathEntity> paths = [];

  ///当前选择的目录
  AssetPathEntity? currentPaths;

  ///获取目录
  Future<void> getPaths() async {
    paths = await PhotoManager.getAssetPathList(
      type: RequestType.image,
    );
    if (paths.length > 0) {
      currentPaths = paths[0];
      setState(() {});
    } else {
      WToastUtil.show('手机相册暂无照片呢');
    }
  }

  var albums = <AssetPathEntity>[];

  GlobalKey globalKey = GlobalKey();
  OverlayEntry? entry;
  onChangeCurrentPath() {
    if (entry != null) {
      entry?.remove();
      entry = null;
      setState(() {});

      return;
    }

    final RenderBox renderBox =
        globalKey.currentContext?.findRenderObject() as RenderBox;
    final offset = renderBox.localToGlobal(Offset.zero);
    final size = renderBox.size;

    entry = OverlayEntry(
      builder: (context) {
        return Positioned.fill(
          top: offset.dy + size.height,
          child: GestureDetector(
            onTap: () {
              entry?.remove();
              entry = null;
            },
            child: Material(
              color: Colors.black26,
              child: Wisdom(
                margin: EdgeInsets.only(
                  bottom: MediaQuery.of(context).size.height / 2,
                ),
                color: Colors.white,
                child: ListView.builder(
                  itemCount: paths.length,
                  itemBuilder: (_, i) {
                    return Wisdom(
                      padding: EdgeInsets.symmetric(horizontal: 20.pt),
                      height: 44.pt,
                      onTap: () => changeCurrentPath(paths[i]),
                      child: Text(
                        paths[i].isAll ? '全部' : paths[i].name,
                        maxLines: 1,
                        overflow: TextOverflow.ellipsis,
                      ),
                    );
                  },
                ),
              ),
            ),
          ),
        );
      },
    );
    Overlay.of(context).insert(entry!);
    setState(() {});
  }

  ///切换目录
  void changeCurrentPath(AssetPathEntity path) {
    entry?.remove();
    entry = null;
    currentPaths = path;
    list = [];
    page = 0;
    setState(() {});
    getList();
  }

  ///当前目录的列表
  List<AssetEntity> list = [];

  int page = 0;

  ///请求列表
  Future<void> getList() async {
    var _list = await currentPaths!.getAssetListPaged(
      page: page,
      size: 50,
    );
    if (_list.length > 0) {
      page = page + 1;
      list.addAll(_list);
    }

    setState(() {});
  }

  ///缓存
  Map<String, Uint8List?> cache = {};
  Future<Uint8List?> onCache(AssetEntity data) async {
    if (cache[data.id] == null) {
      cache[data.id] =
          await data.thumbnailDataWithSize(ThumbnailSize(100, 100));
    }
    return cache[data.id];
  }

  @override
  void dispose() {
    cache = {};
    entry?.remove();
    super.dispose();
  }

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

  onInit() async {
    page = 0;
    setState(() {});
    getPaths().then((value) {
      ///稍微延迟一下，防止低端机在路由动画期间卡顿
      Future.delayed(Duration(milliseconds: 200)).then((value) {
        getList();
      });
    });
  }

  ///当前选中
  List<AssetEntity?> values = [];

  ///选中事件
  void onPick(AssetEntity? data) {
    if (widget.maxCount == 1) {
      values = [data];
    } else if (values.indexOf(data) == -1) {
      if (values.length >= widget.maxCount && widget.maxCount != 1) {
        WToastUtil.show('已超出最大选择数目');
        return;
      } else {
        values.add(data);
      }
    } else {
      values.remove(data);
    }
    setState(() {});
  }

  ///确定 ,
  ///循环转换实体类
  Future<void> pop() async {
    final futures = values.map((e) => FileEntity.formAssetFile(e!)).toList();
    final _values = await Future.wait(futures);
    WNavUtil.instance!.pop(_values);
  }

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

    return _Scope(
      state: this,
      child: Scaffold(
        appBar: AppBar(
          key: globalKey,
          centerTitle: true,
          backgroundColor: Colors.white,
          leading: CloseButton(),
          iconTheme: IconThemeData(color: Colors.black),
          title: TextButton(
            onPressed: () => onChangeCurrentPath(),
            style: ButtonStyle(
              foregroundColor: MaterialStateProperty.all(
                Colors.black,
              ),
            ),
            child: Row(
              mainAxisSize: MainAxisSize.min,
              children: [
                if (currentPaths != null)
                  Text(
                    currentPaths!.isAll ? '全部' : (currentPaths?.name ?? '未知'),
                  ),
                Icon(entry == null ? FaIcons.angle_down : FaIcons.angle_up)
              ],
            ),
          ),
          systemOverlayStyle: SystemUiOverlayStyle.dark,
        ),
        body: WisScrollView(
          onInit: () => onInit(),
          onLoad: () => getList(),
          slivers: [
            WisSliverGrid(
              count: list.length,
              crossAxisCount: 4,
              padding: EdgeInsets.all(2.pt),
              mainAxisSpacing: 2.pt,
              crossAxisSpacing: 2.pt,
              builder: (_, i) => _GridItem(
                data: list[i],
                color: color,
              ),
            ),
          ],
        ),
        bottomNavigationBar: _BottomBar(),
      ),
    );
  }
}

class _BottomBar extends StatelessWidget {
  const _BottomBar({Key? key}) : super(key: key);

  @override
  Widget build(BuildContext context) {
    final state = WAlbumView._of(context)!;
    final countText =
        state.multi ? ' ${state.values.length}/${state.widget.maxCount}' : '';

    return BottomAppBar(
      child: Wisdom.row(
        padding: EdgeInsets.symmetric(horizontal: 15),
        children: [
          // Text('预览'),
          // Text('原图'),
          Spacer(),
          WLoadingButton(
            remain: true,
            onPressed: state.values.length == 0 ? null : () => state.pop(),
            padding: EdgeInsets.symmetric(horizontal: 10),
            height: 30.pt,
            minWidth: 50.pt,
            child: Text(
              '确定' + countText,
            ),
          ),
        ],
      ),
    );
  }
}

class _GridItem extends StatelessWidget {
  _GridItem({
    Key? key,
    this.data,
    this.color,
  }) : super(key: key);
  final AssetEntity? data;
  final Color? color;

  @override
  Widget build(BuildContext context) {
    final state = WAlbumView._of(context)!;
    final active = state.values.indexOf(data) != -1;
    // final title = data.title ?? '';
    // final formatList = title.split('.');
    // final format = formatList.length > 0 ? formatList.last.toUpperCase() : '';
    Widget current;
    if (state.cache[data!.id] != null)
      current = WImage.memory(
        state.cache[data!.id]!,
        fit: BoxFit.cover,
      );
    else
      current = FutureBuilder<Uint8List?>(
        future: state.onCache(data!),
        builder: (_, snapshot) {
          if (snapshot.connectionState == ConnectionState.done) {
            switch (data?.type) {
              case AssetType.image:
                return WImage.memory(
                  snapshot.data ?? Uint8List(0),
                  fit: BoxFit.cover,
                );

              default:
                return ColoredBox(color: Colors.white);
            }
          } else {
            return ColoredBox(color: Colors.white);
          }
        },
      );
    Widget? dot;
    if (active)
      dot = state.widget.maxCount != 1
          ? Text(
              '${state.values.indexOf(data) + 1}',
              style: TextStyle(
                fontSize: 11,
                fontWeight: FontWeight.bold,
                color: Colors.white,
              ),
            )
          : Icon(
              Icons.check,
              color: Colors.white,
              size: 15,
            );

    dot = Wisdom(
      alignment: Alignment.center,
      minWidth: 22,
      minHeight: 22,
      color: active ? color : Colors.black.withOpacity(0.1),
      border: active ? null : Border.all(color: Colors.white, width: 2),
      borderRadius: BorderRadius.circular(11),
      child: dot,
    );

    current = GestureDetector(
      child: Stack(
        alignment: Alignment.center,
        fit: StackFit.expand,
        children: [
          current,
          if (active)
            Positioned.fill(
              child: ColoredBox(
                color: Colors.black.withOpacity(0.4),
              ),
            ),
          Positioned(
            right: 0,
            top: 0,
            child: Wisdom(
              onTap: () => state.onPick(data),
              padding: EdgeInsets.all(4),
              child: dot,
            ),
          ),
        ],
      ),
    );

    return current;
  }
}
