import { describe, it, expect, beforeEach, vi } from 'vitest';
import { useTemplateStore } from './templateStore';
import type { ModelTemplate } from '../types';

const STORAGE_KEY = 'safnaturel_templates';

const mockTemplate = (overrides: Partial<ModelTemplate> = {}): ModelTemplate => ({
  id: 1,
  name: 'Test Bileklik',
  jewelryType: 'bileklik',
  image: '/uploads/templates/test.jpg',
  ...overrides,
});

describe('templateStore', () => {
  beforeEach(() => {
    localStorage.clear();
    useTemplateStore.setState({ templates: [], loading: false, error: null });
  });

  describe('addTemplate', () => {
    it('adds a template to the store and localStorage', () => {
      const template = mockTemplate();
      useTemplateStore.getState().addTemplate(template);

      expect(useTemplateStore.getState().templates).toEqual([template]);
      expect(JSON.parse(localStorage.getItem(STORAGE_KEY)!)).toEqual([template]);
    });

    it('does not add duplicate templates', () => {
      const template = mockTemplate();
      useTemplateStore.getState().addTemplate(template);
      useTemplateStore.getState().addTemplate(template);

      expect(useTemplateStore.getState().templates).toHaveLength(1);
    });

    it('adds multiple different templates', () => {
      const t1 = mockTemplate({ id: 1, name: 'A' });
      const t2 = mockTemplate({ id: 2, name: 'B', jewelryType: 'kolye' });
      useTemplateStore.getState().addTemplate(t1);
      useTemplateStore.getState().addTemplate(t2);

      expect(useTemplateStore.getState().templates).toHaveLength(2);
      const stored = JSON.parse(localStorage.getItem(STORAGE_KEY)!);
      expect(stored).toHaveLength(2);
    });
  });

  describe('removeTemplate', () => {
    it('removes a template from the store and localStorage', () => {
      const t1 = mockTemplate({ id: 1 });
      const t2 = mockTemplate({ id: 2, name: 'B' });
      useTemplateStore.getState().addTemplate(t1);
      useTemplateStore.getState().addTemplate(t2);

      useTemplateStore.getState().removeTemplate(1);

      expect(useTemplateStore.getState().templates).toEqual([t2]);
      expect(JSON.parse(localStorage.getItem(STORAGE_KEY)!)).toEqual([t2]);
    });

    it('does nothing when removing non-existent id', () => {
      const template = mockTemplate();
      useTemplateStore.getState().addTemplate(template);
      useTemplateStore.getState().removeTemplate(999);

      expect(useTemplateStore.getState().templates).toHaveLength(1);
    });
  });

  describe('fetchTemplates', () => {
    it('fetches from API and saves to localStorage on success', async () => {
      const apiTemplates = [mockTemplate({ id: 10, name: 'API Template' })];
      global.fetch = vi.fn().mockResolvedValue({
        ok: true,
        json: () => Promise.resolve({ data: apiTemplates }),
      });

      await useTemplateStore.getState().fetchTemplates();

      expect(useTemplateStore.getState().templates).toEqual(apiTemplates);
      expect(useTemplateStore.getState().loading).toBe(false);
      expect(useTemplateStore.getState().error).toBeNull();
      expect(JSON.parse(localStorage.getItem(STORAGE_KEY)!)).toEqual(apiTemplates);
    });

    it('passes jewelryType as query param', async () => {
      global.fetch = vi.fn().mockResolvedValue({
        ok: true,
        json: () => Promise.resolve({ data: [] }),
      });

      await useTemplateStore.getState().fetchTemplates('kolye');

      expect(global.fetch).toHaveBeenCalledWith('/api/templates.php?type=kolye');
    });

    it('falls back to localStorage when API fails', async () => {
      const cached = [
        mockTemplate({ id: 1, jewelryType: 'bileklik' }),
        mockTemplate({ id: 2, jewelryType: 'kolye', name: 'Kolye' }),
      ];
      localStorage.setItem(STORAGE_KEY, JSON.stringify(cached));

      global.fetch = vi.fn().mockRejectedValue(new Error('Network error'));

      await useTemplateStore.getState().fetchTemplates();

      expect(useTemplateStore.getState().templates).toEqual(cached);
      expect(useTemplateStore.getState().error).toBeTruthy();
      expect(useTemplateStore.getState().loading).toBe(false);
    });

    it('filters localStorage fallback by jewelryType', async () => {
      const cached = [
        mockTemplate({ id: 1, jewelryType: 'bileklik' }),
        mockTemplate({ id: 2, jewelryType: 'kolye', name: 'Kolye' }),
      ];
      localStorage.setItem(STORAGE_KEY, JSON.stringify(cached));

      global.fetch = vi.fn().mockRejectedValue(new Error('fail'));

      await useTemplateStore.getState().fetchTemplates('kolye');

      expect(useTemplateStore.getState().templates).toHaveLength(1);
      expect(useTemplateStore.getState().templates[0].jewelryType).toBe('kolye');
    });

    it('sets loading to true during fetch', async () => {
      let resolvePromise: (value: unknown) => void;
      const pending = new Promise((resolve) => { resolvePromise = resolve; });

      global.fetch = vi.fn().mockReturnValue(pending);

      const fetchPromise = useTemplateStore.getState().fetchTemplates();
      expect(useTemplateStore.getState().loading).toBe(true);

      resolvePromise!({ ok: true, json: () => Promise.resolve({ data: [] }) });
      await fetchPromise;

      expect(useTemplateStore.getState().loading).toBe(false);
    });
  });
});
