import React from 'react';
import { bytesToHex } from '@noble/hashes/utils.js';

import ChevronRightIcon from '@mui/icons-material/ChevronRight';
import ExpandMoreIcon from '@mui/icons-material/ExpandMore';

import { PayloadType } from '../../protocols/meshcore.types';
import type { MeshCorePacketRecord } from './MeshCoreContext';
import {
  payloadDisplayByValue,
  PayloadTypeIcon,
} from './MeshCoreData';

const getPayloadTypeColor = (payloadType: number): string => {
  switch (payloadType) {
    case PayloadType.TEXT:
    case PayloadType.GROUP_TEXT:
    case PayloadType.TRACE:
    case PayloadType.PATH:
      return 'meshcore-packet-green';
    case PayloadType.ADVERT:
      return 'meshcore-packet-purple';
    case PayloadType.REQUEST:
    case PayloadType.RESPONSE:
    case PayloadType.CONTROL:
      return 'meshcore-packet-amber';
    default:
      return '';
  }
};

const getPathInfo = (packet: MeshCorePacketRecord): { prefixes: string; hopCount: number } => {
  if (packet.raw.length < 2) {
    return { prefixes: 'none', hopCount: 0 };
  }

  const pathField = packet.raw[1];
  const hashSize = (pathField >> 6) + 1;
  const hashCount = pathField & 0x3f;

  if (hashCount === 0 || hashSize === 4) {
    return { prefixes: 'none', hopCount: 0 };
  }

  const pathByteLength = hashCount * hashSize;
  const availablePathBytes = Math.min(pathByteLength, Math.max(packet.raw.length - 2, 0));
  const pathBytes = packet.raw.slice(2, 2 + availablePathBytes);

  if (pathBytes.length === 0) {
    return { prefixes: 'none', hopCount: 0 };
  }

  const prefixes: string[] = [];
  for (let offset = 0; offset + hashSize <= pathBytes.length; offset += hashSize) {
    prefixes.push(bytesToHex(pathBytes.slice(offset, offset + hashSize)));
  }

  if (prefixes.length === 0) {
    return { prefixes: 'none', hopCount: 0 };
  }

  return {
    prefixes: prefixes.join(' → '),
    hopCount: prefixes.length,
  };
};

export interface MeshCorePacketGroup {
  hash: string;
  packets: MeshCorePacketRecord[];
  mostRecent: MeshCorePacketRecord;
}

interface MeshCorePacketRowsProps {
  groupedPackets: MeshCorePacketGroup[];
  expandedHashes: Set<string>;
  onToggleExpanded: (hash: string) => void;
  onSelect: (packet: MeshCorePacketRecord) => void;
  selectedHash: string | null;
}

const MeshCorePacketRows: React.FC<MeshCorePacketRowsProps> = ({
  groupedPackets,
  expandedHashes,
  onToggleExpanded,
  onSelect,
  selectedHash,
}) => {
  return (
    <>
      {groupedPackets.map((group) => {
        const isExpanded = expandedHashes.has(group.hash);
        const hasDuplicates = group.packets.length > 1;
        const [packet, ...duplicatePackets] = group.packets;
        const expandedPackets = [packet, ...duplicatePackets].sort((a, b) => {
          const pathA = getPathInfo(a).hopCount;
          const pathB = getPathInfo(b).hopCount;
          if (pathA !== pathB) {
            return pathA - pathB;
          }
          return b.timestamp.getTime() - a.timestamp.getTime();
        });

        return (
          <React.Fragment key={group.hash}>
            <tr
              data-nav-item="true"
              className={`${getPayloadTypeColor(packet.payloadType)} ${selectedHash === packet.hash ? 'is-selected' : ''}`}
              onClick={() => onSelect(packet)}
            >
              <td>
                {hasDuplicates && (
                  <button
                    type="button"
                    className="meshcore-expand-button"
                    onClick={(e) => {
                      e.stopPropagation();
                      onToggleExpanded(group.hash);
                    }}
                    aria-label={isExpanded ? 'Collapse duplicates' : 'Expand duplicates'}
                  >
                    {isExpanded ? <ExpandMoreIcon style={{ fontSize: '1rem' }} /> : <ChevronRightIcon style={{ fontSize: '1rem' }} />}
                  </button>
                )}
              </td>
              <td>
                {packet.timestamp.toLocaleTimeString()}
                {hasDuplicates && (
                  <span className="meshcore-duplicate-badge" title={`${group.packets.length} instances`}>
                    {' '}×{group.packets.length}
                  </span>
                )}
              </td>
              <td>
                <button type="button" className="meshcore-hash-button" onClick={() => onSelect(packet)}>
                  {packet.hash}
                </button>
              </td>
              <td className="meshcore-payload-type-cell" title={payloadDisplayByValue[packet.payloadType] ?? `0x${packet.payloadType.toString(16)}`}>
                <PayloadTypeIcon payloadType={packet.payloadType} />
              </td>
              <td>{packet.payloadSummary}</td>
            </tr>
            {isExpanded && expandedPackets.map((duplicatePacket, index) => (
              <tr
                key={`${group.hash}-${index}`}
                className={`${getPayloadTypeColor(duplicatePacket.payloadType)} ${selectedHash === duplicatePacket.hash ? 'is-selected' : ''}`}
                onClick={() => onSelect(duplicatePacket)}
              >
                <td></td>
                <td>{duplicatePacket.timestamp.toLocaleTimeString()}</td>
                <td>
                  <button type="button" className="meshcore-hash-button" onClick={() => onSelect(duplicatePacket)}>
                    {duplicatePacket.hash}
                  </button>
                </td>
                <td className="meshcore-payload-type-cell" title={payloadDisplayByValue[duplicatePacket.payloadType] ?? `0x${duplicatePacket.payloadType.toString(16)}`}>
                  <PayloadTypeIcon payloadType={duplicatePacket.payloadType} />
                </td>
                <td>
                  {getPathInfo(duplicatePacket).prefixes}
                </td>
              </tr>
            ))}
          </React.Fragment>
        );
      })}
    </>
  );
};

export default MeshCorePacketRows;
