import 'dart:convert';
import 'dart:math';

import 'package:dio/dio.dart';
import 'package:flutter/material.dart';
import 'package:flutter_screenutil/flutter_screenutil.dart';
import 'package:mnemo_cards/admin/add_card.dart';
import 'package:mnemo_cards/admin/admin_api.dart';
import 'package:mnemo_cards/di/injector.dart';
import 'package:mnemo_cards/managers/repository/dio_provider.dart';
import 'package:mnemo_cards/theme/themes.dart';
import 'package:mnemo_cards/widgets/header.dart';
import 'package:mnemo_cards_common/mnemo_cards_common.dart';

import '../main.dart';
import 'add_package.dart';

class AllCards extends StatefulWidget {
  @override
  State<StatefulWidget> createState() => _AllCardsState();

  const AllCards();
}

class _AllCardsState extends State<AllCards> {
  static List<String> ids = [];
  static Set<GameCardDto> cards = {};
  static String filter = '';
  static List<CardPackPreviewDto> _packPreviews = [];
  static EditCardPackDto? _currentPack;
  static String? _currentId;
  static List<String> _selectedCards = [];
  static Map<String, String> _cache = {};

  bool get selectingMode => _selectedCards.isNotEmpty;

  Dio get dio => getIt.get<DioProvider>().dio;

  AdminApi get api => getIt.get<AdminApi>();

  Future<void> loadCards() async {
    var loadingIds = ids.toList();
    cards.clear();
    _cache.clear();
    while (loadingIds.isNotEmpty) {
      try {
        final ids = loadingIds.take(20).toList();
        loadingIds.removeRange(0, ids.length);
        final cardsPage = await api.getCards(ids);
        for (final card in cardsPage) {
          final imageString =
              card.image?.substring(0, min(100, card.image!.length)) ?? '';
          _cache[card.id.toString()] =
              '${card.id}${card.mnemo}${card.transcription}${card.transcriptionMnemo}${card.original}${card.translation}${imageString}';
        }
        cards.addAll(cardsPage);
        setState(() {});
      } catch (e) {
        print(e);
      }
    }
  }

  Future<void> loadIds() async {
    ids = await api.getCardIds();
    setState(() {});
  }

  Future<void> loadPacks() async {
    _packPreviews = await api.packs();
    clearCurrentPack();
  }

  Future<void> loadCurrentPack() async {
    if (_currentId != null) {
      _currentPack = await api.getEditPack(_currentId!);
      setState(() {});
    }
  }

  void clearCurrentPack() {
    _currentId = null;
    _currentPack = null;
    setState(() {});
  }

