import { describe, it, expect, vi } from 'vitest';
import { screen, fireEvent } from '@testing-library/react';
import { renderWithProviders } from '../test/utils';
import InsuranceModal, {
  buildInsurancePayload, contractToForm, EMPTY_FORM, type Contract, type InsuranceOption,
} from './InsuranceModal';
import type { ServiceCategoryOption } from '../hooks/useServiceCategories';

const mkContract = (over: Partial<Contract> = {}): Contract => ({
  uuid: 'c-1', insurance_id: 3, insurance_name: 'بیمه ایران', insurance_kind: 'basic',
  version: 1, is_active: true, coverage_percent: 70, franchise_percent: 15,
  annual_ceiling_rials: 20_000_000, kind: 'basic', effective_from: 1_700_000_000,
  effective_to: null,
  category_coverages: { outpatient: 70, inpatient: 30 },
  category_coverage_source: { outpatient: 'override', inpatient: 'admin_default' },
  ...over,
});

const options: InsuranceOption[] = [
  { insurance_id: 3, insurance_name: 'بیمه ایران', type: 'basic', coverage_defaults: { outpatient: 70, inpatient: 30 } },
  { insurance_id: 5, insurance_name: 'بیمه آسیا', type: 'supplementary', coverage_defaults: { outpatient: 40, inpatient: 20 } },
];

const categories: ServiceCategoryOption[] = [
  { key: 'outpatient', label: 'خدمات سرپایی' },
  { key: 'inpatient', label: 'خدمات بستری' },
];

describe('buildInsurancePayload', () => {
  it('keeps the franchise a percent, converts ceiling toman → rials and Y-m-d → unix', () => {
    const payload = buildInsurancePayload({
      ...EMPTY_FORM, insuranceId: '3', kind: 'supplementary',
      categoryPercents: { outpatient: '80', inpatient: '30' },
      franchise: '10', ceiling: '2000000',
      effectiveFrom: '2024-01-01', effectiveTo: '2025-01-01',
    });
    expect(payload.insurance_id).toBe(3);
    expect(payload.kind).toBe('supplementary');
    expect(payload.coverage_percent).toBe(80); // ستون قدیمی = درصد سرپایی
    expect(payload.category_coverages).toEqual([
      { key: 'outpatient', coverage_percent: 80 },
      { key: 'inpatient', coverage_percent: 30 },
    ]);
    expect(payload.franchise_percent).toBe(10); // درصد است، نه مبلغ
    expect(payload.annual_ceiling_rials).toBe(20_000_000);
    expect(typeof payload.effective_from).toBe('number');
    expect(payload.effective_to).toBeGreaterThan(payload.effective_from!);
  });

  it('empty ceiling → null (بی‌نهایت), empty dates → null', () => {
    const payload = buildInsurancePayload({
      ...EMPTY_FORM, insuranceId: '3', categoryPercents: { outpatient: '50' },
    });
    expect(payload.annual_ceiling_rials).toBeNull();
    expect(payload.effective_from).toBeNull();
    expect(payload.effective_to).toBeNull();
  });

  it('forces franchise to zero on a basic contract', () => {
    const payload = buildInsurancePayload({
      ...EMPTY_FORM, insuranceId: '3', kind: 'basic', franchise: '10',
      categoryPercents: { outpatient: '70' },
    });
    expect(payload.franchise_percent).toBe(0);
  });

  it('omits category_coverages when the user may not override them', () => {
    const payload = buildInsurancePayload(
      { ...EMPTY_FORM, insuranceId: '3', categoryPercents: { outpatient: '70' } },
      null,
      false,
    );
    expect(payload).not.toHaveProperty('category_coverages');
  });
});

describe('contractToForm', () => {
  it('maps the franchise percent, contract kind, and effective category percents', () => {
    const form = contractToForm(mkContract({ franchise_percent: 30, kind: 'supplementary' }));
    expect(form.franchise).toBe('30');
    expect(form.kind).toBe('supplementary');
    expect(form.categoryPercents).toEqual({ outpatient: '70', inpatient: '30' });
  });
});

