import React, { useEffect, useState, useMemo, useRef } from 'react';
import { Badge, Card, Stack, Spinner, Alert } from 'react-bootstrap';
import { useMeshCoreData } from './MeshCoreContext';
import VerticalSplit from '../../components/VerticalSplit';
import StreamStatus from '../../components/StreamStatus';
import MeshCoreServiceImpl, { type MeshCoreGroupRecord } from '../../services/MeshCoreService';
import API from '../../services/API';
import type { MeshCoreGroupChatRecord } from './MeshCoreContext';
import { KeyManager, Packet } from '../../protocols/meshcore';
import KeyboardShortcutsModal from '../../components/KeyboardShortcutsModal';
import { useKeyboardListNavigation } from '../../hooks/useKeyboardListNavigation';

const meshCoreService = new MeshCoreServiceImpl(API);

const GroupList: React.FC<{
  groups: MeshCoreGroupRecord[];
  selectedGroupId: number | null;
  onSelectGroup: (group: MeshCoreGroupRecord) => void;
  onClearSelection: () => void;
  isLoading: boolean;
  error: string | null;
  streamReady: boolean;
}> = ({ groups, selectedGroupId, onSelectGroup, onClearSelection, isLoading, error, streamReady }) => {
  const scrollRef = useRef<HTMLDivElement>(null);
  const selectedIndex = useMemo(() => {
    if (selectedGroupId === null) {
      return null;
    }
    const index = groups.findIndex((group) => group.id === selectedGroupId);
    return index >= 0 ? index : null;
  }, [groups, selectedGroupId]);

  const { showShortcuts, setShowShortcuts, shortcuts } = useKeyboardListNavigation({
    itemCount: groups.length,
    selectedIndex,
    onSelectIndex: (index) => {
      if (index === null) {
        onClearSelection();
        return;
      }
      const group = groups[index];
      if (group) {
        onSelectGroup(group);
      }
    },
    scrollContainerRef: scrollRef,
    rowSelector: '[data-nav-item="true"]',
  });

  return (
    <Card className="data-table-card h-100 d-flex flex-column">
      <Card.Header className="data-table-header d-flex justify-content-between align-items-center">
        <span>Groups</span>
        <div className="d-flex align-items-center gap-2">
          {isLoading && <Spinner animation="border" size="sm" style={{ width: '1rem', height: '1rem' }} />}
          <StreamStatus ready={streamReady} />
        </div>
      </Card.Header>
      <Card.Body className="data-table-body p-0 d-flex flex-column">
        {error && <Alert variant="danger" className="m-2 mb-0">{error}</Alert>}
        {groups.length === 0 && !isLoading && (
          <div className="p-3 text-secondary text-center">
            {error ? 'Failed to load groups' : 'No groups available'}
          </div>
        )}
        <div className="data-table-scroll" ref={scrollRef}>
          {groups.map((group) => (
            <div
              key={group.id}
              data-nav-item="true"
              onClick={() => onSelectGroup(group)}
              className={`list-item ${selectedGroupId === group.id ? 'is-selected' : ''}`}
            >
              <div className="list-item-title">{group.name}</div>
              <div className="list-item-meta">
                <small>ID: {group.id}</small>
                {group.isPublic && <Badge bg="info" className="ms-2">public</Badge>}
              </div>
            </div>
          ))}
        </div>
      </Card.Body>
      <KeyboardShortcutsModal
        show={showShortcuts}
        onHide={() => setShowShortcuts(false)}
        shortcuts={shortcuts}
      />
    </Card>
  );
};

const GroupMessagesPane: React.FC<{
  group: MeshCoreGroupRecord | null;
  messages: MeshCoreGroupChatRecord[];
  isLoading: boolean;
  error: string | null;
  streamReady: boolean;
}> = ({ group, messages, isLoading, error, streamReady }) => {
  if (!group) {
    return (
      <Card body className="data-table-card h-100 d-flex flex-column justify-content-center align-items-center">
        <h6 className="mb-2">Select a group</h6>
        <div className="text-secondary text-center">Click a group on the left to view messages</div>
      </Card>
    );
  }

  return (
    <Card className="data-table-card h-100 d-flex flex-column">
      <Card.Header className="data-table-header d-flex justify-content-between align-items-center">
        <span>{group.name}</span>
        <div className="d-flex align-items-center gap-2">
          {isLoading && <Spinner animation="border" size="sm" style={{ width: '1rem', height: '1rem' }} />}
          <StreamStatus ready={streamReady} />
        </div>
      </Card.Header>
      <Card.Body className="data-table-body p-0 d-flex flex-column">
        {error && <Alert variant="danger" className="m-2 mb-0">{error}</Alert>}
        {messages.length === 0 && !isLoading && (
          <div className="p-3 text-secondary text-center">No messages in this group</div>
        )}
        <div className="data-table-scroll">
          <Stack gap={3} className="p-3">
            {messages.map((message) => (
              <div key={message.hash + message.timestamp.toISOString()} className="meshcore-message-item">
                <div className="d-flex justify-content-between align-items-center mb-1">
                  <strong className="meshcore-message-sender">{message.sender}</strong>
                  <small className="text-secondary">{message.timestamp.toLocaleTimeString()}</small>
                </div>
                <div className="meshcore-message-text mb-2">{message.message}</div>
                <div className="d-flex justify-content-between align-items-center">
                  <Badge bg="primary">#{message.channel}</Badge>
                  <code className="meshcore-hash-code">{message.hash}</code>
                </div>
              </div>
            ))}
          </Stack>
        </div>
      </Card.Body>
    </Card>
  );
};

