import { flushPromises, mount } from '@vue/test-utils';

import { beforeEach, describe, expect, it, vi } from 'vitest';

import StabilityAnalysisPage from '../../index.vue';
import pageSource from '../../index.vue?raw';

const apiMocks = vi.hoisted(() => ({
  getData: vi.fn(),
  getOptions: vi.fn(),
}));
const exportMocks = vi.hoisted(() => ({ download: vi.fn() }));

vi.mock('#/api/x/lims/wendingxing', () => ({
  getStabilityAnalysisData: apiMocks.getData,
  getStabilityAnalysisOptions: apiMocks.getOptions,
}));

vi.mock('../../helpers/stabilityExport', () => ({
  downloadStabilityExport: exportMocks.download,
}));

vi.mock('@jnpf/hooks', () => ({
  useMessage: () => ({ createMessage: { error: vi.fn(), warning: vi.fn() } }),
}));

vi.mock('@vben/plugins/echarts', () => ({
  EchartsUI: { name: 'EchartsUI', template: '<div />' },
  useEcharts: () => ({ renderEcharts: vi.fn() }),
}));

const PopupStub = {
  name: 'AnalysisOptionPopup',
  props: ['columns', 'disabled', 'mode', 'options', 'popupTitle', 'value'],
  template: '<div class="popup-stub" />',
};

function mountPage() {
  return mount(StabilityAnalysisPage, {
    global: {
      stubs: {
        'a-alert': { template: '<div class="alert-stub"><slot /></div>' },
        'a-button': { props: ['disabled'], template: '<button :disabled="disabled" @click="$emit(\'click\')"><slot /></button>' },
        ASpin: { template: '<div><slot /></div>' },
        'a-empty': { props: ['description'], template: '<div class="empty-stub">{{ description }}</div>' },
        'a-table': {
          name: 'ATable',
          props: ['bordered', 'columns', 'dataSource', 'pagination', 'scroll', 'tableLayout'],
          template: '<div class="analysis-table" />',
        },
        AnalysisOptionPopup: PopupStub,
      },
    },
  });
}

async function selectFilters(wrapper: ReturnType<typeof mountPage>) {
  await flushPromises();
  const popup = (title: string) => wrapper.findAllComponents(PopupStub).find((item) => item.props('popupTitle') === title)!;

  popup('选择分类').vm.$emit('update:value', 'CJ');
  popup('选择分类').vm.$emit('change', 'CJ');
  await flushPromises();
  popup('选择品名').vm.$emit('update:value', 'product-1');
  popup('选择品名').vm.$emit('change', 'product-1');
  await flushPromises();
  popup('选择检验项目').vm.$emit('update:value', ['item-ph']);
  popup('选择检验项目').vm.$emit('change', ['item-ph']);
  await flushPromises();
  popup('选择稳定性考察编号').vm.$emit('update:value', ['plan-1']);
  popup('选择稳定性考察编号').vm.$emit('change', ['plan-1']);
  await flushPromises();
  popup('选择批号').vm.$emit('update:value', ['plan-1::250102']);
  popup('选择批号').vm.$emit('change', ['plan-1::250102']);
  await wrapper.vm.$nextTick();
}

