/// Debug browser for SFX and music assets with playback controls.
library;

import 'dart:async';

import 'package:flutter/material.dart';
import 'package:wolf_3d_dart/wolf_3d_data_types.dart';
import 'package:wolf_3d_dart/wolf_3d_synth.dart';
import 'package:wolf_3d_flutter/wolf_3d_flutter.dart';
import 'package:wolf_3d_gui/screens/gallery_game_selector.dart';

class _AudioRow {
  final int id;
  final List<String> aliases;

  const _AudioRow({required this.id, required this.aliases});

  String get subtitle {
    if (aliases.isEmpty) {
      return 'No known alias';
    }
    return aliases.join(', ');
  }
}

/// Displays all decoded SFX and music tracks for the selected game data.
class AudioGallery extends StatefulWidget {
  /// Shared app facade used to access game assets and the audio backend.
  final Wolf3d wolf3d;

  const AudioGallery({super.key, required this.wolf3d});

  @override
  State<AudioGallery> createState() => _AudioGalleryState();
}

class _AudioGalleryState extends State<AudioGallery> {
  late WolfensteinData _selectedGame;
  int? _playingMusicTrackIndex;

  int _gridColumnsForWidth(double width) {
    if (width >= 1400) return 6;
    if (width >= 1100) return 5;
    if (width >= 800) return 4;
    if (width >= 560) return 3;
    return 2;
  }

  @override
  void initState() {
    super.initState();
    _selectedGame =
        widget.wolf3d.maybeActiveGame ?? widget.wolf3d.availableGames.first;
  }

  @override
  void dispose() {
    // Ensure debug playback does not continue after closing the gallery.
    unawaited(widget.wolf3d.audio.stopAllAudio());
    super.dispose();
  }

  Map<int, List<String>> _buildSfxAliases() {
    final Map<int, Set<String>> aliasesById = {};
    for (final key in SoundEffect.values) {
      final ref = _selectedGame.registry.sfx.resolve(key);
      if (ref == null) {
        continue;
      }
      aliasesById
          .putIfAbsent(ref.slotIndex, () => <String>{})
          .add(_readableKeyName(key.name));
    }

    return aliasesById.map(
      (id, aliases) => MapEntry(id, aliases.toList()..sort()),
    );
  }

  Map<int, List<String>> _buildMusicAliases() {
    final Map<int, Set<String>> aliasesById = {};
    for (final key in Music.values) {
      final route = _selectedGame.registry.music.resolve(key);
      if (route == null) {
        continue;
      }
      aliasesById
          .putIfAbsent(route.trackIndex, () => <String>{})
          .add(_readableKeyName(key.name));
    }

    return aliasesById.map(
      (id, aliases) => MapEntry(id, aliases.toList()..sort()),
    );
  }

  String _readableKeyName(String raw) {
    if (raw.isEmpty) {
      return raw;
    }

    return raw.replaceAllMapped(
      RegExp(r'([a-z0-9])([A-Z])'),
      (match) => '${match.group(1)} ${match.group(2)}',
    );
  }

  Future<void> _stopAllAudioPlayback() async {
    await widget.wolf3d.audio.stopAllAudio();
    if (!mounted) {
      return;
    }
    setState(() {
      _playingMusicTrackIndex = null;
    });
  }

  Future<void> _selectGame(WolfensteinData game) async {
    if (identical(_selectedGame, game)) {
      return;
    }

    await _stopAllAudioPlayback();
    widget.wolf3d.setActiveGame(game);
    if (!mounted) {
      return;
    }
    setState(() {
      _selectedGame = game;
      _playingMusicTrackIndex = null;
    });
  }

  void _playSfx(int id) {
    widget.wolf3d.audio.playSoundEffectId(id);
  }

  Future<void> _toggleMusic(int trackIndex) async {
    if (_playingMusicTrackIndex == trackIndex) {
      await _stopAllAudioPlayback();
      return;
    }

    final engineAudio = widget.wolf3d.audio;
    if (engineAudio is! WolfAudio) {
      return;
    }

    if (trackIndex < 0 || trackIndex >= _selectedGame.music.length) {
      return;
    }

    await engineAudio.playMusic(_selectedGame.music[trackIndex]);
    if (!mounted) {
      return;
    }
    setState(() {
      _playingMusicTrackIndex = trackIndex;
    });
  }

  @override
  Widget build(BuildContext context) {
    return DefaultTabController(
      length: 2,
      child: Scaffold(
        appBar: AppBar(
          title: const Text('Audio Gallery'),
          actions: [
            if (widget.wolf3d.availableGames.length > 1)
              GalleryGameSelector(
                wolf3d: widget.wolf3d,
                selectedGame: _selectedGame,
                onSelected: (game) {
                  unawaited(_selectGame(game));
                },
              ),
          ],
          bottom: const TabBar(
            tabs: [
              Tab(icon: Icon(Icons.graphic_eq), text: 'SFX'),
              Tab(icon: Icon(Icons.music_note), text: 'Music'),
            ],
          ),
        ),
        body: TabBarView(
          children: [
            _buildSfxTab(),
            _buildMusicTab(),
          ],
        ),
      ),
    );
  }

