// @vitest-environment jsdom
import { cleanup, render, screen, waitFor } from '@testing-library/react';
import { afterEach, describe, expect, it, vi } from 'vitest';

import type { InstanceContext, InstanceModule } from '../app-shell.js';
import {
  InstanceDetail,
  type CapabilityDataSource,
  type InstanceCapabilityMap,
} from './instance-detail.js';

afterEach(cleanup);

const owner: InstanceContext = {
  id: 'owner',
  name: 'Owner modem',
  origin: 'https://owner.example/path',
  status: 'online',
  authentication: 'authenticated',
  freshness: 'fresh',
};

const capabilities: InstanceCapabilityMap = {
  overview: { state: 'supported' },
  messages: { state: 'degraded', explanation: 'Message history is read-only.' },
  calls: { state: 'unsupported', explanation: 'This modem has no voice support.' },
  esim: { state: 'unknown', explanation: 'Capability discovery did not report eSIM.' },
};

describe('InstanceDetail', () => {
  it('makes only supported modules actionable and explains every other capability state', () => {
    render(
      <InstanceDetail
        instanceId="owner"
        module="overview"
        instance={owner}
        capabilities={capabilities}
      />,
    );

    expect(screen.getByRole('link', { name: 'Overview' }).getAttribute('href')).toBe(
      '/instances/owner/overview',
    );
    expect(screen.queryByRole('link', { name: 'Messages' })).toBeNull();
    expect(screen.getByText('Message history is read-only.')).toBeTruthy();
    expect(screen.getByText('This modem has no voice support.')).toBeTruthy();
    expect(screen.getByText('Capability discovery did not report eSIM.')).toBeTruthy();
    expect(screen.getAllByText('Capability state is unknown.').length).toBeGreaterThan(0);
  });

  it('never renders or loads context when the direct-route owner does not match', () => {
    const load = vi.fn<CapabilityDataSource['load']>();
    render(
      <InstanceDetail
        instanceId="someone-else"
        module="messages"
        instance={owner}
        capabilityDataSource={{ load }}
      />,
    );

    expect(screen.queryByText('Owner modem')).toBeNull();
    expect(screen.queryByRole('navigation', { name: 'Instance modules' })).toBeNull();
    expect(screen.getByText(/Instance context is unavailable/i)).toBeTruthy();
    expect(load).not.toHaveBeenCalled();
  });

  it('aborts the prior owner load and fences stale results to the latest owner', async () => {
    const pending = new Map<
      string,
      { resolve: (value: InstanceCapabilityMap) => void; signal: AbortSignal }
    >();
    const dataSource: CapabilityDataSource = {
      load(instanceId, signal) {
        return new Promise((resolve) => pending.set(instanceId, { resolve, signal }));
      },
    };
    const second: InstanceContext = { ...owner, id: 'second', name: 'Second modem' };
    const { rerender } = render(
      <InstanceDetail
        instanceId="owner"
        module="overview"
        instance={owner}
        capabilityDataSource={dataSource}
      />,
    );
    await waitFor(() => expect(pending.has('owner')).toBe(true));

    rerender(
      <InstanceDetail
        instanceId="second"
        module="overview"
        instance={second}
        capabilityDataSource={dataSource}
      />,
    );
    await waitFor(() => expect(pending.has('second')).toBe(true));
    expect(pending.get('owner')?.signal.aborted).toBe(true);

    pending.get('second')?.resolve({ overview: { state: 'supported' } });
    expect(await screen.findByRole('link', { name: 'Overview' })).toBeTruthy();
    pending
      .get('owner')
      ?.resolve({ overview: { state: 'unsupported', explanation: 'Stale owner result' } });
    await waitFor(() => expect(screen.queryByText('Stale owner result')).toBeNull());
    expect(screen.getByText('Second modem')).toBeTruthy();
  });

  it.each<[InstanceModule, string]>([
    ['cellular', 'Cellular'],
    ['device-network', 'Device Network'],
    ['automation', 'Automation'],
    ['ota', 'OTA'],
  ])('uses the existing module contract for %s', (module, label) => {
    render(
      <InstanceDetail
        instanceId="owner"
        module={module}
        instance={owner}
        capabilities={{ [module]: { state: 'supported' } }}
      />,
    );
    expect(screen.getByRole('heading', { name: label })).toBeTruthy();
  });
});
