import 'package:flutter/material.dart';
import 'package:flutter_riverpod/flutter_riverpod.dart';
import 'package:go_router/go_router.dart';

import '../../../brackets/domain/bracket.dart';
import '../../../events/domain/event.dart';
import '../../../teams/domain/team.dart';
import '../../../teams/infrastructure/teams_repository.dart';
import '../../application/admin_brackets_notifier.dart';
import '../../application/admin_events_notifier.dart';

/// Form for creating or editing a tournament bracket.
///
/// The shape (round count + matches per round) is set up front when creating.
/// After creation — or when editing — admins can adjust team labels, set
/// scores, change match status, and pick a winner per match.
class AdminBracketFormScreen extends ConsumerStatefulWidget {
  const AdminBracketFormScreen({super.key, this.bracketId});

  final String? bracketId;

  bool get isEdit => bracketId != null;

  @override
  ConsumerState<AdminBracketFormScreen> createState() =>
      _AdminBracketFormScreenState();
}

class _AdminBracketFormScreenState
    extends ConsumerState<AdminBracketFormScreen> {
  final _formKey = GlobalKey<FormState>();
  final _nameCtrl = TextEditingController();
  String? _eventId;
  DateTime _createdAt = DateTime.now();

  List<_RoundDraft> _rounds = <_RoundDraft>[];

  // Setup-mode controls (visible when creating a brand-new bracket)
  int _setupRounds = 3;
  int _setupTeams = 8;

  bool _hydrated = false;
  bool _submitting = false;

  @override
  void initState() {
    super.initState();
    if (!widget.isEdit) {
      _hydrated = true;
      _generateRounds(rounds: _setupRounds, teams: _setupTeams);
    }
  }

  @override
  void dispose() {
    _nameCtrl.dispose();
    for (final r in _rounds) {
      r.dispose();
    }
    super.dispose();
  }

  void _hydrateFrom(Bracket bracket) {
    if (_hydrated) return;
    _nameCtrl.text = bracket.name;
    _eventId = bracket.eventId.isEmpty ? null : bracket.eventId;
    _createdAt = bracket.createdAt;
    _rounds = bracket.rounds.map(_RoundDraft.fromRound).toList();
    _hydrated = true;
  }

  void _generateRounds({required int rounds, required int teams}) {
    // For a single-elimination shape, round 1 holds teams/2 matches, round 2
    // holds teams/4, etc. We round up to handle odd team counts gracefully.
    for (final r in _rounds) {
      r.dispose();
    }
    _rounds = <_RoundDraft>[];
    var matchesInRound = (teams / 2).ceil();
    for (var i = 0; i < rounds; i++) {
      _rounds.add(
        _RoundDraft(
          roundNumber: i + 1,
          label: _defaultRoundLabel(i, rounds),
          matches: List.generate(
            matchesInRound < 1 ? 1 : matchesInRound,
            (m) => _MatchDraft.empty(id: 'r${i + 1}_m${m + 1}'),
          ),
        ),
      );
      matchesInRound = (matchesInRound / 2).ceil();
    }
    setState(() {});
  }

  String _defaultRoundLabel(int index, int total) {
    final distanceFromEnd = total - 1 - index;
    switch (distanceFromEnd) {
      case 0:
        return 'Final';
      case 1:
        return 'Semifinals';
      case 2:
        return 'Quarterfinals';
      case 3:
        return 'Round of 16';
      default:
        return 'Round ${index + 1}';
    }
  }

  Future<void> _randomizeTeams() async {
    final messenger = ScaffoldMessenger.of(context);
    final List<Team> teams = await ref
        .read(teamsRepositoryProvider)
        .watchTeams()
        .first;
    if (!mounted) return;
    if (teams.length < 2) {
      messenger.showSnackBar(
        const SnackBar(
          content: Text('Need at least 2 teams in Firestore to randomize.'),
        ),
      );
      return;
    }
    if (_rounds.isEmpty || _rounds.first.matches.isEmpty) {
      messenger.showSnackBar(
        const SnackBar(content: Text('No round-1 matches to fill.')),
      );
      return;
    }

    final shuffled = List<Team>.of(teams)..shuffle();
    final round1 = _rounds.first;

    setState(() {
      var teamIdx = 0;
      for (final match in round1.matches) {
        if (teamIdx < shuffled.length) {
          final a = shuffled[teamIdx++];
          match.teamANameCtrl.text = a.name;
          match.teamAId = a.id;
        } else {
          match.teamANameCtrl.text = '';
          match.teamAId = null;
        }
        if (teamIdx < shuffled.length) {
          final b = shuffled[teamIdx++];
          match.teamBNameCtrl.text = b.name;
          match.teamBId = b.id;
        } else {
          match.teamBNameCtrl.text = '';
          match.teamBId = null;
        }
      }
    });

    messenger.showSnackBar(
      SnackBar(
        content: Text('Randomized ${shuffled.length} teams into round 1.'),
      ),
    );
  }

  Future<void> _submit() async {
    if (!(_formKey.currentState?.validate() ?? false)) return;
    if (_eventId == null || _eventId!.isEmpty) {
      ScaffoldMessenger.of(context).showSnackBar(
        const SnackBar(content: Text('Pick an event for this bracket.')),
      );
      return;
    }
    final id = widget.bracketId ?? '';
    final bracket = Bracket(
      id: id,
      eventId: _eventId!,
      name: _nameCtrl.text.trim(),
      createdAt: _createdAt,
      rounds: _rounds.map((r) => r.toRound()).toList(growable: false),
    );

    setState(() => _submitting = true);
    try {
      if (widget.isEdit) {
        await ref.read(adminBracketsNotifierProvider.notifier).save(bracket);
      } else {
        await ref.read(adminBracketsNotifierProvider.notifier).create(bracket);
      }
      if (!mounted) return;
      ScaffoldMessenger.of(context).showSnackBar(
        SnackBar(
          content: Text(widget.isEdit ? 'Bracket updated' : 'Bracket created'),
        ),
      );
      context.go('/admin/brackets');
    } catch (e) {
      if (!mounted) return;
      ScaffoldMessenger.of(
        context,
      ).showSnackBar(SnackBar(content: Text('Save failed: $e')));
    } finally {
      if (mounted) setState(() => _submitting = false);
    }
  }

  @override
  Widget build(BuildContext context) {
    if (widget.isEdit && !_hydrated) {
      final bracketsAsync = ref.watch(adminBracketsStreamProvider);
      final brackets = bracketsAsync.valueOrNull;
      if (brackets != null) {
        Bracket? match;
        for (final b in brackets) {
          if (b.id == widget.bracketId) {
            match = b;
            break;
          }
        }
        if (match != null) {
          final found = match;
          WidgetsBinding.instance.addPostFrameCallback((_) {
            if (!mounted) return;
            setState(() => _hydrateFrom(found));
          });
        }
      }
    }

    final eventsAsync = ref.watch(adminEventsStreamProvider);
    final theme = Theme.of(context);

    return Scaffold(
      appBar: AppBar(
        title: Text(widget.isEdit ? 'EDIT BRACKET' : 'NEW BRACKET'),
        leading: IconButton(
          icon: const Icon(Icons.close),
          onPressed: () => context.go('/admin/brackets'),
        ),
      ),
      body: SafeArea(
        child: Form(
          key: _formKey,
          child: ListView(
            padding: const EdgeInsets.all(16),
            children: <Widget>[
              TextFormField(
                controller: _nameCtrl,
                decoration: const InputDecoration(labelText: 'Bracket name'),
                validator: (v) =>
                    (v == null || v.trim().isEmpty) ? 'Required' : null,
              ),
              const SizedBox(height: 12),
              eventsAsync.when(
                loading: () => const LinearProgressIndicator(),
                error: (e, _) => Text('Could not load events: $e'),
                data: (events) => _EventPicker(
                  events: events,
                  selected: _eventId,
                  onChanged: (id) => setState(() => _eventId = id),
                ),
              ),
              if (!widget.isEdit) ...<Widget>[
                const SizedBox(height: 16),
                Align(
                  alignment: Alignment.centerLeft,
                  child: OutlinedButton.icon(
                    onPressed: _submitting ? null : _randomizeTeams,
                    icon: const Text('🎲', style: TextStyle(fontSize: 16)),
                    label: const Text('RANDOMIZE TEAMS'),
                  ),
                ),
              ],
              const SizedBox(height: 20),
              if (!widget.isEdit) ...<Widget>[
                Text(
                  'BRACKET SHAPE',
                  style: theme.textTheme.labelLarge?.copyWith(
                    letterSpacing: 1.5,
                  ),
                ),
                const SizedBox(height: 8),
                Row(
                  children: <Widget>[
                    Expanded(
                      child: _NumberStepper(
                        label: 'Rounds',
                        value: _setupRounds,
                        min: 1,
                        max: 6,
                        onChanged: (v) => setState(() {
                          _setupRounds = v;
                          _generateRounds(rounds: v, teams: _setupTeams);
                        }),
                      ),
                    ),
                    const SizedBox(width: 12),
                    Expanded(
                      child: _NumberStepper(
                        label: 'Teams in round 1',
                        value: _setupTeams,
                        min: 2,
                        max: 32,
                        step: 2,
                        onChanged: (v) => setState(() {
                          _setupTeams = v;
                          _generateRounds(rounds: _setupRounds, teams: v);
                        }),
                      ),
                    ),
                  ],
                ),
                const SizedBox(height: 16),
              ],
              ..._rounds.map(
                (round) => _RoundEditor(
                  round: round,
                  onChanged: () => setState(() {}),
                ),
              ),
              const SizedBox(height: 24),
              FilledButton.icon(
                onPressed: _submitting ? null : _submit,
                icon: _submitting
                    ? const SizedBox(
                        width: 16,
                        height: 16,
                        child: CircularProgressIndicator(strokeWidth: 2),
                      )
                    : const Icon(Icons.save_outlined),
                label: Text(widget.isEdit ? 'SAVE CHANGES' : 'CREATE BRACKET'),
              ),
            ],
          ),
        ),
      ),
    );
  }
}

