import 'dart:async';
import 'dart:math';
import 'dart:typed_data';

import 'package:flutter/material.dart';
import 'package:provider/provider.dart';

import '../connector/meshcore_connector.dart';
import '../models/channel.dart';
import '../utils/dialog_utils.dart';
import '../utils/disconnect_navigation_mixin.dart';
import '../utils/route_transitions.dart';
import '../widgets/battery_indicator.dart';
import '../widgets/list_filter_widget.dart';
import '../widgets/empty_state.dart';
import '../widgets/quick_switch_bar.dart';
import '../widgets/unread_badge.dart';
import 'channel_chat_screen.dart';
import 'contacts_screen.dart';
import 'map_screen.dart';
import 'settings_screen.dart';

enum ChannelSortOption {
  manual,
  name,
  latestMessages,
  unread,
}

class ChannelsScreen extends StatefulWidget {
  final bool hideBackButton;

  const ChannelsScreen({
    super.key,
    this.hideBackButton = false,
  });

  @override
  State<ChannelsScreen> createState() => _ChannelsScreenState();
}

class _ChannelsScreenState extends State<ChannelsScreen>
    with DisconnectNavigationMixin {
  final TextEditingController _searchController = TextEditingController();
  String _searchQuery = '';
  Timer? _searchDebounce;
  ChannelSortOption _sortOption = ChannelSortOption.manual;

  @override
  void initState() {
    super.initState();
    WidgetsBinding.instance.addPostFrameCallback((_) {
      context.read<MeshCoreConnector>().getChannels();
    });
  }

  @override
  void dispose() {
    _searchDebounce?.cancel();
    _searchController.dispose();
    super.dispose();
  }

  @override
  Widget build(BuildContext context) {
    final connector = context.watch<MeshCoreConnector>();

    // Auto-navigate back to scanner if disconnected
    if (!checkConnectionAndNavigate(connector)) {
      return const SizedBox.shrink();
    }

    final allowBack = !connector.isConnected;

    return PopScope(
      canPop: allowBack,
      child: Scaffold(
        appBar: AppBar(
          leading: BatteryIndicator(connector: connector),
          title: const Text('Channels'),
          centerTitle: true,
          automaticallyImplyLeading: false,
          actions: [
            IconButton(
              icon: const Icon(Icons.bluetooth_disabled),
              tooltip: 'Disconnect',
              onPressed: () => _disconnect(context),
            ),
            IconButton(
              icon: const Icon(Icons.tune),
              tooltip: 'Settings',
              onPressed: () => Navigator.push(
                context,
                MaterialPageRoute(builder: (context) => const SettingsScreen()),
              ),
            ),
          ],
        ),
        body: RefreshIndicator(
          onRefresh: () async {
            await context.read<MeshCoreConnector>().getChannels();
          },
          child: () {
            if (connector.isLoadingChannels) {
              return const Center(child: CircularProgressIndicator());
            }

            final channels = connector.channels;

            if (channels.isEmpty) {
              return ListView(
                children: [
                  SizedBox(
                    height: MediaQuery.of(context).size.height - 200,
                    child: EmptyState(
                      icon: Icons.tag,
                      title: 'No channels configured',
                      action: FilledButton.icon(
                        onPressed: () => _addPublicChannel(context, connector),
                        icon: const Icon(Icons.public),
                        label: const Text('Add Public Channel'),
                      ),
                    ),
                  ),
                ],
              );
            }

            final filteredChannels = _filterAndSortChannels(channels, connector);

            return Column(
              children: [
                Padding(
                  padding: const EdgeInsets.all(8.0),
                  child: TextField(
                    controller: _searchController,
                    decoration: InputDecoration(
                      hintText: 'Search channels...',
                      prefixIcon: const Icon(Icons.search),
                      suffixIcon: Row(
                        mainAxisSize: MainAxisSize.min,
                        children: [
                          if (_searchQuery.isNotEmpty)
                            IconButton(
                              icon: const Icon(Icons.clear),
                              onPressed: () {
                                _searchController.clear();
                                setState(() {
                                  _searchQuery = '';
                                });
                              },
                            ),
                          _buildFilterButton(),
                        ],
                      ),
                      border: OutlineInputBorder(
                        borderRadius: BorderRadius.circular(12),
                      ),
                      contentPadding:
                          const EdgeInsets.symmetric(horizontal: 16, vertical: 12),
                    ),
                    onChanged: (value) {
                      _searchDebounce?.cancel();
                      _searchDebounce = Timer(const Duration(milliseconds: 300), () {
                        if (!mounted) return;
                        setState(() {
                          _searchQuery = value.toLowerCase();
                        });
                      });
                    },
                  ),
                ),
                Expanded(
                  child: filteredChannels.isEmpty
                      ? ListView(
                          children: [
                            SizedBox(
                              height: MediaQuery.of(context).size.height - 300,
                              child: Center(
                                child: Column(
                                  mainAxisAlignment: MainAxisAlignment.center,
                                  children: [
                                    Icon(Icons.search_off, size: 64, color: Colors.grey[400]),
                                    const SizedBox(height: 16),
                                    Text(
                                      'No channels found',
                                      style: TextStyle(fontSize: 16, color: Colors.grey[600]),
                                    ),
                                  ],
                                ),
                              ),
                            ),
                          ],
                        )
                      : (_sortOption == ChannelSortOption.manual && _searchQuery.isEmpty)
                          ? ReorderableListView.builder(
                              padding: const EdgeInsets.only(
                                left: 16,
                                right: 16,
                                top: 8,
                                bottom: 88,
                              ),
                              buildDefaultDragHandles: false,
                              itemCount: filteredChannels.length,
                              onReorder: (oldIndex, newIndex) {
                                if (newIndex > oldIndex) newIndex -= 1;
                                final reordered = List<Channel>.from(filteredChannels);
                                final item = reordered.removeAt(oldIndex);
                                reordered.insert(newIndex, item);
                                unawaited(
                                  connector.setChannelOrder(
                                    reordered.map((c) => c.index).toList(),
                                  ),
                                );
                              },
                              itemBuilder: (context, index) {
                                final channel = filteredChannels[index];
                                return _buildChannelTile(
                                  context,
                                  connector,
                                  channel,
                                  showDragHandle: true,
                                  dragIndex: index,
                                );
                              },
                            )
                          : ListView.builder(
                              padding: const EdgeInsets.only(
                                left: 16,
                                right: 16,
                                top: 8,
                                bottom: 88,
                              ),
                              itemCount: filteredChannels.length,
                              itemBuilder: (context, index) {
                                final channel = filteredChannels[index];
                                return _buildChannelTile(context, connector, channel);
                              },
                            ),
                ),
              ],
            );
          }(),
        ),
        floatingActionButton: FloatingActionButton(
          onPressed: () => _showAddChannelDialog(context),
          child: const Icon(Icons.add),
        ),
        bottomNavigationBar: SafeArea(
          top: false,
          child: QuickSwitchBar(
            selectedIndex: 1,
            onDestinationSelected: (index) => _handleQuickSwitch(index, context),
          ),
        ),
      ),
    );
  }

  Widget _buildChannelTile(
    BuildContext context,
    MeshCoreConnector connector,
    Channel channel,
    {
    bool showDragHandle = false,
    int? dragIndex,
  }
  ) {
    final unreadCount = connector.getUnreadCountForChannel(channel);
    return Card(
      key: ValueKey('channel_${channel.index}'),
      margin: const EdgeInsets.only(bottom: 12),
      child: ListTile(
        dense: true,
        minVerticalPadding: 0,
        contentPadding: const EdgeInsets.symmetric(horizontal: 12),
        visualDensity: const VisualDensity(vertical: -2),
        leading: CircleAvatar(
          backgroundColor: channel.isPublicChannel
              ? Colors.green.withValues(alpha: 0.2)
              : Colors.blue.withValues(alpha: 0.2),
          child: Icon(
            channel.isPublicChannel
                ? Icons.public
                : channel.name.startsWith('#')
                    ? Icons.tag
                    : Icons.lock,
            color: channel.isPublicChannel ? Colors.green : Colors.blue,
          ),
        ),
        title: Text(
          channel.name.isEmpty ? 'Channel ${channel.index}' : channel.name,
          style: const TextStyle(fontWeight: FontWeight.w500),
        ),
        subtitle: Text(
          channel.name.startsWith('#')
              ? 'Hashtag channel'
              : channel.isPublicChannel
                  ? 'Public channel'
                  : 'Private channel',
        ),
        trailing: Row(
          mainAxisSize: MainAxisSize.min,
          children: [
            if (unreadCount > 0) ...[
              UnreadBadge(count: unreadCount),
              const SizedBox(width: 4),
            ],
            if (showDragHandle && dragIndex != null)
              ReorderableDelayedDragStartListener(
                index: dragIndex,
                child: Icon(
                  Icons.drag_handle,
                  color: Theme.of(context).colorScheme.onSurfaceVariant,
                ),
              ),
          ],
        ),
        onTap: () async {
          connector.markChannelRead(channel.index);
          await Future.delayed(const Duration(milliseconds: 50));
          if (context.mounted) {
            Navigator.push(
              context,
              MaterialPageRoute(
                builder: (context) => ChannelChatScreen(channel: channel),
              ),
            );
          }
        },
        onLongPress: () => _showChannelActions(context, connector, channel),
      ),
    );
  }

  void _showChannelActions(
    BuildContext context,
    MeshCoreConnector connector,
    Channel channel,
  ) {
    showModalBottomSheet(
      context: context,
      builder: (context) => SafeArea(
        child: Column(
          mainAxisSize: MainAxisSize.min,
          children: [
            ListTile(
              leading: const Icon(Icons.edit_outlined),
              title: const Text('Edit channel'),
              onTap: () async {
                Navigator.pop(context);
                await Future.delayed(const Duration(milliseconds: 100));
                if (context.mounted) {
                  _showEditChannelDialog(context, connector, channel);
                }
              },
            ),
            ListTile(
              leading: const Icon(Icons.delete_outline, color: Colors.red),
              title: const Text('Delete channel', style: TextStyle(color: Colors.red)),
              onTap: () async {
                Navigator.pop(context);
                await Future.delayed(const Duration(milliseconds: 100));
                if (context.mounted) {
                  _confirmDeleteChannel(context, connector, channel);
                }
              },
            ),
          ],
        ),
      ),
    );
  }

  void _handleQuickSwitch(int index, BuildContext context) {
    if (index == 1) return;
    switch (index) {
      case 0:
        Navigator.pushReplacement(
          context,
          buildQuickSwitchRoute(
            const ContactsScreen(hideBackButton: true),
          ),
        );
        break;
      case 2:
        Navigator.pushReplacement(
          context,
          buildQuickSwitchRoute(
            const MapScreen(hideBackButton: true),
          ),
        );
        break;
    }
  }

  Future<void> _disconnect(BuildContext context) async {
    final connector = context.read<MeshCoreConnector>();
    await showDisconnectDialog(context, connector);
  }

  Widget _buildFilterButton() {
    const actionSortManual = 0;
    const actionSortName = 1;
    const actionSortLatest = 2;
    const actionSortUnread = 3;

    return SortFilterMenu(
      sections: [
        SortFilterMenuSection(
          title: 'Sort by',
          options: [
            SortFilterMenuOption(
              value: actionSortManual,
              label: 'Manual',
              checked: _sortOption == ChannelSortOption.manual,
            ),
            SortFilterMenuOption(
              value: actionSortName,
              label: 'A-Z',
              checked: _sortOption == ChannelSortOption.name,
            ),
            SortFilterMenuOption(
              value: actionSortLatest,
              label: 'Latest messages',
              checked: _sortOption == ChannelSortOption.latestMessages,
            ),
            SortFilterMenuOption(
              value: actionSortUnread,
              label: 'Unread',
              checked: _sortOption == ChannelSortOption.unread,
            ),
          ],
        ),
      ],
      onSelected: (action) {
        setState(() {
          switch (action) {
            case actionSortManual:
              _sortOption = ChannelSortOption.manual;
              break;
            case actionSortLatest:
              _sortOption = ChannelSortOption.latestMessages;
              break;
            case actionSortUnread:
              _sortOption = ChannelSortOption.unread;
              break;
            case actionSortName:
            default:
              _sortOption = ChannelSortOption.name;
              break;
          }
        });
      },
    );
  }

  List<Channel> _filterAndSortChannels(
    List<Channel> channels,
    MeshCoreConnector connector,
  ) {
    var filtered = channels.where((channel) {
      if (_searchQuery.isEmpty) return true;
      final label = _normalizeChannelName(channel);
      return label.toLowerCase().contains(_searchQuery);
    }).toList();

    int compareByName(Channel a, Channel b) {
      final nameA = _normalizeChannelName(a);
      final nameB = _normalizeChannelName(b);
      return nameA.toLowerCase().compareTo(nameB.toLowerCase());
    }

    switch (_sortOption) {
      case ChannelSortOption.manual:
        break;
      case ChannelSortOption.latestMessages:
        filtered.sort((a, b) {
          final aMessages = connector.getChannelMessages(a);
          final bMessages = connector.getChannelMessages(b);
          final aLast = aMessages.isEmpty ? DateTime(1970) : aMessages.last.timestamp;
          final bLast = bMessages.isEmpty ? DateTime(1970) : bMessages.last.timestamp;
          final timeCompare = bLast.compareTo(aLast);
          if (timeCompare != 0) return timeCompare;
          return compareByName(a, b);
        });
        break;
      case ChannelSortOption.unread:
        filtered.sort((a, b) {
          final aUnread = connector.getUnreadCountForChannel(a);
          final bUnread = connector.getUnreadCountForChannel(b);
          final unreadCompare = bUnread.compareTo(aUnread);
          if (unreadCompare != 0) return unreadCompare;
          return compareByName(a, b);
        });
        break;
      case ChannelSortOption.name:
        filtered.sort(compareByName);
        break;
    }

    return filtered;
  }

  String _normalizeChannelName(Channel channel) {
    if (channel.name.isEmpty) return 'Channel ${channel.index}';
    final trimmed = channel.name.trim();
    if (trimmed.startsWith('#') && trimmed.length > 1) {
      return trimmed.substring(1);
    }
    return trimmed;
  }

  void _showAddChannelDialog(BuildContext context) {
    final connector = context.read<MeshCoreConnector>();
    final nameController = TextEditingController();
    final pskController = TextEditingController();
    final maxChannels = connector.maxChannels;
    int selectedIndex = _findNextAvailableIndex(connector.channels, maxChannels);
    bool usePublicPsk = false;

    showDialog(
      context: context,
      builder: (context) => StatefulBuilder(
        builder: (context, setDialogState) => AlertDialog(
          title: const Text('Add Channel'),
          content: SingleChildScrollView(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              crossAxisAlignment: CrossAxisAlignment.start,
              children: [
                DropdownButtonFormField<int>(
                  initialValue: selectedIndex,
                  decoration: const InputDecoration(
                    labelText: 'Channel Index',
                    border: OutlineInputBorder(),
                  ),
                  items: List.generate(maxChannels, (i) => i)
                      .map((i) => DropdownMenuItem(
                            value: i,
                            child: Text('Channel $i'),
                          ))
                      .toList(),
                  onChanged: (value) {
                    if (value != null) {
                      setDialogState(() => selectedIndex = value);
                    }
                  },
                ),
                const SizedBox(height: 16),
                TextField(
                  controller: nameController,
                  decoration: const InputDecoration(
                    labelText: 'Channel Name',
                    border: OutlineInputBorder(),
                  ),
                  maxLength: 31,
                ),
                const SizedBox(height: 8),
                CheckboxListTile(
                  title: const Text('Use Public Channel'),
                  subtitle: const Text('Standard public PSK'),
                  value: usePublicPsk,
                  onChanged: (value) {
                    setDialogState(() {
                      usePublicPsk = value ?? false;
                      if (usePublicPsk) {
                        nameController.text = 'Public';
                        pskController.text = Channel.publicChannelPsk;
                      } else {
                        pskController.clear();
                      }
                    });
                  },
                ),
                if (!usePublicPsk) ...[
                  const SizedBox(height: 8),
                  TextField(
                    controller: pskController,
                    decoration: InputDecoration(
                      labelText: 'PSK (Hex)',
                      border: const OutlineInputBorder(),
                      suffixIcon: IconButton(
                        icon: const Icon(Icons.casino),
                        tooltip: 'Generate random PSK',
                        onPressed: () {
                          final random = Random.secure();
                          final bytes = Uint8List(16);
                          for (int i = 0; i < 16; i++) {
                            bytes[i] = random.nextInt(256);
                          }
                          pskController.text = Channel.formatPskHex(bytes);
                        },
                      ),
                    ),
                  ),
                ],
              ],
            ),
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: const Text('Cancel'),
            ),
            FilledButton(
              onPressed: () {
                final name = nameController.text.trim();
                final pskHex = usePublicPsk
                    ? Channel.publicChannelPsk
                    : pskController.text.trim();

                if (name.isEmpty) {
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(content: Text('Please enter a channel name')),
                  );
                  return;
                }

                Uint8List psk;
                try {
                  psk = Channel.parsePskHex(pskHex);
                } on FormatException {
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(content: Text('PSK must be 32 hex characters')),
                  );
                  return;
                }

                Navigator.pop(context);
                connector.setChannel(selectedIndex, name, psk);
                if (context.mounted) {
                  ScaffoldMessenger.of(context).showSnackBar(
                    SnackBar(content: Text('Channel "$name" added')),
                  );
                }
              },
              child: const Text('Add'),
            ),
          ],
        ),
      ),
    );
  }

  void _showEditChannelDialog(
    BuildContext context,
    MeshCoreConnector connector,
    Channel channel,
  ) {
    final nameController = TextEditingController(text: channel.name);
    final pskController = TextEditingController(text: channel.pskHex);
    bool smazEnabled = connector.isChannelSmazEnabled(channel.index);

    showDialog(
      context: context,
      builder: (context) => StatefulBuilder(
        builder: (context, setState) => AlertDialog(
          title: Text('Edit Channel ${channel.index}'),
          content: SingleChildScrollView(
            child: Column(
              mainAxisSize: MainAxisSize.min,
              children: [
                TextField(
                  controller: nameController,
                  decoration: const InputDecoration(
                    labelText: 'Channel Name',
                    border: OutlineInputBorder(),
                  ),
                  maxLength: 31,
                ),
                const SizedBox(height: 16),
                TextField(
                  controller: pskController,
                  decoration: InputDecoration(
                    labelText: 'PSK (Hex)',
                    border: const OutlineInputBorder(),
                    suffixIcon: IconButton(
                      icon: const Icon(Icons.casino),
                      tooltip: 'Generate random PSK',
                      onPressed: () {
                        final random = Random.secure();
                        final bytes = Uint8List(16);
                        for (int i = 0; i < 16; i++) {
                          bytes[i] = random.nextInt(256);
                        }
                        pskController.text = Channel.formatPskHex(bytes);
                      },
                    ),
                  ),
                ),
                const SizedBox(height: 16),
                SwitchListTile(
                  contentPadding: EdgeInsets.zero,
                  title: const Text('SMAZ compression'),
                  value: smazEnabled,
                  onChanged: (value) => setState(() => smazEnabled = value),
                ),
              ],
            ),
          ),
          actions: [
            TextButton(
              onPressed: () => Navigator.pop(context),
              child: const Text('Cancel'),
            ),
            FilledButton(
              onPressed: () {
                final name = nameController.text.trim();
                final pskHex = pskController.text.trim();

                Uint8List psk;
                try {
                  psk = Channel.parsePskHex(pskHex);
                } on FormatException {
                  ScaffoldMessenger.of(context).showSnackBar(
                    const SnackBar(content: Text('PSK must be 32 hex characters')),
                  );
                  return;
                }

                Navigator.pop(context);
                connector.setChannel(channel.index, name, psk);
                connector.setChannelSmazEnabled(channel.index, smazEnabled);
                ScaffoldMessenger.of(context).showSnackBar(
                  SnackBar(content: Text('Channel "$name" updated')),
                );
              },
              child: const Text('Save'),
            ),
          ],
        ),
      ),
    );
  }

  void _confirmDeleteChannel(
    BuildContext context,
    MeshCoreConnector connector,
    Channel channel,
  ) {
    showDialog(
      context: context,
      builder: (context) => AlertDialog(
        title: const Text('Delete Channel'),
        content: Text('Delete "${channel.name}"? This cannot be undone.'),
        actions: [
          TextButton(
            onPressed: () => Navigator.pop(context),
            child: const Text('Cancel'),
          ),
          TextButton(
            onPressed: () {
              Navigator.pop(context);
              connector.deleteChannel(channel.index);
              ScaffoldMessenger.of(context).showSnackBar(
                SnackBar(content: Text('Channel "${channel.name}" deleted')),
              );
            },
            child: const Text('Delete', style: TextStyle(color: Colors.red)),
          ),
        ],
      ),
    );
  }

  void _addPublicChannel(BuildContext context, MeshCoreConnector connector) {
    final psk = Channel.parsePskHex(Channel.publicChannelPsk);
    connector.setChannel(0, 'Public', psk);
    ScaffoldMessenger.of(context).showSnackBar(
      const SnackBar(content: Text('Public channel added')),
    );
  }

  int _findNextAvailableIndex(List<Channel> channels, int maxChannels) {
    final usedIndices = channels.map((c) => c.index).toSet();
    for (int i = 0; i < maxChannels; i++) {
      if (!usedIndices.contains(i)) return i;
    }
    return 0;
  }
}
