import 'package:flutter/material.dart';

import '../domain/domain.dart';

final class TagBadgeWrap extends StatelessWidget {
  const TagBadgeWrap({required this.tags, this.maxVisible = 3, super.key});

  final List<String> tags;
  final int maxVisible;

  @override
  Widget build(BuildContext context) {
    if (tags.isEmpty) return const SizedBox.shrink();
    final visible = tags.take(maxVisible).toList();
    final remaining = tags.length - visible.length;
    return Wrap(
      spacing: 6,
      runSpacing: 6,
      children: [
        for (final tag in visible) TagChip(label: tag),
        if (remaining > 0) TagChip(label: '+$remaining'),
      ],
    );
  }
}

final class TagChip extends StatelessWidget {
  const TagChip({required this.label, this.onDeleted, super.key});

  final String label;
  final VoidCallback? onDeleted;

  @override
  Widget build(BuildContext context) {
    return Chip(
      visualDensity: VisualDensity.compact,
      label: Text(label),
      onDeleted: onDeleted,
      deleteIcon: onDeleted == null ? null : const Icon(Icons.close, size: 16),
    );
  }
}

final class LibraryTagFilters extends StatelessWidget {
  const LibraryTagFilters({
    required this.suggestions,
    required this.selectedTags,
    required this.onToggle,
    super.key,
  });

  final List<String> suggestions;
  final Set<String> selectedTags;
  final ValueChanged<String> onToggle;

  @override
  Widget build(BuildContext context) {
    if (suggestions.isEmpty) return const SizedBox.shrink();
    final visible = suggestions.take(12).toList();
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('Tags', style: Theme.of(context).textTheme.titleSmall),
        const SizedBox(height: 8),
        Wrap(
          spacing: 8,
          runSpacing: 8,
          children: [
            for (final tag in visible)
              FilterChip(
                label: Text(tag),
                selected: selectedTags.contains(tag),
                onSelected: (_) => onToggle(tag),
              ),
            if (suggestions.length > 12)
              ActionChip(
                label: const Text('Voir tous les tags'),
                onPressed: () => showTagFilterSheet(
                  context: context,
                  suggestions: suggestions,
                  selectedTags: selectedTags,
                  onToggle: onToggle,
                ),
              ),
          ],
        ),
      ],
    );
  }
}

final class EditableTagsSection extends StatelessWidget {
  const EditableTagsSection({
    required this.tags,
    required this.suggestions,
    required this.onChanged,
    this.description,
    super.key,
  });

  final List<String> tags;
  final List<String> suggestions;
  final ValueChanged<List<String>> onChanged;
  final String? description;

  @override
  Widget build(BuildContext context) {
    return Column(
      crossAxisAlignment: CrossAxisAlignment.start,
      children: [
        Text('Tags', style: Theme.of(context).textTheme.titleMedium),
        if (description != null) ...[
          const SizedBox(height: 4),
          Text(description!, style: Theme.of(context).textTheme.bodySmall),
        ],
        if (tags.isNotEmpty) ...[
          const SizedBox(height: 8),
          Wrap(
            spacing: 6,
            runSpacing: 6,
            children: [
              for (final tag in tags)
                TagChip(
                  label: tag,
                  onDeleted: () =>
                      onChanged(tags.where((item) => item != tag).toList()),
                ),
            ],
          ),
        ],
        const SizedBox(height: 8),
        OutlinedButton.icon(
          onPressed: () => _addTag(context),
          icon: const Icon(Icons.add),
          label: const Text('Ajouter un tag'),
        ),
      ],
    );
  }

  Future<void> _addTag(BuildContext context) async {
    if (tags.length >= 8) {
      _showSnackBar(context, "Tu peux ajouter jusqu'à 8 tags.");
      return;
    }
    final tag = await showModalBottomSheet<String>(
      context: context,
      isScrollControlled: true,
      useSafeArea: true,
      builder: (context) =>
          _AddTagSheet(existingTags: tags, suggestions: suggestions),
    );
    if (tag == null) return;
    onChanged([...tags, tag]);
  }
}

Future<void> showTagFilterSheet({
  required BuildContext context,
  required List<String> suggestions,
  required Set<String> selectedTags,
  required ValueChanged<String> onToggle,
}) {
  return showModalBottomSheet<void>(
    context: context,
    isScrollControlled: true,
    useSafeArea: true,
    builder: (context) => _TagFilterSheet(
      suggestions: suggestions,
      selectedTags: selectedTags,
      onToggle: onToggle,
    ),
  );
}

final class _AddTagSheet extends StatefulWidget {
  const _AddTagSheet({required this.existingTags, required this.suggestions});

  final List<String> existingTags;
  final List<String> suggestions;

  @override
  State<_AddTagSheet> createState() => _AddTagSheetState();
}