class _EventPicker extends StatelessWidget {
  const _EventPicker({
    required this.events,
    required this.selected,
    required this.onChanged,
  });

  final List<Event> events;
  final String? selected;
  final ValueChanged<String?> onChanged;

  @override
  Widget build(BuildContext context) {
    final items = <DropdownMenuItem<String>>[
      const DropdownMenuItem<String>(
        value: null,
        child: Text('— select event —'),
      ),
      ...events.map(
        (e) => DropdownMenuItem<String>(
          value: e.id,
          child: Text(e.title, overflow: TextOverflow.ellipsis),
        ),
      ),
    ];

    final currentValue = events.any((e) => e.id == selected) ? selected : null;

    return DropdownButtonFormField<String>(
      initialValue: currentValue,
      items: items,
      onChanged: onChanged,
      decoration: const InputDecoration(labelText: 'Event'),
    );
  }
}

class _NumberStepper extends StatelessWidget {
  const _NumberStepper({
    required this.label,
    required this.value,
    required this.min,
    required this.max,
    required this.onChanged,
    this.step = 1,
  });

  final String label;
  final int value;
  final int min;
  final int max;
  final int step;
  final ValueChanged<int> onChanged;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Container(
      decoration: BoxDecoration(
        color: theme.colorScheme.surfaceContainerHighest,
        borderRadius: BorderRadius.circular(4),
      ),
      padding: const EdgeInsets.symmetric(horizontal: 12, vertical: 8),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Text(
            label,
            style: theme.textTheme.labelSmall?.copyWith(
              color: theme.colorScheme.onSurfaceVariant,
            ),
          ),
          Row(
            children: <Widget>[
              IconButton(
                icon: const Icon(Icons.remove),
                onPressed: value - step >= min
                    ? () => onChanged(value - step)
                    : null,
              ),
              Expanded(
                child: Text(
                  '$value',
                  textAlign: TextAlign.center,
                  style: theme.textTheme.titleLarge,
                ),
              ),
              IconButton(
                icon: const Icon(Icons.add),
                onPressed: value + step <= max
                    ? () => onChanged(value + step)
                    : null,
              ),
            ],
          ),
        ],
      ),
    );
  }
}

