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

import { fetchSearchResults, fetchSearchStageSummaries } from '@/services/searchService';
import { getSupabaseClient } from '@/lib/supabase';

vi.mock('@/lib/supabase', () => ({
  getSupabaseClient: vi.fn(),
}));

type QueryResponse = {
  data: unknown[] | null;
  error: { code?: string; message: string } | null;
};

function createQuery(response: QueryResponse) {
  const query = {
    order: vi.fn(() => query),
    eq: vi.fn(() => query),
    or: vi.fn(() => query),
    not: vi.fn(() => query),
    in: vi.fn(() => query),
    then: (onFulfilled: (value: QueryResponse) => unknown, onRejected?: (reason: unknown) => unknown) =>
      Promise.resolve(response).then(onFulfilled, onRejected),
    catch: (onRejected: (reason: unknown) => unknown) => Promise.resolve(response).catch(onRejected),
  };

  return query;
}

function createSupabaseMock(responses: Record<string, QueryResponse>) {
  return {
    from: vi.fn((table: string) => ({
      select: vi.fn(() => createQuery(responses[table] ?? { data: [], error: null })),
      delete: vi.fn(() => createQuery(responses[table] ?? { data: [], error: null })),
    })),
  };
}

describe('searchService', () => {
  beforeEach(() => {
    vi.resetAllMocks();
  });

  it('maps final_result_products with procurement and standardized lookups', async () => {
    vi.mocked(getSupabaseClient).mockReturnValue(createSupabaseMock({
      final_result_products: {
        data: [{
          id: 'fr-001',
          task_id: 'BATCH-001-ss-001',
          batch_id: 'BATCH-001',
          material_id: 'mat-001',
          main_keyword: '球墨铸铁井盖',
          stage_order: 1,
          stage_label: '首轮搜索',
          stage_kind: 'keyword',
          stage_main_keyword: '球墨铸铁井盖',
          stage_keyword_hit_rate: 0.75,
          is_placeholder: false,
          placeholder_reason: '',
          rank: 1,
          title: '球墨铸铁井盖重型',
          offer_url: 'https://detail.1688.com/offer/1.html',
          image_url: 'https://img.example.com/1.jpg',
          merchant_name: '有效商家',
          merchant_url: 'https://shop.1688.com/valid',
          wangwang_url: 'https://wangwang.example.com/1',
          offer_screenshot_url: 'https://img.example.com/1.png',
          contact_page_url: 'https://shop.1688.com/valid/contact',
          detected_contacts: [{ type: 'mobile', value: '17736998988' }],
          score: 75,
          is_match: true,
          reason: '标题包含井盖重型和采购主词，语义一致。',
          created_at: '2026-04-15T11:00:00.000Z',
          finished_at: '2026-04-15T11:00:00.000Z',
        }],
        error: null,
      },
      procurement_materials: {
        data: [{ id: 'mat-001', batch_id: 'BATCH-001', material_name: '球墨铸铁井盖' }],
        error: null,
      },
      standardized_results: {
        data: [{
          task_id: 'BATCH-001-ss-001',
          batch_id: 'BATCH-001',
          material_id: 'mat-001',
          standardized_name: '球墨铸铁井盖重型',
          primary_search_term: '球墨铸铁井盖',
        }],
        error: null,
      },
      search_rounds: {
        data: [{
          batch_id: 'BATCH-001',
          material_id: 'mat-001',
          stage_order: 1,
          stage_label: '首轮搜索',
          stage_kind: 'keyword',
          stage_main_keyword: '球墨铸铁井盖',
          keyword_hit_rate: 0.75,
          is_valid_search: true,
          stop_reason: '',
          contact_enrichment_skip_reason: '',
          created_at: '2026-04-15T10:59:00.000Z',
        }],
        error: null,
      },
    }) as unknown as ReturnType<typeof getSupabaseClient>);

    await expect(fetchSearchResults()).resolves.toEqual([
      expect.objectContaining({
        id: 'fr-001',
        task_id: 'BATCH-001-ss-001',
        material_id: 'mat-001',
        material_name: '球墨铸铁井盖',
        standardized_name: '球墨铸铁井盖重型',
        mobile: '17736998988',
        score: 75,
        is_match: true,
        reason: '标题包含井盖重型和采购主词，语义一致。',
        keyword_hit_rate: 0.75,
      }),
    ]);
  });

  it('picks the latest valid stage summary per batch material stage', async () => {
    vi.mocked(getSupabaseClient).mockReturnValue(createSupabaseMock({
      search_rounds: {
        data: [
          {
            task_id: 'BATCH-002-ss-001',
            batch_id: 'BATCH-002',
            material_id: 'mat-002',
            stage_order: 1,
            stage_label: '首轮搜索',
            stage_kind: 'keyword',
            stage_main_keyword: '热镀锌钢管',
            keyword_hit_rate: 0.25,
            is_valid_search: false,
            stop_reason: '',
            contact_enrichment_skip_reason: '',
            created_at: '2026-04-15T10:00:00.000Z',
          },
          {
            task_id: 'BATCH-002-ss-001',
            batch_id: 'BATCH-002',
            material_id: 'mat-002',
            stage_order: 1,
            stage_label: '首轮搜索',
            stage_kind: 'keyword',
            stage_main_keyword: '热镀锌钢管',
            keyword_hit_rate: 0.5,
            is_valid_search: true,
            stop_reason: '',
            contact_enrichment_skip_reason: '',
            created_at: '2026-04-15T10:05:00.000Z',
          },
        ],
        error: null,
      },
    }) as unknown as ReturnType<typeof getSupabaseClient>);

    await expect(fetchSearchStageSummaries()).resolves.toEqual([
      expect.objectContaining({
        batch_id: 'BATCH-002',
        task_id: 'BATCH-002-ss-001',
        material_id: 'mat-002',
        stage_order: 1,
        keyword_hit_rate: 0.5,
      }),
    ]);
  });

  it('uses persisted stage hit rate without recalculating from result scores', async () => {
    vi.mocked(getSupabaseClient).mockReturnValue(createSupabaseMock({
      search_rounds: {
        data: [
          {
            task_id: 'BATCH-HIT-ss-001',
            batch_id: 'BATCH-HIT',
            material_id: 'mat-hit',
            search_round: 1,
            stage_order: 1,
            stage_label: '关键词搜索',
            stage_kind: 'keyword',
            stage_main_keyword: '电磁阀',
            keyword_hit_rate: 0,
            results: [{ title: '气动电磁阀', score: 100 }],
            is_valid_search: true,
            stop_reason: '',
            contact_enrichment_skip_reason: '',
            created_at: '2026-04-24T08:00:00.000Z',
          },
          {
            task_id: 'BATCH-HIT-ss-001',
            batch_id: 'BATCH-HIT',
            material_id: 'mat-hit',
            search_round: 2,
            stage_order: 1,
            stage_label: '关键词搜索',
            stage_kind: 'keyword',
            stage_main_keyword: '电磁阀',
            keyword_hit_rate: 0,
            results: [{ title: '不相关商品', score: 0 }],
            is_valid_search: true,
            stop_reason: '',
            contact_enrichment_skip_reason: '',
            created_at: '2026-04-24T08:01:00.000Z',
          },
          {
            task_id: 'BATCH-HIT-ss-001',
            batch_id: 'BATCH-HIT',
            material_id: 'mat-hit',
            search_round: 3,
            stage_order: 1,
            stage_label: '关键词搜索',
            stage_kind: 'keyword',
            stage_main_keyword: '电磁阀',
            keyword_hit_rate: 0,
            results: [{ title: '重复轮次商品', score: 100 }],
            is_valid_search: false,
            stop_reason: 'duplicate_skip',
            contact_enrichment_skip_reason: '',
            created_at: '2026-04-24T08:02:00.000Z',
          },
        ],
        error: null,
      },
    }) as unknown as ReturnType<typeof getSupabaseClient>);

    await expect(fetchSearchStageSummaries()).resolves.toEqual([
      expect.objectContaining({
        batch_id: 'BATCH-HIT',
        material_id: 'mat-hit',
        keyword_hit_rate: 0,
      }),
    ]);
  });

  it('preserves persisted stage hit rate when rounds cannot be reliably recalculated', async () => {
    vi.mocked(getSupabaseClient).mockReturnValue(createSupabaseMock({
      search_rounds: {
        data: [
          {
            task_id: 'BATCH-FIXED-ss-001',
            batch_id: 'BATCH-FIXED',
            material_id: 'mat-fixed',
            search_round: 1,
            stage_order: 1,
            stage_label: '关键词搜索',
            stage_kind: 'keyword',
            stage_main_keyword: '岩棉板',
            keyword_hit_rate: 1,
            keyword_hit_rate_source: 'fixed_runtime',
            results: [{ title: '岩棉板保温板' }],
            is_valid_search: false,
            stop_reason: '',
            contact_enrichment_skip_reason: '',
            created_at: '2026-04-24T08:00:00.000Z',
          },
          {
            task_id: 'BATCH-FIXED-ss-001',
            batch_id: 'BATCH-FIXED',
            material_id: 'mat-fixed',
            search_round: 2,
            stage_order: 1,
            stage_label: '关键词搜索',
            stage_kind: 'keyword',
            stage_main_keyword: '岩棉板',
            keyword_hit_rate: 1,
            keyword_hit_rate_source: 'fixed_runtime',
            results: [{ title: '防火岩棉彩钢板' }],
            is_valid_search: false,
            stop_reason: '',
            contact_enrichment_skip_reason: '',
            created_at: '2026-04-24T08:01:00.000Z',
          },
        ],
        error: null,
      },
    }) as unknown as ReturnType<typeof getSupabaseClient>);

    await expect(fetchSearchStageSummaries()).resolves.toEqual([
      expect.objectContaining({
        batch_id: 'BATCH-FIXED',
        material_id: 'mat-fixed',
        keyword_hit_rate: 1,
      }),
    ]);
  });

  it('hides rejected no-phone merchants by default', async () => {
    vi.mocked(getSupabaseClient).mockReturnValue(createSupabaseMock({
      final_result_products: {
        data: [{
          id: 'fr-002',
          task_id: 'BATCH-003-ss-001',
          batch_id: 'BATCH-003',
          material_id: 'mat-003',
          main_keyword: '电线',
          stage_order: 1,
          stage_label: '首轮搜索',
          stage_kind: 'keyword',
          stage_main_keyword: '电线',
          stage_keyword_hit_rate: 0.4,
          is_placeholder: false,
          placeholder_reason: '',
          rank: 1,
          title: '无号码商家商品',
          offer_url: 'https://detail.1688.com/offer/2.html',
          image_url: 'https://img.example.com/2.jpg',
          merchant_name: '无号码商家',
          merchant_url: 'https://shop.1688.com/no-phone',
          wangwang_url: '',
          offer_screenshot_url: '',
          contact_page_url: '',
          detected_contacts: [],
          has_phone_contact: false,
          qualification_status: 'rejected_no_phone',
          contact_collection_reason: 'contact_navigation_failed',
          created_at: '2026-04-15T11:00:00.000Z',
          finished_at: '2026-04-15T11:00:00.000Z',
        }],
        error: null,
      },
      procurement_materials: {
        data: [{ id: 'mat-003', batch_id: 'BATCH-003', material_name: '电线' }],
        error: null,
      },
      standardized_results: {
        data: [{
          batch_id: 'BATCH-003',
          material_id: 'mat-003',
          standardized_name: '电线',
          primary_search_term: '电线',
        }],
        error: null,
      },
      search_rounds: {
        data: [],
        error: null,
      },
    }) as unknown as ReturnType<typeof getSupabaseClient>);

    await expect(fetchSearchResults()).resolves.toEqual([]);
    await expect(fetchSearchResults({ includeRejectedNoPhone: true })).resolves.toEqual([
      expect.objectContaining({
        id: 'fr-002',
        task_id: 'BATCH-003-ss-001',
        qualification_status: 'rejected_no_phone',
      }),
    ]);
  });

  it('backfills missing task_id for legacy search results from search_task_items timeline', async () => {
    vi.mocked(getSupabaseClient).mockReturnValue(createSupabaseMock({
      final_result_products: {
        data: [{
          id: 'legacy-fr-001',
          task_id: null,
          batch_id: 'BATCH-LEGACY',
          material_id: 'mat-legacy',
          main_keyword: '罗盘',
          stage_order: 1,
          stage_label: '首轮搜索',
          stage_kind: 'keyword',
          stage_main_keyword: '罗盘',
          stage_keyword_hit_rate: null,
          is_placeholder: false,
          placeholder_reason: '',
          rank: 1,
          title: '老数据结果',
          offer_url: 'https://detail.1688.com/offer/legacy.html',
          image_url: 'https://img.example.com/legacy.jpg',
          merchant_name: '老数据商家',
          merchant_url: 'https://shop.1688.com/legacy',
          wangwang_url: '',
          offer_screenshot_url: '',
          contact_page_url: '',
          detected_contacts: [{ type: 'mobile', value: '13800138000' }],
          created_at: '2026-04-22T08:09:19.000Z',
          finished_at: '2026-04-22T08:09:19.000Z',
        }],
        error: null,
      },
      procurement_materials: {
        data: [{ id: 'mat-legacy', batch_id: 'BATCH-LEGACY', material_name: '地质罗盘' }],
        error: null,
      },
      standardized_results: {
        data: [{
          batch_id: 'BATCH-LEGACY',
          material_id: 'mat-legacy',
          standardized_name: '地质罗盘',
          primary_search_term: '罗盘',
        }],
        error: null,
      },
      search_rounds: {
        data: [{
          task_id: null,
          batch_id: 'BATCH-LEGACY',
          material_id: 'mat-legacy',
          stage_order: 1,
          stage_label: '首轮搜索',
          stage_kind: 'keyword',
          stage_main_keyword: '罗盘',
          keyword_hit_rate: 0.6,
          is_valid_search: true,
          stop_reason: '',
          contact_enrichment_skip_reason: '',
          created_at: '2026-04-22T08:08:00.000Z',
        }],
        error: null,
      },
      search_task_items: {
        data: [
          {
            task_id: 'BATCH-LEGACY-ss-003',
            batch_id: 'BATCH-LEGACY',
            material_id: 'mat-legacy',
            created_at: '2026-04-22T08:00:08.000Z',
          },
          {
            task_id: 'BATCH-LEGACY-ss-002',
            batch_id: 'BATCH-LEGACY',
            material_id: 'mat-legacy',
            created_at: '2026-04-22T07:55:31.000Z',
          },
        ],
        error: null,
      },
    }) as unknown as ReturnType<typeof getSupabaseClient>);

    await expect(fetchSearchResults()).resolves.toEqual([
      expect.objectContaining({
        id: 'legacy-fr-001',
        task_id: 'BATCH-LEGACY-ss-003',
        keyword_hit_rate: 0.6,
      }),
    ]);
  });

  it('keeps stage summaries from different inferred tasks separate', async () => {
    vi.mocked(getSupabaseClient).mockReturnValue(createSupabaseMock({
      search_rounds: {
        data: [
          {
            task_id: null,
            batch_id: 'BATCH-MULTI',
            material_id: 'mat-multi',
            stage_order: 1,
            stage_label: '首轮搜索',
            stage_kind: 'keyword',
            stage_main_keyword: '轴承',
            keyword_hit_rate: 0.35,
            is_valid_search: true,
            stop_reason: '',
            contact_enrichment_skip_reason: '',
            created_at: '2026-04-22T07:05:00.000Z',
          },
          {
            task_id: null,
            batch_id: 'BATCH-MULTI',
            material_id: 'mat-multi',
            stage_order: 1,
            stage_label: '首轮搜索',
            stage_kind: 'keyword',
            stage_main_keyword: '轴承',
            keyword_hit_rate: 0.72,
            is_valid_search: true,
            stop_reason: '',
            contact_enrichment_skip_reason: '',
            created_at: '2026-04-22T08:05:00.000Z',
          },
        ],
        error: null,
      },
      search_task_items: {
        data: [
          {
            task_id: 'BATCH-MULTI-ss-001',
            batch_id: 'BATCH-MULTI',
            material_id: 'mat-multi',
            created_at: '2026-04-22T07:00:00.000Z',
          },
          {
            task_id: 'BATCH-MULTI-ss-002',
            batch_id: 'BATCH-MULTI',
            material_id: 'mat-multi',
            created_at: '2026-04-22T08:00:00.000Z',
          },
        ],
        error: null,
      },
    }) as unknown as ReturnType<typeof getSupabaseClient>);

    await expect(fetchSearchStageSummaries()).resolves.toEqual([
      expect.objectContaining({
        batch_id: 'BATCH-MULTI',
        task_id: 'BATCH-MULTI-ss-001',
        material_id: 'mat-multi',
        stage_order: 1,
        keyword_hit_rate: 0.35,
      }),
      expect.objectContaining({
        batch_id: 'BATCH-MULTI',
        task_id: 'BATCH-MULTI-ss-002',
        material_id: 'mat-multi',
        stage_order: 1,
        keyword_hit_rate: 0.72,
      }),
    ]);
  });
});