describe('stability analysis page', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    apiMocks.getOptions.mockResolvedValue({
      data: {
        fenlei_list: [{ code: 'CJ', id: 'category-1', key: 'CJ', name: '成品' }],
        jihua_list: [{ code: 'STP-1', id: 'plan-1', key: 'plan-1', name: 'STP-1' }],
        pihao_list: [
          {
            fangan_mingcheng: '长期稳定性方案',
            jihua_bianhao: 'STP-1',
            jihua_id: 'plan-1',
            key: 'plan-1::250102',
            name: '250102',
            pihao: '250102',
          },
        ],
        xiangmu_list: [{ code: 'XM1899', id: 'item-ph', key: 'item-ph', name: 'pH值', shuju_leixing: '数值' }],
        yangpin_list: [{ code: 'YP001', id: 'product-1', key: 'product-1', name: '脉络宁口服液' }],
      },
    });
    apiMocks.getData.mockResolvedValue({
      data: {
        completeness: { audited_count: 1, expected_count: 3, missing_count: 1, pending_count: 1 },
        expected_periods: [{ xiangmu_id: 'item-ph', zhouqi: '0', zhouqi_danwei: '/', zhouqi_order: 0 }],
        rows: [
          {
            batch_key: 'plan-1::250102',
            biaozhun_id: 'standard-1',
            exception_type: '',
            jieguo_luru_riqi: '2026-07-23',
            jihua_bianhao: 'STP-1',
            jihua_id: 'plan-1',
            numeric_result: 6.7,
            pihao: '250102',
            raw_result: '6.7',
            shangxian: '7',
            shangxian_value: 7,
            shuju_leixing: '数值',
            unit: '/',
            xiaxian: '5',
            xiaxian_value: 5,
            xiangmu_bianma: 'XM1899',
            xiangmu_id: 'item-ph',
            xiangmu_mingcheng: 'pH值',
            yangpin_mingcheng: '脉络宁口服液',
            zhouqi: '0',
            zhouqi_danwei: '/',
            zhouqi_order: 0,
          },
        ],
      },
    });
  });

  it('uses a compact report layout with a dedicated result scroller', async () => {
    const wrapper = mountPage();
    await flushPromises();

    expect(wrapper.find('.page-heading').exists()).toBe(false);
    expect(wrapper.find('[data-scroll-container="true"]').exists()).toBe(true);
    expect(wrapper.find('.filter-toolbar').exists()).toBe(true);
    expect(wrapper.find('.table-section').exists()).toBe(true);
    expect(wrapper.find('.table-section h2').text()).toBe('稳定性数据分析表');
    expect(wrapper.find('.analysis-table').exists()).toBe(true);
    expect(wrapper.findComponent({ name: 'ATable' }).props('dataSource')).toEqual([]);
    expect(wrapper.find('.completeness-band').exists()).toBe(false);
    expect(wrapper.find('.empty-stub').exists()).toBe(false);
  });

  it('keeps five equal filters and fixed-width actions on one row', () => {
    expect(pageSource).toContain('grid-template-columns: repeat(5, minmax(0, 1fr)) 188px;');
    expect(pageSource).toContain('width: 96px;');
    expect(pageSource).toContain('width: 84px;');
    expect(pageSource).not.toContain('.filter-toolbar {\n  display: flex;');
  });

  it('shows only project identity and data type columns in the project popup', async () => {
    const wrapper = mountPage();
    await flushPromises();
    const itemPopup = wrapper.findAllComponents(PopupStub).find((item) => item.props('popupTitle') === '选择检验项目')!;
    const columnKeys = (itemPopup.props('columns') as Array<{ dataIndex: string }>).map((column) => column.dataIndex);

    expect(columnKeys).toEqual(['sequence', 'code', 'name', 'shuju_leixing']);
    expect(columnKeys).not.toContain('unit');
  });

  it('renders the full result table without pagination or horizontal scrolling', async () => {
    const wrapper = mountPage();
    await selectFilters(wrapper);
    await wrapper.find('[data-action="search"]').trigger('click');
    await flushPromises();

    const table = wrapper.findComponent({ name: 'ATable' });
    expect(table.props('bordered')).not.toBeUndefined();
    expect(table.props('pagination')).toBe(false);
    expect(table.props('scroll')).toBeUndefined();
    expect(table.props('tableLayout')).toBe('fixed');
    expect(wrapper.find('.export-implementation-note').exists()).toBe(false);
  });

  it('closes the bottom border of the empty table placeholder', () => {
    expect(pageSource).toContain(':deep(.ant-table-tbody > .ant-table-placeholder > td)');
    expect(pageSource).toContain('border-bottom: 1px solid #b9c2ce !important;');
  });

  it('renders the raw result without compliance annotations', async () => {
    const defaultResponse = await apiMocks.getData();
    apiMocks.getData.mockResolvedValueOnce({
      data: {
        completeness: { audited_count: 1, expected_count: 1, missing_count: 0, pending_count: 0 },
        expected_periods: [],
        rows: [
          {
            ...defaultResponse.data.rows[0],
            exception_type: 'non_compliant',
            raw_result: '6.7',
          },
        ],
      },
    });
    const wrapper = mountPage();
    await selectFilters(wrapper);
    await wrapper.find('[data-action="search"]').trigger('click');
    await flushPromises();

    const table = wrapper.findComponent({ name: 'ATable' });
    const resultColumn = (table.props('columns') as Array<Record<string, any>>).find((column) => column.dataIndex === 'raw_result');
    const resultRow = (table.props('dataSource') as Array<Record<string, any>>)[0];
    expect(resultColumn?.customRender({ record: resultRow })).toBe('6.7');
  });

  it('queries audited rows and exports the displayed rows in the browser', async () => {
    const wrapper = mountPage();
    await selectFilters(wrapper);

    await wrapper.find('[data-action="search"]').trigger('click');
    await flushPromises();

    const expectedQuery = {
      fenlei_bianma: 'CJ',
      jihua_ids: ['plan-1'],
      pihao_keys: [{ jihua_id: 'plan-1', pihao: '250102' }],
      xiangmu_ids: ['item-ph'],
      yangpin_id: 'product-1',
    };
    expect(apiMocks.getData).toHaveBeenCalledWith(expectedQuery);
    expect(wrapper.find('.completeness-band').exists()).toBe(false);
    expect(wrapper.find('.analysis-table').exists()).toBe(true);
    expect(wrapper.find('.chart-block').exists()).toBe(true);

    await wrapper.find('[data-action="export"]').trigger('click');
    await flushPromises();
    const queriedResponse = await apiMocks.getData.mock.results[0]?.value;
    expect(exportMocks.download).toHaveBeenCalledWith(queriedResponse.data.rows);
  });

  it('keeps the last result and does not query automatically when the category changes', async () => {
    const wrapper = mountPage();
    await selectFilters(wrapper);
    await wrapper.find('[data-action="search"]').trigger('click');
    await flushPromises();
    const queryCount = apiMocks.getData.mock.calls.length;
    const popup = (title: string) => wrapper.findAllComponents(PopupStub).find((item) => item.props('popupTitle') === title)!;

    popup('选择分类').vm.$emit('update:value', 'YL');
    popup('选择分类').vm.$emit('change', 'YL');
    await flushPromises();

    expect(popup('选择品名').props('value')).toBeUndefined();
    expect(popup('选择检验项目').props('value')).toEqual([]);
    expect(popup('选择稳定性考察编号').props('value')).toEqual([]);
    expect(popup('选择批号').props('value')).toEqual([]);
    expect(apiMocks.getData).toHaveBeenCalledTimes(queryCount);
    expect(wrapper.find('.analysis-table').exists()).toBe(true);
    expect(wrapper.find('.completeness-band').exists()).toBe(false);
    expect(wrapper.find<HTMLButtonElement>('[data-action="export"]').element.disabled).toBe(false);

    await wrapper.find('[data-action="export"]').trigger('click');
    await flushPromises();
    const queriedResponse = await apiMocks.getData.mock.results[0]?.value;
    expect(exportMocks.download).toHaveBeenLastCalledWith(queriedResponse.data.rows);
    expect(apiMocks.getData).toHaveBeenCalledTimes(queryCount);
  });
});
