import * as React from 'react';
import { createElement } from 'react';
import { createRoot, type Root } from 'react-dom/client';
import { afterEach, beforeEach, describe, expect, it, vi } from 'vitest';

(globalThis as { IS_REACT_ACT_ENVIRONMENT?: boolean }).IS_REACT_ACT_ENVIRONMENT = true;
const act = (React as { act?: (cb: () => void | Promise<void>) => void | Promise<void> }).act as (cb: () => void | Promise<void>) => void | Promise<void>;

const testState = vi.hoisted(() => ({
  account: {} as Record<string, any>,
  rpcSettings: { state: 'disconnected' } as Record<string, any>,
  setAccountMock: vi.fn().mockResolvedValue(undefined),
}));

vi.mock('react-i18next', () => ({
  useTranslation: () => ({
    t: (key: string) => key,
  }),
}));

vi.mock('@bitsocial/bitsocial-react-hooks', () => ({
  setAccount: (account: unknown) => testState.setAccountMock(account),
  useAccount: () => testState.account,
  usePkcRpcSettings: () => testState.rpcSettings,
}));

let container: HTMLDivElement;
let root: Root;

const loadComponent = async (isElectron = false) => {
  vi.resetModules();
  window.electronApi = isElectron ? ({ isElectron: true } as Window['electronApi']) : undefined;
  window.isElectron = isElectron;
  return (await import('../p2p-stats-settings')).default;
};

const renderSettings = async (isElectron = false) => {
  const P2PStatsSettings = await loadComponent(isElectron);
  await act(async () => {
    root.render(createElement(P2PStatsSettings));
    await Promise.resolve();
  });
};

const getStatRows = () =>
  new Map(Array.from(container.querySelectorAll('tr')).map((row) => [row.children.item(0)?.textContent ?? '', row.children.item(1)?.textContent ?? '']));

const getMarkerByTitle = (title: string) => Array.from(container.querySelectorAll('svg rect')).find((rect) => rect.querySelector('title')?.textContent === title);

