import React from 'react';
import { render, screen } from '@testing-library/react';
import { describe, expect, it } from 'vitest';

import { ObjectList } from '../src/platform/features/objects/components/ObjectList';
import type { SObjectDescribe } from '../src/platform/types';

/**
 * Object Manager cards rendered a hardcoded "No description" for every object,
 * with a comment conceding the reason: the list response has no description
 * field. So ~300 objects looked undocumented, including the ones whose
 * descriptions carry retirement markers.
 *
 * This is a different failure from the rest of the #607 family: nothing was
 * *read* here, so no type check could have caught it. These tests pin the
 * binding itself — that the card shows a real description, and that it does not
 * claim "No description" before the authoring read has answered.
 */

function describeEntry(name: string, label = name): SObjectDescribe {
  return {
    name,
    label,
    labelPlural: `${label}s`,
    custom: false,
    keyPrefix: '001',
    createable: true,
    updateable: true,
    deletable: true,
    retrieveable: true,
    searchable: true,
    triggerable: true,
    undeletable: true,
    mergeable: false,
    deprecatedAndHidden: false,
    layoutable: true,
    queryable: true,
    replicateable: true,
    feedEnabled: true,
  } as unknown as SObjectDescribe;
}

const RETIREMENT_MARKER =
  'RETIRED — superseded by OrderItem (2026-07-23). Read from OrderItem instead.';

describe('Object Manager cards — description', () => {
  it('renders the description from the authoring map', () => {
    render(
      <ObjectList
        schemas={[describeEntry('Account')]}
        descriptions={new Map([['account', 'Standard Salesforce Account object']])}
        descriptionStatus="loaded"
        onDelete={() => {}}
      />,
    );

    expect(screen.getByText('Standard Salesforce Account object')).toBeInTheDocument();
    expect(screen.queryByText('No description')).not.toBeInTheDocument();
  });

  it('matches objects case-insensitively, since the map is keyed lowercase', () => {
    render(
      <ObjectList
        schemas={[describeEntry('Order_Product__c')]}
        descriptions={new Map([['order_product__c', RETIREMENT_MARKER]])}
        descriptionStatus="loaded"
        onDelete={() => {}}
      />,
    );

    expect(screen.getByText(RETIREMENT_MARKER)).toBeInTheDocument();
  });

  it('does not claim "No description" while the read is still out', () => {
    render(
      <ObjectList
        schemas={[describeEntry('Account')]}
        descriptions={null}
        descriptionStatus="loading"
        onDelete={() => {}}
      />,
    );

    // The old code said this unconditionally and forever.
    expect(screen.queryByText('No description')).not.toBeInTheDocument();
    expect(screen.getByText('Loading…')).toBeInTheDocument();
  });

  it('does not strand cards on "Loading…" when the read failed', () => {
    // The first cut collapsed loading and failed into one boolean, so a failed
    // first load rendered every card as perpetually loading — no error, no way
    // out. Three states exist precisely so this cannot happen.
    render(
      <ObjectList
        schemas={[describeEntry('Account')]}
        descriptions={null}
        descriptionStatus="unavailable"
        onDelete={() => {}}
      />,
    );

    expect(screen.queryByText('Loading…')).not.toBeInTheDocument();
    expect(screen.queryByText('No description')).not.toBeInTheDocument();
    expect(screen.getByText('Descriptions unavailable')).toBeInTheDocument();
  });

  it('says "No description" only once the read confirms the object has none', () => {
    render(
      <ObjectList
        schemas={[describeEntry('Account')]}
        descriptions={new Map()}
        descriptionStatus="loaded"
        onDelete={() => {}}
      />,
    );

    expect(screen.getByText('No description')).toBeInTheDocument();
  });

  it('treats a whitespace-only description as absent', () => {
    render(
      <ObjectList
        schemas={[describeEntry('Account')]}
        descriptions={new Map([['account', '   ']])}
        descriptionStatus="loaded"
        onDelete={() => {}}
      />,
    );

    expect(screen.getByText('No description')).toBeInTheDocument();
  });

  it('renders each card against its own object, not a shared value', () => {
    render(
      <ObjectList
        schemas={[describeEntry('Account'), describeEntry('Contact'), describeEntry('Lead')]}
        descriptions={new Map([['account', 'Account desc'], ['lead', 'Lead desc']])}
        descriptionStatus="loaded"
        onDelete={() => {}}
      />,
    );

    expect(screen.getByText('Account desc')).toBeInTheDocument();
    expect(screen.getByText('Lead desc')).toBeInTheDocument();
    // Contact has none, and must not inherit a neighbour's text.
    expect(screen.getAllByText('No description')).toHaveLength(1);
  });
});