describe('InsuranceModal', () => {
  it('renders one percent input per category and hides franchise on basic', () => {
    renderWithProviders(
      <InsuranceModal open editContract={null} options={options} categories={categories} kind="basic" onClose={() => {}} onSubmit={() => {}} />,
    );
    expect(screen.getByText('افزودن بیمه')).toBeInTheDocument();
    expect(screen.getByText('نام بیمه')).toBeInTheDocument();
    // Manual "نوع بیمه" select is gone; kind is shown as a read-only chip from the tab.
    expect(screen.queryByText('نوع بیمه')).not.toBeInTheDocument();
    expect(screen.getByText('پایه')).toBeInTheDocument();
    expect(screen.getByText('درصد پوشش — خدمات سرپایی')).toBeInTheDocument();
    expect(screen.getByText('درصد پوشش — خدمات بستری')).toBeInTheDocument();
    expect(screen.queryByText('فرانشیز (درصد)')).not.toBeInTheDocument();
    expect(screen.getByText('سقف تعهد (تومان)')).toBeInTheDocument();
    expect(screen.getByText('ثبت بیمه')).toBeInTheDocument();
  });

  it('shows the franchise field for a supplementary contract', () => {
    renderWithProviders(
      <InsuranceModal open editContract={null} options={options} categories={categories} kind="supplementary" onClose={() => {}} onSubmit={() => {}} />,
    );
    expect(screen.getByText('تکمیلی')).toBeInTheDocument();
    expect(screen.getByText('فرانشیز (درصد)')).toBeInTheDocument();
  });

  it('blocks submit until every rendered category has a valid percent', () => {
    const onSubmit = vi.fn();
    renderWithProviders(
      <InsuranceModal
        open
        editContract={mkContract({ category_coverages: { outpatient: 70 } })}
        options={options}
        categories={categories}
        kind="basic"
        onClose={() => {}}
        onSubmit={onSubmit}
      />,
    );

    // بستری بدون درصد مانده: ثبت باید بسته باشد و پیام الزامی دیده شود.
    expect(screen.getByText('ثبت بیمه')).toBeDisabled();
    expect(screen.getByText('درصد پوشش الزامی است (۱ تا ۱۰۰)')).toBeInTheDocument();

    fireEvent.change(screen.getByLabelText('درصد پوشش خدمات بستری'), { target: { value: '30' } });
    expect(screen.getByText('ثبت بیمه')).not.toBeDisabled();

    fireEvent.click(screen.getByText('ثبت بیمه'));
    expect(onSubmit).toHaveBeenCalled();
  });

  it('renders only the service kinds it is given', () => {
    renderWithProviders(
      <InsuranceModal
        open
        editContract={null}
        options={options}
        categories={[{ key: 'outpatient', label: 'خدمات سرپایی' }]}
        kind="basic"
        onClose={() => {}}
        onSubmit={() => {}}
      />,
    );
    expect(screen.getByText('درصد پوشش — خدمات سرپایی')).toBeInTheDocument();
    expect(screen.queryByText('درصد پوشش — خدمات بستری')).not.toBeInTheDocument();
  });

  it('prefills the percents of an edited contract and marks admin defaults', () => {
    renderWithProviders(
      <InsuranceModal open editContract={mkContract()} options={options} categories={categories} kind="basic" onClose={() => {}} onSubmit={() => {}} />,
    );
    expect(screen.getByLabelText('درصد پوشش خدمات سرپایی')).toHaveValue('70');
    expect(screen.getByLabelText('درصد پوشش خدمات بستری')).toHaveValue('30');
    expect(screen.getByText('پیش‌فرض ادمین')).toBeInTheDocument();
  });

  it('makes the percents read-only without the update permission', () => {
    renderWithProviders(
      <InsuranceModal open editContract={mkContract()} options={options} categories={categories} kind="basic" canUpdate={false} onClose={() => {}} onSubmit={() => {}} />,
    );
    expect(screen.getByLabelText('درصد پوشش خدمات سرپایی')).toHaveAttribute('readonly');
    expect(screen.getAllByText('مقدار پیش‌فرض تنظیمات مرکزی').length).toBe(2);
  });

  it('submits the built payload for an edited contract', () => {
    const onSubmit = vi.fn();
    renderWithProviders(
      <InsuranceModal open editContract={mkContract()} options={options} categories={categories} kind="basic" onClose={() => {}} onSubmit={onSubmit} />,
    );
    fireEvent.click(screen.getByText('ثبت بیمه'));
    expect(onSubmit).toHaveBeenCalledWith(expect.objectContaining({
      insurance_id: 3, coverage_percent: 70, franchise_percent: 0, kind: 'basic',
      category_coverages: [
        { key: 'outpatient', coverage_percent: 70 },
        { key: 'inpatient', coverage_percent: 30 },
      ],
    }));
  });
});