  Future<void> editPack(EditCardPackDto pack) async {
    final result = await api.editPack(pack);
    if (!result) {
      ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar(
        content: Text('ERROR'),
      ));
    } else {
      ScaffoldMessenger.of(scaffoldKey.currentContext!).showSnackBar(SnackBar(
        content: Text('Success!!!'),
      ));
      loadCurrentPack();
      _selectedCards.clear();
    }
  }

  void addOrEditPack() => AddPackage(_currentPack, api).addPack(context);

  List<GameCardDto> buildCards() {
    final filteredCards = cards.where((dto) {
      final filterOk =
          filter.isEmpty || _cache[dto.id.toString()]?.contains(filter) == true;
      final packFilter =
          _currentPack?.addCardIds?.contains(dto.id.toString()) ?? true;
      return filterOk && packFilter;
    });
    return filteredCards.toList();
  }

  @override
  Widget build(BuildContext context) {
    final filteredCards = buildCards();
    return Scaffold(
      body: SafeArea(
        child: Stack(
          children: [
            ListView.builder(
                itemExtentBuilder: (index, dims) => index >= 1 ? 160.h : 350,
                itemBuilder: (context, index) {
                  if (index == 0)
                    return Column(
                      children: [
                        Header(
                          _currentId == null
                              ? 'Все карточки'
                              : _currentPack?.title ??
                                  'Пак ${_currentPack?.id}',
                          subtitle: filteredCards.isEmpty
                              ? 'Нет карточек'
                              : '${filteredCards.length} карточек',
                          hasPopButton: true,
                          trail: IconButton(
                              onPressed: () async {
                                setState(() {});
                                await loadIds();
                                await loadPacks();
                                await loadCards();
                              },
                              icon: Icon(Icons.sync)),
                        ),
                        dropdownButton(context),
                        Padding(
                          padding: const EdgeInsets.all(8.0),
                          child: TextField(
                            decoration: InputDecoration(hintText: 'Поиск'),
                            onChanged: (v) {
                              if (filter != v.toLowerCase()) {
                                filter = v.toLowerCase();
                                setState(() {});
                              }
                            },
                          ),
                        ),
                        Expanded(
                          child: GestureDetector(
                            onTap: () => EditCard(null, api).addCard(context),
                            child: Container(
                              color: Colors.green.withOpacity(0.1),
                              alignment: Alignment.center,
                              child: Icon(Icons.add, size: 30),
                            ),
                          ),
                        ),
                      ],
                    );
                  if (filteredCards.length >= (index - 1) * 3) {
                    final cardIndex = (index - 1) * 3;
                    return Row(
                      children: [
                        if (filteredCards.length > cardIndex)
                          cardWidget(filteredCards[cardIndex]),
                        if (filteredCards.length > cardIndex + 1)
                          cardWidget(filteredCards[cardIndex + 1]),
                        if (filteredCards.length > cardIndex + 2)
                          cardWidget(filteredCards[cardIndex + 2]),
                      ],
                    );
                  }
                  return null;
                }),
            if (selectingMode)
              Align(
                alignment: Alignment.bottomCenter,
                child: Container(
                  height: 100,
                  padding: EdgeInsets.all(10.0),
                  alignment: Alignment.center,
                  child: Row(
                    children: [
                      GestureDetector(
                        onTap: () {
                          _selectedCards.clear();
                          setState(() {});
                        },
                        child: Container(
                          color: Colors.blue,
                          padding: EdgeInsets.all(8.0),
                          child: Row(
                            children: [
                              Text('${_selectedCards.length} '),
                              Icon(Icons.clear)
                            ],
                          ),
                        ),
                      ),
                      if (_currentPack != null)
                        if (_selectedCards.every((c) =>
                            _currentPack!.addCardIds?.contains(c) ?? false))
                          Row(
                            children: [
                              SizedBox(width: 8.0),
                              GestureDetector(
                                onTap: () {
                                  final updated =
                                      _currentPack!.copyWith.removeCardIds(
                                    _selectedCards.toList(),
                                  );
                                  editPack(updated);
                                },
                                child: Container(
                                  padding: EdgeInsets.all(8.0),
                                  color: Colors.blue,
                                  child: Text('Убрать из пака'),
                                ),
                              ),
                              SizedBox(width: 8.0),
                              GestureDetector(
                                onTap: () {
                                  final updated =
                                      _currentPack!.copyWith.previewCards(
                                    _selectedCards.toList(),
                                  );
                                  editPack(updated);
                                },
                                child: Container(
                                  padding: EdgeInsets.all(8.0),
                                  color: Colors.blue,
                                  child: Text('Как превью'),
                                ),
                              ),
                            ],
                          )
                        else
                          MaterialButton(
                            onPressed: () {
                              final updated = _currentPack!.copyWith.addCardIds(
                                _selectedCards.toList(),
                              );
                              editPack(updated);
                            },
                            child: Container(
                              padding: EdgeInsets.all(8.0),
                              color: Colors.blue,
                              child: Text('Добавить в пак'),
                            ),
                          )
                    ],
                  ),
                ),
              ),
          ],
        ),
      ),
    );
  }

  Widget cardWidget(GameCardDto card) {
    void toggleSelect() {
      final id = card.id.toString();
      if (_selectedCards.contains(id)) {
        _selectedCards.remove(id);
      } else {
        _selectedCards.add(card.id.toString());
      }
      setState(() {});
    }

    return GestureDetector(
      onTap: () {
        if (selectingMode) {
          toggleSelect();
        } else {
          EditCard(card, api).addCard(context);
        }
      },
      onLongPress: toggleSelect,
      child: _Card(card, api, _selectedCards.contains(card.id.toString())),
    );
  }

  void _onPackChanged(String? id) {
    if (id == null) {
      clearCurrentPack();
    } else {
      _currentId = id;
      loadCurrentPack();
    }
  }

  Widget dropdownButton(BuildContext context) {
    return Row(
      children: [
        Expanded(
          child: DropdownButton(
            items: [..._packPreviews, null]
                .map((p) => DropdownMenuItem<String?>(
                      child: Padding(
                        padding: const EdgeInsets.all(8.0),
                        child: p == null
                            ? Text('Все паки')
                            : Text('${p.title} ${p.cards}'),
                      ),
                      value: p?.id,
                    ))
                .toList(),
            value: _currentId,
            onChanged: (v) => _onPackChanged(v),
          ),
        ),
        IconButton(
          onPressed: addOrEditPack,
          icon: _currentPack == null ? Icon(Icons.add) : Icon(Icons.edit),
        ),
      ],
    );
  }
}

class _Card extends StatelessWidget {
  final GameCardDto cardDto;
  final AdminApi api;
  final bool selected;

  _Card(this.cardDto, this.api, this.selected);

  @override
  Widget build(BuildContext context) {
    final image = cardDto.image != null ? base64.decode(cardDto.image!) : null;
    return Container(
      padding: EdgeInsets.all(8.0),
      width: MediaQuery.of(context).size.width / 3,
      height: 160.h,
      decoration: BoxDecoration(
        border: Border.all(color: selected ? Colors.blue : borderGray),
        color: selected ? Colors.blue.withOpacity(0.2) : null,
      ),
      child: Column(children: [
        Text(cardDto.translation ?? ''),
        Text(cardDto.original ?? ''),
        if (image != null)
          Expanded(
            child: Image.memory(
              key: ObjectKey(cardDto.image),
              gaplessPlayback: true,
              image,
              fit: BoxFit.scaleDown,
            ),
          ),
      ]),
    );
  }
}
