import { describe, it, expect, beforeEach, vi } from 'vitest';
import { render, screen, fireEvent, waitFor, act } from '@testing-library/react';
import TemplateSelector from './TemplateSelector';
import { useDesignStore } from '../store/designStore';
import { useTemplateStore } from '../store/templateStore';
import type { ModelTemplate } from '../types';

const bileklikTemplates: ModelTemplate[] = [
  { id: 1, name: 'Yuvarlak Boncuk', jewelryType: 'bileklik', image: '/round.jpg' },
  { id: 2, name: 'Düz Boncuk', jewelryType: 'bileklik', image: '/flat.jpg' },
];

const kolyeTemplates: ModelTemplate[] = [
  { id: 3, name: 'İnci Kolye', jewelryType: 'kolye', image: '/pearl.jpg' },
];

function resetStores() {
  useDesignStore.setState({
    jewelryType: 'bileklik',
    selectedTemplate: null,
  });
  useTemplateStore.setState({
    templates: [],
    loading: false,
    error: null,
  });
}

/**
 * Creates a mock fetchTemplates that sets templates in the store
 * based on the requested jewelryType.
 */
function mockFetchTemplates(templateMap: Record<string, ModelTemplate[]>) {
  return vi.fn(async (jewelryType?: string) => {
    const templates = jewelryType ? (templateMap[jewelryType] ?? []) : Object.values(templateMap).flat();
    useTemplateStore.setState({ templates, loading: false, error: null });
  });
}

describe('TemplateSelector', () => {
  beforeEach(() => {
    localStorage.clear();
    resetStores();
  });

  it('shows loading state while fetching', () => {
    // Mock fetchTemplates to never resolve (keeps loading=true)
    useTemplateStore.setState({
      loading: true,
      fetchTemplates: vi.fn().mockReturnValue(new Promise(() => {})),
    });

    render(<TemplateSelector />);
    expect(screen.getByText('Şablonlar yükleniyor...')).toBeInTheDocument();
  });

  it('shows empty message when no templates available', () => {
    useTemplateStore.setState({
      templates: [],
      loading: false,
      fetchTemplates: vi.fn().mockResolvedValue(undefined),
    });

    render(<TemplateSelector />);
    expect(screen.getByText('Şablon bulunamadı')).toBeInTheDocument();
  });

  it('renders templates for current jewelryType', async () => {
    useTemplateStore.setState({
      fetchTemplates: mockFetchTemplates({ bileklik: bileklikTemplates, kolye: kolyeTemplates }),
    });

    render(<TemplateSelector />);

    await waitFor(() => {
      expect(screen.getByText('Yuvarlak Boncuk')).toBeInTheDocument();
      expect(screen.getByText('Düz Boncuk')).toBeInTheDocument();
    });
    expect(screen.queryByText('İnci Kolye')).not.toBeInTheDocument();
  });

  it('calls setTemplate when a template card is clicked', async () => {
    useTemplateStore.setState({
      fetchTemplates: mockFetchTemplates({ bileklik: bileklikTemplates }),
    });

    render(<TemplateSelector />);

    await waitFor(() => {
      expect(screen.getByText('Yuvarlak Boncuk')).toBeInTheDocument();
    });

    fireEvent.click(screen.getByText('Yuvarlak Boncuk'));
    expect(useDesignStore.getState().selectedTemplate).toEqual(bileklikTemplates[0]);
  });

  it('highlights the currently selected template', async () => {
    useDesignStore.setState({ selectedTemplate: bileklikTemplates[0] });
    useTemplateStore.setState({
      fetchTemplates: mockFetchTemplates({ bileklik: bileklikTemplates }),
    });

    render(<TemplateSelector />);

    await waitFor(() => {
      expect(screen.getByText('Yuvarlak Boncuk')).toBeInTheDocument();
    });

    const selectedBtn = screen.getByText('Yuvarlak Boncuk').closest('button');
    expect(selectedBtn?.className).toContain('ring-purple-400');

    const unselectedBtn = screen.getByText('Düz Boncuk').closest('button');
    expect(unselectedBtn?.className).not.toContain('ring-purple-400');
  });

  it('fetches templates when jewelryType changes', async () => {
    const mockFetch = mockFetchTemplates({ bileklik: bileklikTemplates, kolye: kolyeTemplates });
    useTemplateStore.setState({ fetchTemplates: mockFetch });

    const { rerender } = render(<TemplateSelector />);

    await waitFor(() => {
      expect(screen.getByText('Yuvarlak Boncuk')).toBeInTheDocument();
    });

    // Change type to kolye
    await act(async () => {
      useDesignStore.setState({ jewelryType: 'kolye', selectedTemplate: null });
    });
    rerender(<TemplateSelector />);

    await waitFor(() => {
      expect(screen.getByText('İnci Kolye')).toBeInTheDocument();
    });
    expect(screen.queryByText('Yuvarlak Boncuk')).not.toBeInTheDocument();
  });

  it('renders template images with correct alt text and src', async () => {
    useTemplateStore.setState({
      fetchTemplates: mockFetchTemplates({ bileklik: [bileklikTemplates[0]] }),
    });

    render(<TemplateSelector />);

    await waitFor(() => {
      const img = screen.getByAltText('Yuvarlak Boncuk');
      expect(img).toBeInTheDocument();
      expect(img.getAttribute('src')).toBe('/round.jpg');
    });
  });

  it('seeds sample templates to localStorage on mount', async () => {
    useTemplateStore.setState({
      fetchTemplates: vi.fn().mockResolvedValue(undefined),
    });

    render(<TemplateSelector />);

    await waitFor(() => {
      const stored = JSON.parse(localStorage.getItem('safnaturel_templates')!);
      expect(stored.length).toBe(4);
    });
  });
});
