import { fireEvent, render, screen } from '@testing-library/react';
import type { ComponentProps } from 'react';
import { beforeEach, describe, expect, it, vi } from 'vitest';

import {
  SendEmailPanel,
  getSendEmailRecipientDisplay,
  isEditableSendEmailScalar,
} from '../src/platform/features/flows/components/builder/panels/SendEmailPanel';

const queryState = vi.hoisted(() => ({
  current: {
    data: [
      {
        Id: 'tmpl-1',
        Name: 'Welcome Template',
        Subject: 'Welcome',
        IsActive: true,
        CreatedDate: '2026-01-01T00:00:00Z',
        LastModifiedDate: '2026-01-01T00:00:00Z',
        DeveloperName: 'Welcome_Template',
      },
    ],
    isError: false,
    isLoading: false,
  },
}));

vi.mock('@tanstack/react-query', () => ({
  useQuery: () => queryState.current,
}));

describe('SendEmailPanel app-pack behavior coverage', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    queryState.current = {
      data: [
        {
          Id: 'tmpl-1',
          Name: 'Welcome Template',
          Subject: 'Welcome',
          IsActive: true,
          CreatedDate: '2026-01-01T00:00:00Z',
          LastModifiedDate: '2026-01-01T00:00:00Z',
          DeveloperName: 'Welcome_Template',
        },
      ],
      isError: false,
      isLoading: false,
    };
  });

  it('lists active email templates and writes the selected id to templateId', () => {
    queryState.current = {
      data: [
        {
          Id: 'tmpl-active',
          Name: 'Active Template',
          Subject: 'Active',
          IsActive: true,
          CreatedDate: '2026-01-01T00:00:00Z',
          LastModifiedDate: '2026-01-01T00:00:00Z',
          DeveloperName: 'Active_Template',
        },
        {
          Id: 'tmpl-inactive',
          Name: 'Inactive Template',
          Subject: 'Inactive',
          IsActive: false,
          CreatedDate: '2026-01-01T00:00:00Z',
          LastModifiedDate: '2026-01-01T00:00:00Z',
          DeveloperName: 'Inactive_Template',
        },
      ],
      isError: false,
      isLoading: false,
    };
    const updateConfig = vi.fn();

    renderPanel({
      actionConfig: {
        to: 'person@example.com',
        variables: {},
      },
      updateConfig,
    });

    const templateSelect = screen.getByLabelText('Select template...');
    expect(screen.getByText('Active Template')).toBeInTheDocument();
    expect(screen.queryByText('Inactive Template')).not.toBeInTheDocument();

    fireEvent.change(templateSelect, { target: { value: 'tmpl-active' } });

    expect(updateConfig).toHaveBeenCalledWith('templateId', { stringValue: 'tmpl-active' });
  });

  it('keeps templateId element references editable outside the template picker', () => {
    const updateConfig = vi.fn();

    renderPanel({
      actionConfig: {
        templateId: { elementReference: 'SelectedTemplateId' },
        to: 'person@example.com',
        variables: {},
      },
      updateConfig,
    });

    fireEvent.change(screen.getByDisplayValue('{!SelectedTemplateId}'), {
      target: { value: '{!NextTemplateId}' },
    });

    expect(updateConfig).toHaveBeenCalledWith('templateId', { elementReference: 'NextTemplateId' });
    expect(screen.queryByText(/not in active template list/)).not.toBeInTheDocument();
  });

  it('keeps manual templateId editing available when template lookup fails', () => {
    queryState.current = {
      data: [],
      isError: true,
      isLoading: false,
    };
    const updateConfig = vi.fn();

    renderPanel({
      actionConfig: {
        templateId: { elementReference: 'SelectedTemplateId' },
        to: 'person@example.com',
        variables: {},
      },
      updateConfig,
    });

    expect(screen.getByText('Template lookup failed; enter a template ID or resource reference.')).toBeInTheDocument();

    fireEvent.change(screen.getByDisplayValue('{!SelectedTemplateId}'), {
      target: { value: 'tmpl-manual' },
    });

    expect(updateConfig).toHaveBeenCalledWith('templateId', { stringValue: 'tmpl-manual' });
  });

  it('keeps collection recipient values read-only so save preserves raw metadata', () => {
    const updateConfig = vi.fn();
    const to = [{ stringValue: 'primary@example.com' }, { elementReference: 'MoreRecipients' }];
    const cc = [{ elementReference: 'CcRecipients' }];

    renderPanel({
      actionConfig: {
        templateId: 'tmpl-1',
        to,
        cc,
        variables: {},
      },
      updateConfig,
    });

    const toInput = screen.getByDisplayValue(JSON.stringify(to)) as HTMLInputElement;
    const ccInput = screen.getByDisplayValue(JSON.stringify(cc)) as HTMLInputElement;

    expect(toInput.readOnly).toBe(true);
    expect(ccInput.readOnly).toBe(true);

    fireEvent.change(toInput, { target: { value: 'mutated@example.com' } });
    fireEvent.change(ccInput, { target: { value: 'mutated-cc@example.com' } });

    expect(updateConfig).not.toHaveBeenCalledWith('to', expect.anything());
    expect(updateConfig).not.toHaveBeenCalledWith('cc', expect.anything());
  });

  it('continues editing scalar literal and reference recipients', () => {
    const updateConfig = vi.fn();

    renderPanel({
      actionConfig: {
        templateId: 'tmpl-1',
        to: 'person@example.com',
        cc: { elementReference: 'CcRecipient' },
        variables: {},
      },
      updateConfig,
    });

    const toInput = screen.getByDisplayValue('person@example.com') as HTMLInputElement;
    const ccInput = screen.getByDisplayValue('{!CcRecipient}') as HTMLInputElement;

    expect(toInput.readOnly).toBe(false);
    expect(ccInput.readOnly).toBe(false);

    fireEvent.change(toInput, { target: { value: 'other@example.com' } });
    fireEvent.change(ccInput, { target: { value: '{!OtherCcRecipient}' } });

    expect(updateConfig).toHaveBeenCalledWith('to', { stringValue: 'other@example.com' });
    expect(updateConfig).toHaveBeenCalledWith('cc', { elementReference: 'OtherCcRecipient' });
  });

  it('edits named scalar and reference variables without JSON rewriting', () => {
    const updateConfig = vi.fn();

    renderPanel({
      actionConfig: {
        templateId: 'tmpl-1',
        to: 'person@example.com',
        variables: { ApprovalUrl: { elementReference: 'ApprovalUrl' } },
      },
      updateConfig,
    });

    fireEvent.change(screen.getByDisplayValue('{!ApprovalUrl}'), {
      target: { value: '{!NextApprovalUrl}' },
    });
    expect(updateConfig).toHaveBeenCalledWith('variables', {
      ApprovalUrl: { elementReference: 'NextApprovalUrl' },
    });

    fireEvent.click(screen.getByRole('button', { name: 'Add' }));
    expect(updateConfig).toHaveBeenCalledWith('variables', {
      ApprovalUrl: { elementReference: 'ApprovalUrl' },
      Variable2: { stringValue: '' },
    });
  });

  it('does not overwrite sibling variables during duplicate rename drafts', () => {
    const updateConfig = vi.fn();

    renderPanel({
      actionConfig: {
        templateId: 'tmpl-1',
        to: 'person@example.com',
        variables: {
          First: { stringValue: 'first-value' },
          Second: { stringValue: 'second-value' },
        },
      },
      updateConfig,
    });

    const firstNameInput = screen.getByDisplayValue('First');

    fireEvent.change(firstNameInput, { target: { value: 'Second' } });
    expect(updateConfig).not.toHaveBeenCalledWith('variables', expect.anything());

    fireEvent.blur(firstNameInput);

    expect(screen.getByText('Name must be unique')).toBeInTheDocument();
    expect(updateConfig).not.toHaveBeenCalledWith('variables', expect.anything());

    fireEvent.change(firstNameInput, { target: { value: 'Third' } });
    fireEvent.blur(firstNameInput);

    expect(updateConfig).toHaveBeenCalledWith('variables', {
      Third: { stringValue: 'first-value' },
      Second: { stringValue: 'second-value' },
    });
  });

  it('classifies only scalar recipient values as editable', () => {
    expect(isEditableSendEmailScalar('person@example.com')).toBe(true);
    expect(isEditableSendEmailScalar({ elementReference: 'Recipients' })).toBe(true);
    expect(isEditableSendEmailScalar([{ elementReference: 'Recipients' }])).toBe(false);
    expect(isEditableSendEmailScalar({ values: [{ elementReference: 'Recipients' }] })).toBe(false);
    expect(getSendEmailRecipientDisplay([{ elementReference: 'Recipients' }])).toBe('[{"elementReference":"Recipients"}]');
  });
});

function renderPanel(props: ComponentProps<typeof SendEmailPanel>) {
  return render(<SendEmailPanel {...props} />);
}