describe('P2PStatsSettings', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    localStorage.clear();
    window.electronApi = undefined;
    window.isElectron = false;
    testState.account = {
      id: 'account-1',
      author: { address: 'author', wallets: {} },
      pkcOptions: {
        ipfsGatewayUrls: ['https://gateway.example'],
      },
    };
    testState.rpcSettings = { state: 'disconnected' };
    testState.setAccountMock.mockReset().mockResolvedValue(undefined);
    // Default: own-IP endpoint lookups resolve offline so browser
    // stats tests never hit the network. Individual tests can override this stub.
    vi.stubGlobal(
      'fetch',
      vi.fn().mockResolvedValue({
        ok: true,
        json: async () => ({ country: 'US', ip: '147.75.84.175' }),
      }),
    );
    container = document.createElement('div');
    document.body.appendChild(container);
    root = createRoot(container);
  });

  afterEach(() => {
    act(() => root.unmount());
    container.remove();
    vi.unstubAllGlobals();
  });

  it('renders browser libp2p stats from the active PKC client', async () => {
    testState.account = {
      ...testState.account,
      pkcOptions: {
        httpRoutersOptions: ['https://router.example'],
        libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
      },
      pkc: {
        clients: {
          libp2pJsClients: {
            libp2pjs: {
              key: 'libp2pjs',
              heliaWithKuboRpcClientFunctions: {
                add: async () => {
                  throw new Error("Helia 'add' is not supported at the moment in pkc-js API");
                },
              },
              _helia: {
                libp2p: {
                  getConnections: () => [
                    {
                      direction: 'outbound',
                      remoteAddr: { toString: () => '/ip4/127.0.0.1/tcp/4001/ws/p2p/peer-1' },
                      remotePeer: { toString: () => 'peer-1' },
                      status: 'open',
                    },
                  ],
                  getMultiaddrs: () => ['/ip4/147.75.84.175/tcp/4001/ws'],
                  getPeers: () => ['peer-1', 'peer-2'],
                  metrics: {
                    toJSON: () => ({
                      helia_bitswap_data_received_bytes: { global: 2048, 'peer-1': 1536 },
                      helia_bitswap_sent_data_bytes: { global: 1024, 'peer-1': 512 },
                    }),
                  },
                  peerId: { toString: () => 'self-peer' },
                  services: {
                    pubsub: {
                      getPeers: () => ['peer-1'],
                    },
                  },
                },
                routing: {
                  routers: [
                    {
                      async provide() {
                        // noop
                      },
                    },
                  ],
                },
              },
            },
          },
        },
      },
    };

    await renderSettings(false);
    await act(async () => Promise.resolve());

    const rows = getStatRows();
    const connectedPeers = container.querySelector('[data-testid="connected-peers"]');
    expect(container.textContent).toContain('Leeching');
    expect(container.textContent).toContain('want to seed');
    const seederLink = container.querySelector('a[href="https://github.com/bitsocialnet/bitsocial-seeder"]');
    expect(seederLink).not.toBeNull();
    expect(seederLink?.textContent).toBe('want to seed?');
    expect(rows.get('Your IP')).toContain('147.75.84.175');
    // Browser mode resolves "Your IP" from the browser's public endpoint, not
    // from libp2p observed/WebRTC addresses.
    expect(fetch).toHaveBeenCalledWith('https://api.ipify.org?format=json', expect.objectContaining({ signal: expect.any(AbortSignal) }));
    const yourIpRow = Array.from(container.querySelectorAll('tr')).find((row) => row.textContent?.includes('Your IP'));
    expect(yourIpRow?.querySelector('img[aria-label]')).not.toBeNull();
    expect(container.textContent).not.toContain('browser Helia');
    expect(container.textContent).not.toContain('seed mode');
    expect(container.textContent).not.toContain('status');
    expect(connectedPeers?.textContent).toContain('2 peers, 1 connection');
    expect(connectedPeers?.textContent).toContain('WebSocket');
    expect(connectedPeers?.textContent).toContain('Received 1.50 KB');
    expect(connectedPeers?.textContent).toContain('Sent 512 B');
    expect(connectedPeers?.textContent).not.toContain('outbound');
    expect(connectedPeers?.textContent).not.toContain('open');
    expect(connectedPeers?.textContent).toContain('/ip4/127.0.0.1/tcp/4001/ws/p2p/peer-1');
    expect(rows.has('connections')).toBe(false);
    expect(rows.has('Listen addresses')).toBe(false);
    expect(rows.has('p2p_stats_updated')).toBe(true);
    const tableRows = Array.from(container.querySelectorAll('tr'));
    const rowTexts = tableRows.map((row) => row.textContent ?? '');
    const dataSentIndex = rowTexts.findIndex((text) => text.includes('Data sent'));
    const updatedIndex = rowTexts.findIndex((text) => text.includes('p2p_stats_updated'));
    const connectedPeersIndex = rowTexts.findIndex((text) => text.includes('Connected peers'));
    expect(dataSentIndex).toBeGreaterThanOrEqual(0);
    expect(updatedIndex).toBeGreaterThan(dataSentIndex);
    expect(connectedPeersIndex).toBeGreaterThan(updatedIndex);
    expect(container.textContent).toContain('self-peer');
    expect(container.textContent).toContain('Peer ID');
    expect(container.textContent).toContain('Data received');
    expect(container.textContent).toContain('2.00 KB');
    expect(container.textContent).toContain('Data sent');
    expect(container.textContent).toContain('1.00 KB');
    expect(container.textContent).not.toContain('client key');
    expect(container.textContent).not.toContain('pubsub peers');
    expect(container.textContent).not.toContain('routers');
    expect(container.textContent).not.toContain('pubsub topics');
    expect(container.textContent).not.toContain('topic subscribers');
  });

  it('places peer map markers from city-level IP locations', async () => {
    const fetchMock = vi.fn(async (url: string | URL | Request) => {
      const requestUrl = String(url);
      if (requestUrl === 'https://free.freeipapi.com/api/json/91.234.199.189') {
        return {
          ok: true,
          json: async () => ({
            cityName: 'Haarlem',
            countryCode: 'NL',
            ipAddress: '91.234.199.189',
            latitude: 52.3874,
            longitude: 4.64622,
            regionName: 'North Holland',
          }),
        };
      }
      return {
        ok: true,
        json: async () => ({ country: 'US', ip: '147.75.84.175' }),
      };
    });
    vi.stubGlobal('fetch', fetchMock);
    testState.account = {
      ...testState.account,
      pkcOptions: {
        libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
      },
      pkc: {
        clients: {
          libp2pJsClients: {
            libp2pjs: {
              key: 'libp2pjs',
              _helia: {
                libp2p: {
                  getConnections: () => [
                    {
                      remoteAddr: { toString: () => '/ip4/91.234.199.189/tcp/4001/ws/p2p/peer-geo' },
                      remotePeer: { toString: () => 'peer-geo' },
                    },
                  ],
                  getMultiaddrs: () => ['/ip4/147.75.84.175/tcp/4001/ws'],
                  getPeers: () => ['peer-geo'],
                  peerId: { toString: () => 'self-peer' },
                },
              },
            },
          },
        },
      },
    };

    await renderSettings(false);
    await act(async () => {
      await Promise.resolve();
      await Promise.resolve();
    });

    const marker = getMarkerByTitle('peer-geo - Haarlem, North Holland, NL');
    expect(marker).not.toBeNull();
    expect(marker?.getAttribute('height')).toBe('3');
    expect(marker?.getAttribute('width')).toBe('3');
    expect(Number(marker?.getAttribute('x'))).toBeCloseTo(183.15, 1);
    expect(Number(marker?.getAttribute('y'))).toBeCloseTo(36.11, 1);
    expect(fetchMock).toHaveBeenCalledWith('https://free.freeipapi.com/api/json/91.234.199.189', expect.objectContaining({ signal: expect.any(AbortSignal) }));
  });

  it('shows peer country flags for DNS6 relay hostnames with embedded IPv6 addresses', async () => {
    const fetchMock = vi.fn(async (url: string | URL | Request) => {
      const requestUrl = String(url);
      if (requestUrl === 'https://free.freeipapi.com/api/json/2a11%3A6100%3A0%3A5e9f%3A%3A0') {
        return {
          ok: true,
          json: async () => ({
            cityName: 'Reykjavik',
            countryCode: 'IS',
            ipAddress: '2a11:6100:0:5e9f::0',
            latitude: 64.1466,
            longitude: -21.9426,
          }),
        };
      }
      return {
        ok: true,
        json: async () => ({ country: 'US', ip: '147.75.84.175' }),
      };
    });
    vi.stubGlobal('fetch', fetchMock);
    testState.account = {
      ...testState.account,
      pkcOptions: {
        libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
      },
      pkc: {
        clients: {
          libp2pJsClients: {
            libp2pjs: {
              key: 'libp2pjs',
              _helia: {
                libp2p: {
                  getConnections: () => [
                    {
                      remoteAddr: {
                        toString: () => '/dns6/2a11-6100-0-5e9f--0.k51qzi5uqu5djg5pdoi9a98.example/tcp/443/ws/p2p/relay-peer/p2p-circuit/p2p/12D3KooWIPv6Peer',
                      },
                      remotePeer: { toString: () => '12D3KooWIPv6Peer' },
                    },
                  ],
                  getMultiaddrs: () => ['/ip4/147.75.84.175/tcp/4001/ws'],
                  getPeers: () => ['12D3KooWIPv6Peer'],
                  peerId: { toString: () => 'self-peer' },
                },
              },
            },
          },
        },
      },
    };

    await renderSettings(false);
    await act(async () => {
      await Promise.resolve();
      await Promise.resolve();
    });

    const connectedPeers = container.querySelector('[data-testid="connected-peers"]');
    expect(connectedPeers?.textContent).toContain('WebSocket through relay');
    expect(connectedPeers?.querySelector('img[aria-label="Iceland"]')).not.toBeNull();
    expect(fetchMock).toHaveBeenCalledWith(
      'https://free.freeipapi.com/api/json/2a11%3A6100%3A0%3A5e9f%3A%3A0',
      expect.objectContaining({ signal: expect.any(AbortSignal) }),
    );
  });

  it('shows the own IP flag and a red precise map marker when leeching', async () => {
    const fetchMock = vi.fn(async (url: string | URL | Request) => {
      const requestUrl = String(url);
      if (requestUrl === 'https://api.ipify.org?format=json') {
        return {
          ok: true,
          json: async () => ({ ip: '117.2.120.113' }),
        };
      }
      if (requestUrl === 'https://api.country.is/117.2.120.113') {
        return {
          ok: false,
          json: async () => ({}),
        };
      }
      if (requestUrl === 'https://free.freeipapi.com/api/json/117.2.120.113') {
        return {
          ok: true,
          json: async () => ({
            cityName: 'Da Nang',
            countryCode: 'VN',
            ipAddress: '117.2.120.113',
            latitude: 16.0678,
            longitude: 108.221,
            regionName: 'Da Nang City',
          }),
        };
      }
      return {
        ok: true,
        json: async () => ({ country: 'US', ip: '147.75.84.175' }),
      };
    });
    vi.stubGlobal('fetch', fetchMock);
    testState.account = {
      ...testState.account,
      pkcOptions: {
        libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
      },
      pkc: {
        clients: {
          libp2pJsClients: {
            libp2pjs: {
              key: 'libp2pjs',
              _helia: {
                libp2p: {
                  getConnections: () => [],
                  getMultiaddrs: () => ['/ip4/117.2.120.113/tcp/4001/ws'],
                  getPeers: () => [],
                  peerId: { toString: () => 'self-peer' },
                },
              },
            },
          },
        },
      },
    };

    await renderSettings(false);
    await act(async () => {
      await Promise.resolve();
      await Promise.resolve();
    });

    const rows = getStatRows();
    const yourIpRow = Array.from(container.querySelectorAll('tr')).find((row) => row.textContent?.includes('Your IP'));
    const marker = getMarkerByTitle('Your node - Da Nang, Da Nang City, VN');
    expect(container.textContent).toContain('Leeching');
    expect(rows.get('Your IP')).toContain('117.2.120.113');
    expect(yourIpRow?.querySelector('img[aria-label]')?.getAttribute('aria-label')).toBe('Vietnam');
    expect(marker?.getAttribute('data-peer-role')).toBe('leecher');
    expect(Number(marker?.getAttribute('x'))).toBeCloseTo(286.72, 1);
    expect(Number(marker?.getAttribute('y'))).toBeCloseTo(72.43, 1);
  });

  it('keeps browser "Your IP" on the browser public endpoint when libp2p exposes a different public address', async () => {
    const fetchMock = vi.fn(async (url: string | URL | Request) => {
      const requestUrl = String(url);
      if (requestUrl === 'https://api.ipify.org?format=json') {
        return {
          ok: true,
          json: async () => ({ ip: '104.28.68.171' }),
        };
      }
      if (requestUrl === 'https://api.country.is/104.28.68.171') {
        return {
          ok: true,
          json: async () => ({ country: 'VN', ip: '104.28.68.171' }),
        };
      }
      if (requestUrl === 'https://free.freeipapi.com/api/json/104.28.68.171') {
        return {
          ok: true,
          json: async () => ({
            cityName: 'Toronto',
            countryCode: 'CA',
            ipAddress: '104.28.68.171',
            latitude: 43.6532,
            longitude: -79.3832,
            regionName: 'Ontario',
          }),
        };
      }
      if (requestUrl === 'https://free.freeipapi.com/api/json/146.75.187.55') {
        return {
          ok: true,
          json: async () => ({
            cityName: 'Bandar Seri Begawan',
            countryCode: 'BN',
            ipAddress: '146.75.187.55',
            latitude: 4.89234,
            longitude: 114.942,
            regionName: 'Brunei-Muara',
          }),
        };
      }
      return {
        ok: true,
        json: async () => ({ country: 'US', ip: '147.75.84.175' }),
      };
    });
    vi.stubGlobal('fetch', fetchMock);
    testState.account = {
      ...testState.account,
      pkcOptions: {
        libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
      },
      pkc: {
        clients: {
          libp2pJsClients: {
            libp2pjs: {
              key: 'libp2pjs',
              _helia: {
                libp2p: {
                  getConnections: () => [
                    {
                      localAddr: { toString: () => '/ip4/146.75.187.55/udp/4001/webrtc-direct' },
                    },
                  ],
                  getMultiaddrs: () => ['/ip4/146.75.187.55/udp/4001/webrtc-direct'],
                  getPeers: () => [],
                  peerId: { toString: () => 'self-peer' },
                },
              },
            },
          },
        },
      },
    };

    await renderSettings(false);
    await act(async () => {
      await Promise.resolve();
      await Promise.resolve();
    });

    const rows = getStatRows();
    const yourIpRow = Array.from(container.querySelectorAll('tr')).find((row) => row.textContent?.includes('Your IP'));
    const marker = getMarkerByTitle('Your node - VN');
    expect(rows.get('Your IP')).toContain('104.28.68.171');
    expect(rows.get('Your IP')).not.toContain('146.75.187.55');
    expect(yourIpRow?.querySelector('img[aria-label]')?.getAttribute('aria-label')).toBe('Vietnam');
    expect(marker).not.toBeNull();
    expect(container.querySelector('svg rect title')?.textContent).not.toContain('Toronto');
    expect(fetchMock).not.toHaveBeenCalledWith('https://free.freeipapi.com/api/json/146.75.187.55', expect.anything());
  });

  it('reads browser transfer counters from Helia bitswap ledgers', async () => {
    testState.account = {
      ...testState.account,
      pkcOptions: {
        libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
      },
      pkc: {
        clients: {
          libp2pJsClients: {
            libp2pjs: {
              key: 'libp2pjs',
              _helia: {
                blockstore: {
                  child: {
                    blockBrokers: [
                      {
                        bitswap: {
                          peerWantLists: {
                            ledgerMap: new Map([['peer-1', { bytesReceived: 4096, bytesSent: 2048 }]]),
                          },
                        },
                      },
                    ],
                  },
                },
                libp2p: {
                  getConnections: () => [
                    {
                      remoteAddr: { toString: () => '/ip4/91.234.199.189/tcp/4001/ws/p2p/peer-1' },
                      remotePeer: { toString: () => 'peer-1' },
                    },
                  ],
                  getMultiaddrs: () => ['/ip4/147.75.84.175/tcp/4001/ws'],
                  getPeers: () => ['peer-1'],
                  peerId: { toString: () => 'self-peer' },
                },
              },
            },
          },
        },
      },
    };

    await renderSettings(false);
    await act(async () => Promise.resolve());

    expect(container.textContent).toContain('Data received');
    expect(container.textContent).toContain('4.00 KB');
    expect(container.textContent).toContain('Data sent');
    expect(container.textContent).toContain('2.00 KB');
    expect(container.querySelector('[data-testid="connected-peers"]')?.textContent).toContain('Received 4.00 KB');
    expect(container.querySelector('[data-testid="connected-peers"]')?.textContent).toContain('Sent 2.00 KB');
  });

  it('starts browser transfer counters at zero when Helia exposes no byte totals yet', async () => {
    testState.account = {
      ...testState.account,
      pkcOptions: {
        libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
      },
      pkc: {
        clients: {
          libp2pJsClients: {
            libp2pjs: {
              key: 'libp2pjs',
              _helia: {
                libp2p: {
                  getConnections: () => [],
                  getMultiaddrs: () => ['/ip4/147.75.84.175/tcp/4001/ws'],
                  getPeers: () => [],
                  peerId: { toString: () => 'self-peer' },
                },
              },
            },
          },
        },
      },
    };

    await renderSettings(false);
    await act(async () => Promise.resolve());

    const rows = getStatRows();
    expect(rows.get('Data received')).toBe('0 B');
    expect(rows.get('Data sent')).toBe('0 B');
  });

  it('falls back to the browser node public endpoint when Helia exposes no public address', async () => {
    const fetchMock = vi.fn(async (url: string | URL | Request) => {
      const requestUrl = String(url);
      if (requestUrl === 'https://api.ipify.org?format=json') {
        return {
          ok: true,
          json: async () => ({ ip: '104.28.68.171' }),
        };
      }
      return {
        ok: true,
        json: async () => ({ country: 'VN', ip: '104.28.68.171' }),
      };
    });
    vi.stubGlobal('fetch', fetchMock);
    testState.account = {
      ...testState.account,
      pkcOptions: {
        libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
      },
      pkc: {
        clients: {
          libp2pJsClients: {
            libp2pjs: {
              key: 'libp2pjs',
              _helia: {
                libp2p: {
                  getConnections: () => [
                    {
                      localAddr: { toString: () => '/ip4/127.0.0.1/tcp/4001/ws' },
                      remoteAddr: { toString: () => '/ip4/127.0.0.1/tcp/4001/ws/p2p/peer-1' },
                      remotePeer: { toString: () => 'peer-1' },
                    },
                  ],
                  getMultiaddrs: () => [],
                  getPeers: () => [],
                  peerId: { toString: () => 'self-peer' },
                },
              },
            },
          },
        },
      },
    };

    await renderSettings(false);
    await act(async () => Promise.resolve());

    const rows = getStatRows();
    expect(rows.get('Your IP')).toContain('104.28.68.171');
    expect(rows.get('Your IP')).not.toContain('unknown');
    const yourIpRow = Array.from(container.querySelectorAll('tr')).find((row) => row.textContent?.includes('Your IP'));
    expect(yourIpRow?.querySelector('img[aria-label]')).not.toBeNull();
    expect(fetch).toHaveBeenCalledWith('https://api.ipify.org?format=json', expect.objectContaining({ signal: expect.any(AbortSignal) }));
  });

  it('reports seeding only when browser Helia can add and publish provider records', async () => {
    testState.account = {
      ...testState.account,
      pkcOptions: {
        libp2pJsClientsOptions: [{ key: 'libp2pjs' }],
      },
      pkc: {
        clients: {
          libp2pJsClients: {
            libp2pjs: {
              key: 'libp2pjs',
              heliaWithKuboRpcClientFunctions: {
                add: async () => ({ cid: 'cid' }),
              },
              _helia: {
                libp2p: {
                  getConnections: () => [],
                  getMultiaddrs: () => ['/ip4/147.75.84.175/tcp/4001/ws'],
                  getPeers: () => [],
                  peerId: { toString: () => 'self-peer' },
                },
                routing: {
                  routers: [
                    {
                      provide: async (cid: unknown) => cid,
                    },
                  ],
                },
              },
            },
          },
        },
      },
    };

    await renderSettings(false);
    await act(async () => Promise.resolve());

    expect(container.textContent).toContain('Seeding');
    expect(container.querySelector('a[href="https://github.com/bitsocialnet/bitsocial-seeder"]')).toBeNull();
    expect(container.textContent).not.toContain('seed mode');
  });

  it('renders browser full-node RPC stats with seeding mode and leecher peer markers', async () => {
    const fetchMock = vi.fn(async (url: string | URL | Request) => {
      const requestUrl = String(url);
      if (requestUrl === 'https://free.freeipapi.com/api/json/147.75.84.175') {
        return {
          ok: true,
          json: async () => ({
            cityName: 'New York',
            countryCode: 'US',
            latitude: 40.7128,
            longitude: -74.006,
            regionName: 'New York',
          }),
        };
      }
      if (requestUrl === 'https://free.freeipapi.com/api/json/91.234.199.189') {
        return {
          ok: true,
          json: async () => ({
            cityName: 'Haarlem',
            countryCode: 'NL',
            latitude: 52.3874,
            longitude: 4.64622,
            regionName: 'North Holland',
          }),
        };
      }
      if (requestUrl === 'https://free.freeipapi.com/api/json/117.2.120.113') {
        return {
          ok: true,
          json: async () => ({
            cityName: 'Da Nang',
            countryCode: 'VN',
            latitude: 16.0678,
            longitude: 108.221,
            regionName: 'Da Nang City',
          }),
        };
      }
      return {
        ok: true,
        json: async () => ({ country: 'US', ip: '147.75.84.175' }),
      };
    });
    vi.stubGlobal('fetch', fetchMock);
    testState.rpcSettings = { state: 'connected' };
    testState.account = {
      ...testState.account,
      pkcOptions: {
        pkcRpcClientsOptions: ['ws://147.75.84.175:9138'],
      },
      pkc: {
        clients: {
          pkcRpcClients: {
            'ws://147.75.84.175:9138': {
              getPeers: vi.fn().mockResolvedValue({
                peers: [
                  {
                    address: '/ip4/91.234.199.189/tcp/4001',
                    bandwidth: { TotalIn: 256, TotalOut: 512 },
                    listenAddress: '/ip4/91.234.199.189/tcp/4001',
                    peerId: 'seed-peer',
                  },
                  {
                    address: '/ip4/117.2.120.113/tcp/4001',
                    bandwidth: { TotalIn: 128, TotalOut: 64 },
                    listenAddress: '',
                    peerId: 'leech-peer',
                  },
                ],
              }),
              getStats: vi.fn().mockResolvedValue({
                bandwidth: { TotalIn: 1024, TotalOut: 2048 },
                identity: {
                  AgentVersion: 'kubo/full-node',
                  ID: 'full-node-peer',
                  Addresses: ['/ip4/147.75.84.175/tcp/4001'],
                },
              }),
              state: 'connected',
            },
          },
        },
      },
    };

    await renderSettings(false);
    await act(async () => {
      await Promise.resolve();
      await Promise.resolve();
    });

    const rows = getStatRows();
    const markers = Array.from(container.querySelectorAll('svg rect'));
    const ownMarker = markers.find((marker) => marker.querySelector('title')?.textContent?.startsWith('Your node'));
    const leecherMarker = markers.find((marker) => marker.querySelector('title')?.textContent?.startsWith('leech-peer'));
    expect(rows.get('Mode')).toBe('Seeding');
    expect(rows.get('PKC RPC')).toBe('connected');
    expect(rows.get('Peer ID')).toBe('full-node-peer');
    expect(rows.get('Your IP')).toContain('147.75.84.175');
    expect(rows.get('Data received')).toBe('1.00 KB');
    expect(rows.get('Data sent')).toBe('2.00 KB');
    expect(container.textContent).toContain('seed-peer');
    expect(container.textContent).toContain('leech-peer');
    expect(container.querySelector('[data-testid="connected-peers"]')?.textContent).toContain('Received 256 B');
    expect(container.querySelector('[data-testid="connected-peers"]')?.textContent).toContain('Sent 64 B');
    expect(container.textContent).toContain('Leeching');
    expect(container.querySelector('a[href="https://github.com/bitsocialnet/bitsocial-seeder"]')).toBeNull();
    expect(ownMarker?.getAttribute('data-peer-role')).toBe('seeder');
    expect(leecherMarker?.getAttribute('data-peer-role')).toBe('leecher');
  });

  it('does not resolve full-node RPC hostnames through external DNS', async () => {
    const fetchMock = vi.fn();
    vi.stubGlobal('fetch', fetchMock);
    testState.rpcSettings = { state: 'connected' };
    testState.account = {
      ...testState.account,
      pkcOptions: {
        pkcRpcClientsOptions: ['ws://node.example:9138'],
      },
      pkc: {
        clients: {
          pkcRpcClients: {
            'ws://node.example:9138': {
              getPeers: vi.fn().mockResolvedValue({ peers: [] }),
              getStats: vi.fn().mockResolvedValue({
                bandwidth: { TotalIn: 0, TotalOut: 0 },
                identity: {
                  ID: 'hostname-rpc-node',
                },
              }),
              state: 'connected',
            },
          },
        },
      },
    };

    await renderSettings(false);
    await act(async () => Promise.resolve());

    const rows = getStatRows();
    expect(rows.get('Mode')).toBe('Seeding');
    expect(rows.get('Peer ID')).toBe('hostname-rpc-node');
    expect(rows.get('Your IP')).toBe('unavailable');
    expect(fetchMock).not.toHaveBeenCalled();
  });

  it('renders Electron Kubo stats as seeding with the node location on the map', async () => {
    const fetchMock = vi.fn(async (url: string | URL | Request) => {
      const requestUrl = String(url);
      if (requestUrl === 'http://localhost:50019/api/v0/id') {
        return {
          ok: true,
          text: async () =>
            JSON.stringify({
              Addresses: [
                '/dns4/77-168-54-121.example/tcp/4001/tls/ws/p2p/relay-peer/p2p-circuit/p2p/desktop-kubo-peer',
                '/ip4/117.2.120.113/udp/4001/webrtc-direct/p2p/desktop-kubo-peer',
              ],
              AgentVersion: 'kubo/0.41.0',
              ID: 'desktop-kubo-peer',
            }),
        };
      }
      if (requestUrl === 'http://localhost:50019/api/v0/swarm/peers?direction=true&latency=true&streams=true') {
        return {
          ok: true,
          text: async () =>
            JSON.stringify({
              Peers: [
                {
                  Addr: '/ip4/91.234.199.189/tcp/4001',
                  Direction: 'outbound',
                  ListenAddress: '/ip4/91.234.199.189/tcp/4001',
                  Peer: 'kubo-seeder',
                },
                {
                  Addr: '/ip4/203.0.113.10/tcp/4001',
                  Direction: 'inbound',
                  ListenAddress: '',
                  Peer: 'kubo-leecher',
                },
              ],
            }),
        };
      }
      if (requestUrl === 'http://localhost:50019/api/v0/stats/bw') {
        return { ok: true, text: async () => JSON.stringify({ RateIn: 12, RateOut: 34, TotalIn: 4096, TotalOut: 8192 }) };
      }
      if (requestUrl === 'https://free.freeipapi.com/api/json/117.2.120.113') {
        return {
          ok: true,
          json: async () => ({
            cityName: 'Da Nang',
            countryCode: 'VN',
            latitude: 16.0678,
            longitude: 108.221,
            regionName: 'Da Nang City',
          }),
        };
      }
      if (requestUrl === 'https://free.freeipapi.com/api/json/91.234.199.189') {
        return {
          ok: true,
          json: async () => ({
            cityName: 'Haarlem',
            countryCode: 'NL',
            latitude: 52.3874,
            longitude: 4.64622,
            regionName: 'North Holland',
          }),
        };
      }
      return {
        ok: true,
        json: async () => ({ country: 'VN', ip: '117.2.120.113' }),
      };
    });
    vi.stubGlobal('fetch', fetchMock);
    testState.rpcSettings = { state: 'connected' };
    testState.account = {
      ...testState.account,
      pkcOptions: {
        pkcRpcClientsOptions: ['ws://localhost:9138'],
      },
    };

    await renderSettings(true);
    await act(async () => {
      await Promise.resolve();
      await Promise.resolve();
    });

    const rows = getStatRows();
    const markers = Array.from(container.querySelectorAll('svg rect'));
    const ownMarker = markers.find((marker) => marker.querySelector('title')?.textContent?.startsWith('Your node'));
    const leecherMarker = markers.find((marker) => marker.querySelector('title')?.textContent?.startsWith('kubo-leecher'));
    expect(rows.get('Mode')).toBe('Seeding');
    expect(rows.get('Kubo RPC')).toBe('http://localhost:50019/api/v0');
    expect(rows.get('Peer ID')).toBe('desktop-kubo-peer');
    expect(rows.get('Your IP')).toContain('117.2.120.113');
    expect(rows.get('Your IP')).not.toContain('77.168.54.121');
    expect(rows.get('Data received')).toBe('4.00 KB');
    expect(rows.get('Data sent')).toBe('8.00 KB');
    expect(rows.has('PKC RPC')).toBe(false);
    expect(rows.has('Agent')).toBe(false);
    expect(rows.has('Repo size')).toBe(false);
    expect(rows.has('Repo objects')).toBe(false);
    expect(rows.has('Bitswap peers')).toBe(false);
    expect(rows.has('Bitswap wantlist')).toBe(false);
    expect(rows.has('Bandwidth in')).toBe(false);
    expect(rows.has('Bandwidth out')).toBe(false);
    expect(container.textContent).toContain('kubo-seeder');
    expect(container.textContent).toContain('kubo-leecher');
    expect(container.textContent).toContain('Leeching');
    expect(container.textContent).not.toContain('Listen addresses');
    expect(ownMarker?.getAttribute('data-peer-role')).toBe('seeder');
    expect(leecherMarker?.getAttribute('data-peer-role')).toBe('leecher');
    expect(fetchMock).not.toHaveBeenCalledWith('http://localhost:50019/api/v0/repo/stat', expect.anything());
    expect(fetchMock).not.toHaveBeenCalledWith('http://localhost:50019/api/v0/bitswap/stat', expect.anything());
    expect(fetchMock).not.toHaveBeenCalledWith('http://localhost:50019/api/v0/version', expect.anything());
    expect(fetchMock).not.toHaveBeenCalledWith('http://localhost:50019/api/v0/swarm/addrs/local', expect.anything());
  });
});