final class _AddTagSheetState extends State<_AddTagSheet> {
  final _controller = TextEditingController();
  String? _error;

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final bottom = MediaQuery.viewInsetsOf(context).bottom;
    final suggestions = widget.suggestions
        .where((tag) => !widget.existingTags.contains(tag))
        .take(12)
        .toList();
    return Padding(
      padding: EdgeInsets.fromLTRB(20, 0, 20, bottom + 20),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('Ajouter un tag', style: Theme.of(context).textTheme.titleLarge),
          const SizedBox(height: 16),
          TextField(
            controller: _controller,
            autofocus: true,
            decoration: InputDecoration(
              labelText: 'Nom du tag',
              errorText: _error,
            ),
            onSubmitted: (_) => _submit(),
          ),
          if (suggestions.isNotEmpty) ...[
            const SizedBox(height: 16),
            Text(
              'Tags existants',
              style: Theme.of(context).textTheme.titleSmall,
            ),
            const SizedBox(height: 8),
            Wrap(
              spacing: 8,
              runSpacing: 8,
              children: [
                for (final tag in suggestions)
                  ActionChip(
                    label: Text(tag),
                    onPressed: () {
                      _controller.text = tag;
                      _submit();
                    },
                  ),
              ],
            ),
          ],
          const SizedBox(height: 16),
          Row(
            mainAxisAlignment: MainAxisAlignment.end,
            children: [
              TextButton(
                onPressed: () => Navigator.of(context).pop(),
                child: const Text('Annuler'),
              ),
              const SizedBox(width: 8),
              FilledButton(onPressed: _submit, child: const Text('Ajouter')),
            ],
          ),
        ],
      ),
    );
  }

  void _submit() {
    final value = _controller.text;
    final normalized = _validateTag(value);
    if (normalized == null) return;
    Navigator.of(context).pop(normalized);
  }

  String? _validateTag(String value) {
    try {
      final normalized = normalizeTags([value]).singleOrNull;
      if (normalized == null) {
        setState(() => _error = 'Saisis un tag.');
        return null;
      }
      if (widget.existingTags.contains(normalized)) {
        setState(() => _error = 'Ce tag est déjà ajouté.');
        return null;
      }
      return normalized;
    } on DomainException catch (error) {
      setState(() => _error = _tagErrorLabel(error));
      return null;
    }
  }
}

final class _TagFilterSheet extends StatefulWidget {
  const _TagFilterSheet({
    required this.suggestions,
    required this.selectedTags,
    required this.onToggle,
  });

  final List<String> suggestions;
  final Set<String> selectedTags;
  final ValueChanged<String> onToggle;

  @override
  State<_TagFilterSheet> createState() => _TagFilterSheetState();
}

final class _TagFilterSheetState extends State<_TagFilterSheet> {
  final _controller = TextEditingController();
  late Set<String> _selectedTags;

  @override
  void initState() {
    super.initState();
    _selectedTags = Set<String>.of(widget.selectedTags);
    _controller.addListener(() => setState(() {}));
  }

  @override
  void dispose() {
    _controller.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final query = _controller.text.trim().toLowerCase();
    final filtered = widget.suggestions
        .where((tag) => query.isEmpty || tag.contains(query))
        .toList();
    return Padding(
      padding: const EdgeInsets.fromLTRB(20, 0, 20, 20),
      child: Column(
        mainAxisSize: MainAxisSize.min,
        crossAxisAlignment: CrossAxisAlignment.start,
        children: [
          Text('Tags', style: Theme.of(context).textTheme.titleLarge),
          const SizedBox(height: 16),
          TextField(
            controller: _controller,
            decoration: const InputDecoration(
              labelText: 'Rechercher un tag',
              prefixIcon: Icon(Icons.search),
            ),
          ),
          const SizedBox(height: 16),
          Flexible(
            child: SingleChildScrollView(
              child: Wrap(
                spacing: 8,
                runSpacing: 8,
                children: [
                  for (final tag in filtered)
                    FilterChip(
                      label: Text(tag),
                      selected: _selectedTags.contains(tag),
                      onSelected: (_) {
                        widget.onToggle(tag);
                        setState(() {
                          if (_selectedTags.contains(tag)) {
                            _selectedTags.remove(tag);
                          } else {
                            _selectedTags.add(tag);
                          }
                        });
                      },
                    ),
                ],
              ),
            ),
          ),
        ],
      ),
    );
  }
}

String _tagErrorLabel(DomainException error) {
  return switch (error.message) {
    'Tag must not be blank.' => 'Saisis un tag.',
    'Tag must be 24 characters or less.' =>
      'Un tag contient 24 caractères maximum.',
    'Tags must be unique.' => 'Ce tag est déjà ajouté.',
    'An item cannot have more than 8 tags.' =>
      "Tu peux ajouter jusqu'à 8 tags.",
    _ => error.message,
  };
}

void _showSnackBar(BuildContext context, String message) {
  ScaffoldMessenger.of(context).showSnackBar(SnackBar(content: Text(message)));
}