  Widget _buildSfxTab() {
    final aliasesById = _buildSfxAliases();
    final rows = List<_AudioRow>.generate(
      _selectedGame.sounds.length,
      (id) => _AudioRow(id: id, aliases: aliasesById[id] ?? const []),
    );

    if (rows.isEmpty) {
      return const Center(child: Text('No SFX available in this game data.'));
    }

    return Column(
      children: [
        const ListTile(
          leading: Icon(Icons.info_outline),
          title: Text('Tap any SFX to play it once'),
        ),
        Expanded(
          child: LayoutBuilder(
            builder: (context, constraints) {
              final columns = _gridColumnsForWidth(constraints.maxWidth);
              return GridView.builder(
                padding: const EdgeInsets.all(8),
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: columns,
                  crossAxisSpacing: 8,
                  mainAxisSpacing: 8,
                  childAspectRatio: 2.8,
                ),
                itemCount: rows.length,
                itemBuilder: (context, index) {
                  final row = rows[index];
                  return Card(
                    child: InkWell(
                      borderRadius: BorderRadius.circular(12),
                      onTap: () => _playSfx(row.id),
                      child: Padding(
                        padding: const EdgeInsets.symmetric(
                          horizontal: 12,
                          vertical: 10,
                        ),
                        child: Row(
                          children: [
                            CircleAvatar(child: Text('${row.id}')),
                            const SizedBox(width: 10),
                            Expanded(
                              child: Column(
                                mainAxisAlignment: MainAxisAlignment.center,
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                  Text(
                                    'SFX ${row.id}',
                                    style: Theme.of(
                                      context,
                                    ).textTheme.titleSmall,
                                  ),
                                  const SizedBox(height: 2),
                                  Text(
                                    row.subtitle,
                                    maxLines: 2,
                                    overflow: TextOverflow.ellipsis,
                                    style: Theme.of(
                                      context,
                                    ).textTheme.bodySmall,
                                  ),
                                ],
                              ),
                            ),
                            const Icon(Icons.play_arrow),
                          ],
                        ),
                      ),
                    ),
                  );
                },
              );
            },
          ),
        ),
      ],
    );
  }

  Widget _buildMusicTab() {
    final aliasesById = _buildMusicAliases();
    final rows = List<_AudioRow>.generate(
      _selectedGame.music.length,
      (id) => _AudioRow(id: id, aliases: aliasesById[id] ?? const []),
    );

    if (rows.isEmpty) {
      return const Center(
        child: Text('No music tracks available in this game data.'),
      );
    }

    return Column(
      children: [
        ListTile(
          leading: const Icon(Icons.info_outline),
          title: const Text('Tap a track to play, tap again to stop'),
          subtitle: Text(
            _playingMusicTrackIndex == null
                ? 'No track currently playing'
                : 'Playing track ${_playingMusicTrackIndex!}',
          ),
          trailing: FilledButton.icon(
            onPressed: _playingMusicTrackIndex == null
                ? null
                : () {
                    unawaited(_stopAllAudioPlayback());
                  },
            icon: const Icon(Icons.stop),
            label: const Text('Stop'),
          ),
        ),
        Expanded(
          child: LayoutBuilder(
            builder: (context, constraints) {
              final columns = _gridColumnsForWidth(constraints.maxWidth);
              return GridView.builder(
                padding: const EdgeInsets.all(8),
                gridDelegate: SliverGridDelegateWithFixedCrossAxisCount(
                  crossAxisCount: columns,
                  crossAxisSpacing: 8,
                  mainAxisSpacing: 8,
                  childAspectRatio: 2.8,
                ),
                itemCount: rows.length,
                itemBuilder: (context, index) {
                  final row = rows[index];
                  final bool isPlaying = _playingMusicTrackIndex == row.id;

                  return Card(
                    color: isPlaying
                        ? Theme.of(context).colorScheme.primaryContainer
                        : null,
                    child: InkWell(
                      borderRadius: BorderRadius.circular(12),
                      onTap: () {
                        unawaited(_toggleMusic(row.id));
                      },
                      child: Padding(
                        padding: const EdgeInsets.symmetric(
                          horizontal: 12,
                          vertical: 10,
                        ),
                        child: Row(
                          children: [
                            CircleAvatar(child: Text('${row.id}')),
                            const SizedBox(width: 10),
                            Expanded(
                              child: Column(
                                mainAxisAlignment: MainAxisAlignment.center,
                                crossAxisAlignment: CrossAxisAlignment.start,
                                children: [
                                  Text(
                                    'Track ${row.id}',
                                    style: Theme.of(
                                      context,
                                    ).textTheme.titleSmall,
                                  ),
                                  const SizedBox(height: 2),
                                  Text(
                                    row.subtitle,
                                    maxLines: 2,
                                    overflow: TextOverflow.ellipsis,
                                    style: Theme.of(
                                      context,
                                    ).textTheme.bodySmall,
                                  ),
                                ],
                              ),
                            ),
                            Icon(isPlaying ? Icons.stop : Icons.play_arrow),
                          ],
                        ),
                      ),
                    ),
                  );
                },
              );
            },
          ),
        ),
      ],
    );
  }
}