class _RoundEditor extends StatelessWidget {
  const _RoundEditor({required this.round, required this.onChanged});

  final _RoundDraft round;
  final VoidCallback onChanged;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Card(
      margin: const EdgeInsets.symmetric(vertical: 8),
      child: Padding(
        padding: const EdgeInsets.all(14),
        child: Column(
          crossAxisAlignment: CrossAxisAlignment.start,
          children: <Widget>[
            TextField(
              controller: round.labelCtrl,
              decoration: InputDecoration(
                labelText: 'Round ${round.roundNumber} label',
                hintText: 'e.g. Quarterfinals',
              ),
            ),
            const SizedBox(height: 12),
            for (var i = 0; i < round.matches.length; i++)
              _MatchEditor(
                index: i,
                match: round.matches[i],
                onChanged: onChanged,
              ),
            Align(
              alignment: Alignment.centerRight,
              child: TextButton.icon(
                onPressed: () {
                  round.matches.add(
                    _MatchDraft.empty(
                      id: 'r${round.roundNumber}_m${round.matches.length + 1}',
                    ),
                  );
                  onChanged();
                },
                icon: const Icon(Icons.add, size: 18),
                label: Text('Add match', style: theme.textTheme.labelMedium),
              ),
            ),
          ],
        ),
      ),
    );
  }
}

