import React from 'react';
import { render, screen } from '@testing-library/react';
import { describe, expect, it } from 'vitest';
import { createCrmUiFieldComponents } from '../src/ui-field-components';
import type { CrmUiFieldDefinition } from '../src/ui-field-components';

// Decodes the handful of entities a stored long-text value can carry, so the
// renderer test exercises the same decode the default renderer applies.
const decodeHtmlEntities = (value: string): string =>
  value
    .replace(/&lt;/g, '<')
    .replace(/&gt;/g, '>')
    .replace(/&quot;/g, '"')
    .replace(/&#39;/g, "'")
    .replace(/&amp;/g, '&');

function textareaRenderer() {
  return createCrmUiFieldComponents({
    SearchableLookup: () => null,
    RecordLink: () => null,
    decodeHtmlEntities,
    sanitizeHtml: value => value,
    htmlToText: value => value,
    formatCurrency: value => String(value),
    formatDate: value => value,
    formatDateTime: value => value,
    getRecordValue: (record, fieldName) => record?.[fieldName],
    parseMultipicklistSelections: value => (Array.isArray(value) ? value.map(String) : []),
    joinMultipicklistSelections: values => values.join(';'),
  }).fieldRenderers.textarea;
}

const textBody: CrmUiFieldDefinition = { name: 'TextBody', label: 'Text Body', type: 'textarea' };

// A realistic plain-text email body: multiple paragraphs and hard newlines that
// the old single-line-truncating default renderer would have clipped to one row.
const MULTILINE = 'Hi team,\n\nThanks for the quick turnaround on the renewal.\nLet us reconnect next week.\n\n— Dana';

describe('textarea (long-text) renderer', () => {
  it('renders the full multi-line body with newlines preserved and no truncation on the detail surface', () => {
    const Textarea = textareaRenderer();
    const { container } = render(<Textarea field={textBody} value={MULTILINE} variant="detail" />);

    const block = container.firstElementChild as HTMLElement;
    expect(block.tagName).toBe('DIV');
    // Full content, verbatim — every line survives (no clip, no collapse).
    expect(block.textContent).toBe(MULTILINE);
    expect(block).toHaveTextContent('Thanks for the quick turnaround on the renewal.');
    expect(block).toHaveTextContent('— Dana');
    // Preserves whitespace/newlines and never single-line-truncates on detail.
    expect(block).toHaveClass('whitespace-pre-wrap');
    expect(block).not.toHaveClass('truncate');
  });

  it('truncates to a single line on compact surfaces (table and variant-less callers)', () => {
    for (const props of [{ variant: 'table' as const }, {}]) {
      const Textarea = textareaRenderer();
      const { container, unmount } = render(<Textarea field={textBody} value={MULTILINE} {...props} />);

      const el = container.firstElementChild as HTMLElement;
      expect(el.tagName).toBe('SPAN');
      expect(el).toHaveClass('truncate');
      expect(el).not.toHaveClass('whitespace-pre-wrap');
      // The full text stays reachable via the hover title even when clipped.
      expect(el).toHaveAttribute('title', MULTILINE);
      unmount();
    }
  });

  it('decodes HTML entities in the stored text instead of showing raw escapes', () => {
    const Textarea = textareaRenderer();
    const { container } = render(
      <Textarea field={textBody} value={'Tom &amp; Jerry &lt;3'} variant="detail" />,
    );

    expect(container.firstElementChild).toHaveTextContent('Tom & Jerry <3');
  });

  it('renders the empty placeholder for blank or missing values', () => {
    for (const value of ['', null, undefined]) {
      const Textarea = textareaRenderer();
      const { unmount } = render(<Textarea field={textBody} value={value} variant="detail" />);
      expect(screen.getByText('—')).toBeInTheDocument();
      unmount();
    }
  });
});
