import React, { useEffect } from 'react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import BlogWizardContainer from '@/features/blog/containers/BlogWizardContainer';

// Mocks for blogService
const publishBlogPostMock = vi.fn();
const updateBlogPostMock = vi.fn();
const fetchBlogTopicSuggestionsMock = vi.fn();
const newBlogMock = vi.fn();
const generateBlogPostMock = vi.fn();
vi.mock('@/features/blog/api/blogService', async () => {
  const mod = (await vi.importActual<typeof import('@/features/blog/api/blogService')>(
    '@/features/blog/api/blogService'
  )) as any;
  return {
    ...(mod as any),
    publishBlogPost: (...args: any[]) => publishBlogPostMock(...args),
    updateBlogPost: (...args: any[]) => updateBlogPostMock(...args),
    fetchBlogTopicSuggestions: (...args: any[]) => fetchBlogTopicSuggestionsMock(...args),
    newBlog: (...args: any[]) => newBlogMock(...args),
    generateBlogPost: (...args: any[]) => generateBlogPostMock(...args),
  };
});

// Mocks for fileService (not used in these tests but required by container callbacks shape)
const uploadBlogFileMock = vi.fn();
const generateBlogPostImageMock = vi.fn();
vi.mock('@/shared/api/fileService', () => ({
  uploadBlogFile: (...args: any[]) => uploadBlogFileMock(...args),
  generateBlogPostImage: (...args: any[]) => generateBlogPostImageMock(...args),
}));

// Mock BlogWizard presenter to invoke callbacks
vi.mock('@/features/blog/components/BlogWizard', () => ({
  default: (props: any) => {
    useEffect(() => {
      // no-op on mount
    }, []);
    return (
      <div>
        <button
          onClick={() => {
            const p = props.onPublish?.({
              blogId: 'b1',
              publishDate: '2025-01-01',
              publishToSocialMedia: true,
              socialMediaChannels: ['LinkedIn'],
              socialMediaLanguages: ['de'],
            });
            if (p && typeof p.catch === 'function') p.catch(() => {});
          }}
        >
          trigger-publish
        </button>
        <button onClick={() => props.onFetchSuggestions?.()}>trigger-suggest</button>
      </div>
    );
  }
}));

// Hoist-safe sonner mock
vi.mock('sonner', () => ({ toast: { success: vi.fn(), error: vi.fn() } }));
import { toast } from 'sonner';

beforeEach(() => {
  vi.restoreAllMocks();
  publishBlogPostMock.mockReset();
  updateBlogPostMock.mockReset();
  fetchBlogTopicSuggestionsMock.mockReset();
  newBlogMock.mockReset();
  generateBlogPostMock.mockReset();
  uploadBlogFileMock.mockReset();
  generateBlogPostImageMock.mockReset();
  (toast.success as any).mockReset?.();
  (toast.error as any).mockReset?.();
});

describe('BlogWizardContainer (integration)', () => {
  it('calls publish and shows success toast, then onComplete', async () => {
    publishBlogPostMock.mockResolvedValueOnce({ ok: true });

    const onComplete = vi.fn();
    render(<BlogWizardContainer onComplete={onComplete} />);

    // Click trigger to call onPublish
    await screen.findByText('trigger-publish');
    screen.getByText('trigger-publish').click();

    // success toast and onComplete should be called
    expect(publishBlogPostMock).toHaveBeenCalledTimes(1);
    await waitFor(() => expect((toast.success as any)).toHaveBeenCalledTimes(1));
    await waitFor(() => expect(onComplete).toHaveBeenCalledTimes(1));
  });

  it('handles publish error and shows error toast', async () => {
    publishBlogPostMock.mockRejectedValueOnce(new Error('fail'));

    render(<BlogWizardContainer onComplete={() => {}} />);

    await screen.findByText('trigger-publish');
    screen.getByText('trigger-publish').click();

    expect(publishBlogPostMock).toHaveBeenCalledTimes(1);
    await waitFor(() => expect((toast.error as any)).toHaveBeenCalledTimes(1));
  });
});