class _MatchEditor extends StatelessWidget {
  const _MatchEditor({
    required this.index,
    required this.match,
    required this.onChanged,
  });

  final int index;
  final _MatchDraft match;
  final VoidCallback onChanged;

  @override
  Widget build(BuildContext context) {
    final theme = Theme.of(context);
    return Container(
      margin: const EdgeInsets.only(bottom: 12),
      padding: const EdgeInsets.all(12),
      decoration: BoxDecoration(
        color: theme.colorScheme.surfaceContainerHighest,
        borderRadius: BorderRadius.circular(4),
        border: Border.all(color: theme.colorScheme.outlineVariant),
      ),
      child: Column(
        crossAxisAlignment: CrossAxisAlignment.start,
        children: <Widget>[
          Row(
            children: <Widget>[
              Text(
                'MATCH ${index + 1}',
                style: theme.textTheme.labelSmall?.copyWith(
                  letterSpacing: 1.2,
                  color: theme.colorScheme.onSurfaceVariant,
                ),
              ),
              const Spacer(),
              DropdownButton<MatchStatus>(
                value: match.status,
                onChanged: (v) {
                  if (v == null) return;
                  match.status = v;
                  onChanged();
                },
                items: MatchStatus.values
                    .map(
                      (s) => DropdownMenuItem<MatchStatus>(
                        value: s,
                        child: Text(_statusLabel(s)),
                      ),
                    )
                    .toList(),
              ),
            ],
          ),
          const SizedBox(height: 8),
          Row(
            children: <Widget>[
              Expanded(
                child: TextField(
                  controller: match.teamANameCtrl,
                  decoration: const InputDecoration(labelText: 'Team A'),
                ),
              ),
              const SizedBox(width: 8),
              SizedBox(
                width: 72,
                child: TextField(
                  controller: match.scoreACtrl,
                  keyboardType: TextInputType.number,
                  textAlign: TextAlign.center,
                  decoration: const InputDecoration(labelText: 'Score'),
                ),
              ),
            ],
          ),
          const SizedBox(height: 8),
          Row(
            children: <Widget>[
              Expanded(
                child: TextField(
                  controller: match.teamBNameCtrl,
                  decoration: const InputDecoration(labelText: 'Team B'),
                ),
              ),
              const SizedBox(width: 8),
              SizedBox(
                width: 72,
                child: TextField(
                  controller: match.scoreBCtrl,
                  keyboardType: TextInputType.number,
                  textAlign: TextAlign.center,
                  decoration: const InputDecoration(labelText: 'Score'),
                ),
              ),
            ],
          ),
          const SizedBox(height: 8),
          Row(
            children: <Widget>[
              Text(
                'Winner: ',
                style: theme.textTheme.labelMedium?.copyWith(
                  color: theme.colorScheme.onSurfaceVariant,
                ),
              ),
              const SizedBox(width: 4),
              Expanded(
                child: SegmentedButton<_WinnerSelection>(
                  segments: const <ButtonSegment<_WinnerSelection>>[
                    ButtonSegment(
                      value: _WinnerSelection.none,
                      label: Text('TBD'),
                    ),
                    ButtonSegment(
                      value: _WinnerSelection.teamA,
                      label: Text('A'),
                    ),
                    ButtonSegment(
                      value: _WinnerSelection.teamB,
                      label: Text('B'),
                    ),
                  ],
                  selected: <_WinnerSelection>{match.winner},
                  onSelectionChanged: (set) {
                    match.winner = set.first;
                    onChanged();
                  },
                ),
              ),
            ],
          ),
        ],
      ),
    );
  }

  String _statusLabel(MatchStatus s) {
    switch (s) {
      case MatchStatus.scheduled:
        return 'Scheduled';
      case MatchStatus.inProgress:
        return 'In progress';
      case MatchStatus.completed:
        return 'Completed';
    }
  }
}

