import { describe, it, expect, vi } from 'vitest';
import { useState } from 'react';
import { render, screen, fireEvent } from '@testing-library/react';
import PriceInput from './PriceInput';

/** پوشش حالت واقعی: مقدار توسط والد نگه داشته می‌شود (controlled). */
function Controlled({ initial = 0, ...rest }: { initial?: number } & Record<string, unknown>) {
  const [value, setValue] = useState(initial);
  return (
    <>
      <PriceInput value={value} onChange={setValue} {...rest} />
      <span data-testid="value">{value}</span>
    </>
  );
}

const input = () => screen.getByRole('textbox') as HTMLInputElement;
const emitted = () => screen.getByTestId('value').textContent;

describe('PriceInput', () => {
  it('رقم فارسی را می‌پذیرد و عدد لاتین می‌دهد', () => {
    render(<Controlled />);
    fireEvent.change(input(), { target: { value: '۸۵۰۰۰' } });

    expect(emitted()).toBe('85000');
    expect(input().value).toBe('۸۵٬۰۰۰');
  });

  it('رقم عربی را می‌پذیرد', () => {
    render(<Controlled />);
    fireEvent.change(input(), { target: { value: '٢٥٠' } });

    expect(emitted()).toBe('250');
  });

  it('پیست با واحد و جداکننده پاک‌سازی می‌شود', () => {
    render(<Controlled />);
    fireEvent.change(input(), { target: { value: '۸۵,۰۰۰ تومان' } });

    expect(emitted()).toBe('85000');
  });

  it('صفرِ تایپ‌شده حفظ می‌شود و به خالی تبدیل نمی‌شود', () => {
    render(<Controlled />);
    fireEvent.change(input(), { target: { value: '۰' } });

    expect(input().value).toBe('۰');
    expect(emitted()).toBe('0');
  });

  it('پاک‌کردن فیلد ⇒ خالی و مقدار صفر', () => {
    render(<Controlled initial={5000} />);
    fireEvent.change(input(), { target: { value: '' } });

    expect(input().value).toBe('');
    expect(emitted()).toBe('0');
  });

  it('مقدار اولیه صفر ⇒ فیلد خالی (نه ۰)', () => {
    render(<Controlled initial={0} />);
    expect(input().value).toBe('');
  });

  it('min حین تایپ اعمال نمی‌شود ولی روی blur اعمال می‌شود', () => {
    render(<Controlled min={100} />);
    fireEvent.change(input(), { target: { value: '۵' } });
    expect(emitted()).toBe('5');

    fireEvent.blur(input());
    expect(emitted()).toBe('100');
    expect(input().value).toBe('۱۰۰');
  });

  it('max روی blur اعمال می‌شود', () => {
    render(<Controlled max={1000} />);
    fireEvent.change(input(), { target: { value: '۵۰۰۰' } });
    fireEvent.blur(input());

    expect(emitted()).toBe('1000');
  });

  it('فیلد خالی روی blur به min پرت نمی‌شود', () => {
    render(<Controlled min={100} />);
    fireEvent.blur(input());

    expect(input().value).toBe('');
    expect(emitted()).toBe('0');
  });

  it('حروف نامعتبر حذف می‌شوند و هرگز NaN نمی‌دهد', () => {
    render(<Controlled />);
    fireEvent.change(input(), { target: { value: 'ابج' } });

    expect(input().value).toBe('');
    expect(emitted()).toBe('0');
    expect(emitted()).not.toContain('NaN');
  });

  it('latin ارقام لاتین با کاما نمایش می‌دهد', () => {
    render(<Controlled latin />);
    fireEvent.change(input(), { target: { value: '۱۲۰۰' } });

    expect(input().value).toBe('1,200');
  });

  it('suffix واحد را کنار فیلد نشان می‌دهد', () => {
    render(<Controlled suffix="تومان" />);
    expect(screen.getByText('تومان')).toBeTruthy();
  });

  it('تغییر مقدار از بیرون متن فیلد را همگام می‌کند', () => {
    const { rerender } = render(<PriceInput value={1000} onChange={vi.fn()} />);
    expect(input().value).toBe('۱٬۰۰۰');

    rerender(<PriceInput value={0} onChange={vi.fn()} />);
    expect(input().value).toBe('');
  });

  /**
   * برچسبِ کنارِ بعضی فیلدهای مبلغ `<label>` واقعی نیست (span/div)، پس نامِ
   * دسترسی‌پذیر باید صریح داده شود؛ پیش از این آن فیلدها input خام بودند و
   * `aria-label` خودشان را داشتند.
   */
  it('ariaLabel نام دسترسی‌پذیر می‌سازد', () => {
    render(<PriceInput value={0} onChange={vi.fn()} ariaLabel="قیمت ویزیت" />);

    expect(screen.getByRole('textbox', { name: 'قیمت ویزیت' })).toBeTruthy();
  });

  it('ariaInvalid فقط در حالت خطا روی فیلد می‌نشیند', () => {
    const { rerender } = render(<PriceInput value={0} onChange={vi.fn()} ariaInvalid />);
    expect(input().getAttribute('aria-invalid')).toBe('true');

    rerender(<PriceInput value={0} onChange={vi.fn()} />);
    expect(input().getAttribute('aria-invalid')).toBeNull();
  });
});