const MeshCoreGroupChatView: React.FC = () => {
  const { groupChats, streamReady } = useMeshCoreData();
  const [groups, setGroups] = useState<MeshCoreGroupRecord[]>([]);
  const [selectedGroup, setSelectedGroup] = useState<MeshCoreGroupRecord | null>(null);
  const [isLoadingGroups, setIsLoadingGroups] = useState(false);
  const [groupsError, setGroupsError] = useState<string | null>(null);
  const [isLoadingPackets, setIsLoadingPackets] = useState(false);
  const [packetsError, setPacketsError] = useState<string | null>(null);
  const [decryptedMessages, setDecryptedMessages] = useState<MeshCoreGroupChatRecord[]>([]);
  const keyManagerRef = useRef<KeyManager>(new KeyManager());

  // Fetch groups on mount
  useEffect(() => {
    const loadGroups = async () => {
      setIsLoadingGroups(true);
      setGroupsError(null);
      try {
        const fetchedGroups = await meshCoreService.fetchGroups();
        setGroups(fetchedGroups);

        // Add groups to key manager
        const keyManager = keyManagerRef.current;
        for (const group of fetchedGroups) {
          try {
            keyManager.addGroup(group.name, group.secret.toBytes());
          } catch (err) {
            console.warn(`Failed to add group ${group.name} to key manager:`, err);
          }
        }

        if (fetchedGroups.length > 0 && !selectedGroup) {
          setSelectedGroup(fetchedGroups[0]);
        }
      } catch (err) {
        setGroupsError(err instanceof Error ? err.message : 'Failed to load groups');
      } finally {
        setIsLoadingGroups(false);
      }
    };

    loadGroups();
  }, []);

  // Fetch and decrypt packets for selected group
  useEffect(() => {
    if (!selectedGroup) {
      setDecryptedMessages([]);
      return;
    }

    const loadGroupPackets = async () => {
      setIsLoadingPackets(true);
      setPacketsError(null);
      try {
        const channelHash = selectedGroup.secret.toHash();
        const packets = await meshCoreService.fetchGroupPackets(channelHash);
        const messages: MeshCoreGroupChatRecord[] = [];

        for (const packet of packets) {
          try {
            const p = new Packet(packet.raw);
            const payload = p.decode();

            if (payload && 'cipherText' in payload && 'cipherMAC' in payload && 'channelHash' in payload) {
              const decrypted = keyManagerRef.current.decryptGroup(
                packet.channel_hash,
                payload.cipherText as Uint8Array,
                payload.cipherMAC
              );

              messages.push({
                hash: packet.hash,
                timestamp: decrypted.timestamp,
                channel: selectedGroup.name,
                sender: decrypted.message.split(':')[0] || 'Unknown',
                message: decrypted.message.split(':').slice(1).join(':').trim(),
              });
            }
          } catch (err) {
            console.warn('Failed to decrypt packet:', err);
          }
        }

        setDecryptedMessages(messages.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime()));
      } catch (err) {
        setPacketsError(err instanceof Error ? err.message : 'Failed to load packets');
      } finally {
        setIsLoadingPackets(false);
      }
    };

    loadGroupPackets();
  }, [selectedGroup]);

  // Combine stream messages and decrypted messages
  const filteredMessages = useMemo(() => {
    if (!selectedGroup) return [];

    // Get stream messages for this group
    const streamMessages = groupChats.filter(
      (chat) => chat.channel === selectedGroup.secret.toHash() || chat.channel === selectedGroup.name
    );

    // Combine with decrypted messages and deduplicate by hash
    const combined = [...decryptedMessages, ...streamMessages];
    const seen = new Set<string>();
    const unique = combined.filter((msg) => {
      if (seen.has(msg.hash)) return false;
      seen.add(msg.hash);
      return true;
    });

    return unique.sort((a, b) => b.timestamp.getTime() - a.timestamp.getTime());
  }, [groupChats, selectedGroup, decryptedMessages]);

  const handleSelectGroup = (group: MeshCoreGroupRecord) => {
    setSelectedGroup(group);
  };

  return (
    <VerticalSplit
      ratio="25/70"
      left={
        <GroupList
          groups={groups}
          selectedGroupId={selectedGroup?.id ?? null}
          onSelectGroup={handleSelectGroup}
          onClearSelection={() => setSelectedGroup(null)}
          isLoading={isLoadingGroups}
          error={groupsError}
          streamReady={streamReady}
        />
      }
      right={
        <GroupMessagesPane
          group={selectedGroup}
          messages={filteredMessages}
          isLoading={isLoadingPackets}
          error={packetsError}
          streamReady={streamReady}
        />
      }
    />
  );
};

export default MeshCoreGroupChatView;