enum _WinnerSelection { none, teamA, teamB }

class _RoundDraft {
  _RoundDraft({
    required this.roundNumber,
    required String label,
    required this.matches,
  }) : labelCtrl = TextEditingController(text: label);

  factory _RoundDraft.fromRound(BracketRound round) {
    return _RoundDraft(
      roundNumber: round.roundNumber,
      label: round.label,
      matches: round.matches.map(_MatchDraft.fromMatch).toList(),
    );
  }

  final int roundNumber;
  final TextEditingController labelCtrl;
  final List<_MatchDraft> matches;

  void dispose() {
    labelCtrl.dispose();
    for (final m in matches) {
      m.dispose();
    }
  }

  BracketRound toRound() {
    return BracketRound(
      roundNumber: roundNumber,
      label: labelCtrl.text.trim().isEmpty
          ? 'Round $roundNumber'
          : labelCtrl.text.trim(),
      matches: matches.map((m) => m.toMatch()).toList(growable: false),
    );
  }
}

class _MatchDraft {
  _MatchDraft({
    required this.id,
    required String teamA,
    required String teamB,
    required int? scoreA,
    required int? scoreB,
    required this.status,
    required this.winner,
    this.teamAId,
    this.teamBId,
  }) : teamANameCtrl = TextEditingController(text: teamA),
       teamBNameCtrl = TextEditingController(text: teamB),
       scoreACtrl = TextEditingController(
         text: scoreA == null ? '' : '$scoreA',
       ),
       scoreBCtrl = TextEditingController(
         text: scoreB == null ? '' : '$scoreB',
       );

  factory _MatchDraft.empty({required String id}) {
    return _MatchDraft(
      id: id,
      teamA: '',
      teamB: '',
      scoreA: null,
      scoreB: null,
      status: MatchStatus.scheduled,
      winner: _WinnerSelection.none,
    );
  }

  factory _MatchDraft.fromMatch(BracketMatch match) {
    final winner = match.winnerId == null
        ? _WinnerSelection.none
        : match.isTeamAWinner
        ? _WinnerSelection.teamA
        : match.isTeamBWinner
        ? _WinnerSelection.teamB
        : _WinnerSelection.none;
    return _MatchDraft(
      id: match.id,
      teamA: match.teamA?.name ?? '',
      teamB: match.teamB?.name ?? '',
      scoreA: match.scoreA,
      scoreB: match.scoreB,
      status: match.status,
      winner: winner,
      teamAId: match.teamA?.id,
      teamBId: match.teamB?.id,
    );
  }

  final String id;
  final TextEditingController teamANameCtrl;
  final TextEditingController teamBNameCtrl;
  final TextEditingController scoreACtrl;
  final TextEditingController scoreBCtrl;
  MatchStatus status;
  _WinnerSelection winner;
  String? teamAId;
  String? teamBId;

  void dispose() {
    teamANameCtrl.dispose();
    teamBNameCtrl.dispose();
    scoreACtrl.dispose();
    scoreBCtrl.dispose();
  }

  BracketMatch toMatch() {
    final aName = teamANameCtrl.text.trim();
    final bName = teamBNameCtrl.text.trim();
    final teamA = aName.isEmpty
        ? null
        : BracketTeam(id: teamAId ?? _slug(aName), name: aName);
    final teamB = bName.isEmpty
        ? null
        : BracketTeam(id: teamBId ?? _slug(bName), name: bName);

    String? winnerId;
    switch (winner) {
      case _WinnerSelection.none:
        winnerId = null;
        break;
      case _WinnerSelection.teamA:
        winnerId = teamA?.id;
        break;
      case _WinnerSelection.teamB:
        winnerId = teamB?.id;
        break;
    }

    return BracketMatch(
      id: id,
      teamA: teamA,
      teamB: teamB,
      scoreA: int.tryParse(scoreACtrl.text.trim()),
      scoreB: int.tryParse(scoreBCtrl.text.trim()),
      status: status,
      winnerId: winnerId,
    );
  }

  static String _slug(String input) {
    final lower = input.toLowerCase();
    final cleaned = lower
        .replaceAll(RegExp(r'[^a-z0-9]+'), '_')
        .replaceAll(RegExp(r'^_|_$'), '');
    return cleaned.isEmpty ? 'team' : cleaned;
  }
}
