import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { describe, it, expect, vi, beforeEach } from 'vitest';

import { useAutoSave } from '@/hooks/useAutoSave';
import { useQualityScore } from '@/hooks/useQualityScore';
import { trackProductEvent } from '@/lib/analytics';
import { CONTENT_EDITOR_OPENED } from '@/lib/event-catalog';

import ContentEditorEdit from './Edit';

vi.mocked(useAutoSave);
vi.mocked(useQualityScore);

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

// Mock axios
vi.mock('axios', () => ({
  default: {
    post: vi.fn().mockResolvedValue({ data: {} }),
    patch: vi.fn().mockResolvedValue({ data: {} }),
    isAxiosError: vi.fn(() => false),
  },
}));

// Mock Inertia
vi.mock('@inertiajs/react', async () => {
  const actual = await vi.importActual('@inertiajs/react');
  return {
    ...actual,
    Head: ({ title }: { title: string }) => <title>{title}</title>,
    Link: ({ children, href }: { children: React.ReactNode; href: string }) => (
      <a href={href}>{children}</a>
    ),
    usePage: vi.fn(() => ({
      props: {
        auth: { user: { name: 'Test User', email: 'test@example.com' } },
        features: { billing: false, notifications: false },
        sites: [],
        limits: null,
        ai_defaults: { model: 'gpt-4o-mini', temperature: 0.7 },
      },
    })),
    router: { reload: vi.fn() },
  };
});

// Mock DashboardLayout
vi.mock('@/Layouts/DashboardLayout', () => ({
  default: ({ children }: { children: React.ReactNode }) => (
    <div data-testid="dashboard-layout">{children}</div>
  ),
}));

// Mock SiteNav
vi.mock('@/Components/Navigation/SiteNav', () => ({
  default: () => <div data-testid="site-nav" />,
}));

// Mock TipTapEditor
vi.mock('@/Components/ContentEditor/TipTapEditor', () => {
  const { forwardRef } = require('react');
  return {
    default: forwardRef(
      (
        {
          value,
          onChange,
          placeholder,
        }: { value: string; onChange: (html: string) => void; placeholder: string },
        ref: unknown,
      ) => {
        const mockRef = ref as React.MutableRefObject<{
          getEditor: () => null;
          getHTML: () => string;
          setContent: () => void;
          focus: () => void;
          clear: () => void;
        }>;
        if (mockRef && typeof mockRef === 'object') {
          mockRef.current = {
            getEditor: () => null,
            getHTML: () => value,
            setContent: () => {},
            focus: () => {},
            clear: () => {},
          };
        }
        return (
          <div data-testid="tiptap-editor">
            <textarea
              value={value}
              onChange={(e) => onChange(e.target.value)}
              placeholder={placeholder}
            />
          </div>
        );
      },
    ),
  };
});

// Mock EditorToolbar
vi.mock('@/Components/ContentEditor/EditorToolbar', () => ({
  EditorToolbar: ({ editor }: { editor: unknown }) => (
    <div data-testid="editor-toolbar">Toolbar {editor ? 'with editor' : 'without editor'}</div>
  ),
}));

// Mock QualityScoreSidebar
vi.mock('@/Components/ContentEditor/QualityScoreSidebar', () => ({
  default: ({ metrics, isLoading }: { metrics: unknown; isLoading: boolean }) => (
    <div data-testid="quality-sidebar">
      {isLoading ? 'Loading metrics...' : metrics ? 'Metrics loaded' : 'No metrics'}
    </div>
  ),
}));

// Mock PublishDraftModal
vi.mock('@/Components/Ai/PublishDraftModal', () => ({
  default: ({ open, onOpenChange }: { open: boolean; onOpenChange: (open: boolean) => void }) =>
    open ? (
      <div data-testid="publish-modal">
        <button onClick={() => onOpenChange(false)}>Close</button>
      </div>
    ) : null,
}));

// Mock hooks
vi.mock('@/hooks/useAutoSave', () => ({
  useAutoSave: vi.fn(() => ({
    isSaving: false,
    hasUnsavedChanges: false,
    lastSavedAt: null,
    error: null,
    saveNow: vi.fn(),
  })),
}));

vi.mock('@/hooks/useQualityScore', () => ({
  useQualityScore: vi.fn(() => ({
    metrics: null,
    isLoading: false,
    error: null,
  })),
}));

vi.mock('@/hooks/useSerpAnalysis', () => ({
  useSerpAnalysis: vi.fn(() => ({
    analyze: vi.fn(),
    serpSnapshotId: null,
    status: 'idle',
    error: null,
    isAnalyzing: false,
    serpData: null,
  })),
}));

vi.mock('@/hooks/useContentScore', () => ({
  useContentScore: vi.fn(() => ({
    score: null,
    isLoading: false,
    error: null,
    terms: [],
  })),
}));

vi.mock('@/Components/ContentEditor/ContentScoreSidebar', () => ({
  default: () => <div data-testid="content-score-sidebar">Content Score</div>,
}));

vi.mock('@/Components/theme/use-theme', () => ({
  useTheme: vi.fn(() => ({ theme: 'system', setTheme: vi.fn(), resolvedTheme: 'light' })),
}));

const baseSite = { id: 1, name: 'Test Site', domain: 'https://test.com' };

const baseDraft = {
  id: 42,
  content: '<p>This is the original draft content.</p>',
  edited_content: null,
  token_usage: { prompt_tokens: 500, completion_tokens: 300 },
  created_at: '2026-01-15T12:00:00Z',
  ai_job: { id: 5, model: 'gpt-4o' },
  recommendation: {
    id: 10,
    page_url: 'https://test.com/blog/seo-guide',
    title: 'Update SEO Guide',
    action_type: 'content_rewrite',
    wp_post_content: '<p>Original blog post content here.</p>',
    wp_post_id: '123',
    wp_modified_at: '2026-01-10T10:00:00Z',
  },
};

describe('ContentEditor/Edit', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('page title', () => {
    it('renders page title with site name', () => {
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(document.querySelector('title')).toHaveTextContent('Test Site - Edit Draft');
    });
  });

  describe('navigation', () => {
    it('renders SiteNav component', () => {
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(screen.getByTestId('site-nav')).toBeInTheDocument();
    });

    it('renders back to recommendations link when draft has recommendation', () => {
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      const backLink = screen.getByRole('link', { name: /back to recommendations/i });
      expect(backLink).toBeInTheDocument();
    });

    it('does not render back to recommendations link when draft has no recommendation', () => {
      const draftWithoutRec = { ...baseDraft, recommendation: null };
      render(<ContentEditorEdit site={baseSite} draft={draftWithoutRec} />);

      const backLink = screen.queryByRole('link', { name: /back to recommendations/i });
      expect(backLink).not.toBeInTheDocument();
    });

    it('renders view draft link', () => {
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      const viewLink = screen.getByRole('link', { name: /view draft/i });
      expect(viewLink).toBeInTheDocument();
    });
  });

  describe('page header', () => {
    it('renders recommendation title as heading when available', () => {
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(
        screen.getByRole('heading', { name: 'Update SEO Guide', level: 1 }),
      ).toBeInTheDocument();
    });

    it('renders draft id as heading when no recommendation', () => {
      const draftWithoutRec = { ...baseDraft, recommendation: null };
      render(<ContentEditorEdit site={baseSite} draft={draftWithoutRec} />);

      expect(screen.getByRole('heading', { name: 'Edit Draft #42', level: 1 })).toBeInTheDocument();
    });

    it('renders page URL when recommendation available', () => {
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(screen.getByText('https://test.com/blog/seo-guide')).toBeInTheDocument();
    });
  });

  describe('editor components', () => {
    it('renders TipTap editor', () => {
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(screen.getByTestId('tiptap-editor')).toBeInTheDocument();
    });

    it('renders editor toolbar', () => {
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(screen.getByTestId('editor-toolbar')).toBeInTheDocument();
    });

    it('renders tabbed sidebar with content score and quality tabs', () => {
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(screen.getByRole('tab', { name: 'Score' })).toBeInTheDocument();
      expect(screen.getByRole('tab', { name: 'Quality' })).toBeInTheDocument();
    });

    it('initializes editor with edited_content when available', () => {
      const draftWithEdited = {
        ...baseDraft,
        edited_content: '<p>This is edited content.</p>',
      };
      render(<ContentEditorEdit site={baseSite} draft={draftWithEdited} />);

      const textarea = screen.getByPlaceholderText('Start editing your content...');
      expect(textarea).toHaveValue('<p>This is edited content.</p>');
    });

    it('initializes editor with original content when no edited_content', () => {
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      const textarea = screen.getByPlaceholderText('Start editing your content...');
      expect(textarea).toHaveValue('<p>This is the original draft content.</p>');
    });

    it('displays token usage info', () => {
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(screen.getByText(/800 tokens/)).toBeInTheDocument();
      expect(screen.getByText(/gpt-4o/)).toBeInTheDocument();
    });
  });

  describe('auto-save status', () => {
    beforeEach(() => {
      vi.mocked(useAutoSave).mockReturnValue({
        isSaving: false,
        hasUnsavedChanges: false,
        lastSavedAt: null,
        error: null,
        saveNow: vi.fn(),
      });
    });

    it('shows saving indicator when isSaving is true', () => {
      vi.mocked(useAutoSave).mockReturnValue({
        isSaving: true,
        hasUnsavedChanges: false,
        lastSavedAt: null,
        error: null,
        saveNow: vi.fn(),
      });

      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(screen.getByText('Saving...')).toBeInTheDocument();
    });

    it('shows unsaved changes indicator when hasUnsavedChanges is true', () => {
      vi.mocked(useAutoSave).mockReturnValue({
        isSaving: false,
        hasUnsavedChanges: true,
        lastSavedAt: null,
        error: null,
        saveNow: vi.fn(),
      });

      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(screen.getByText('Unsaved changes')).toBeInTheDocument();
    });

    it('shows saved indicator when content is saved', () => {
      const lastSaved = new Date(Date.now() - 30000); // 30 seconds ago
      vi.mocked(useAutoSave).mockReturnValue({
        isSaving: false,
        hasUnsavedChanges: false,
        lastSavedAt: lastSaved,
        error: null,
        saveNow: vi.fn(),
      });

      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(screen.getByText(/Saved/)).toBeInTheDocument();
    });

    it('shows save now button when there are unsaved changes', () => {
      vi.mocked(useAutoSave).mockReturnValue({
        isSaving: false,
        hasUnsavedChanges: true,
        lastSavedAt: null,
        error: null,
        saveNow: vi.fn(),
      });

      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(screen.getByRole('button', { name: /save now/i })).toBeInTheDocument();
    });

    it('calls saveNow when save now button is clicked', async () => {
      const saveNowMock = vi.fn();
      vi.mocked(useAutoSave).mockReturnValue({
        isSaving: false,
        hasUnsavedChanges: true,
        lastSavedAt: null,
        error: null,
        saveNow: saveNowMock,
      });

      const user = userEvent.setup();
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      const saveButton = screen.getByRole('button', { name: /save now/i });
      await user.click(saveButton);

      expect(saveNowMock).toHaveBeenCalledOnce();
    });
  });

  describe('publish functionality', () => {
    it('shows publish button when draft has wp_post_id', () => {
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(screen.getByRole('button', { name: /publish to wordpress/i })).toBeInTheDocument();
    });

    it('does not show publish button when draft has no wp_post_id', () => {
      const draftWithoutWpPostId = {
        ...baseDraft,
        recommendation: {
          ...baseDraft.recommendation!,
          wp_post_id: undefined,
        },
      };
      render(<ContentEditorEdit site={baseSite} draft={draftWithoutWpPostId} />);

      expect(
        screen.queryByRole('button', { name: /publish to wordpress/i }),
      ).not.toBeInTheDocument();
    });

    it('opens publish modal when publish button is clicked', async () => {
      const user = userEvent.setup();
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      const publishButton = screen.getByRole('button', { name: /publish to wordpress/i });
      await user.click(publishButton);

      await waitFor(() => {
        expect(screen.getByTestId('publish-modal')).toBeInTheDocument();
      });
    });

    it('closes publish modal when close is called', async () => {
      const user = userEvent.setup();
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      const publishButton = screen.getByRole('button', { name: /publish to wordpress/i });
      await user.click(publishButton);

      await waitFor(() => {
        expect(screen.getByTestId('publish-modal')).toBeInTheDocument();
      });

      const closeButton = screen.getByRole('button', { name: /close/i });
      await user.click(closeButton);

      await waitFor(() => {
        expect(screen.queryByTestId('publish-modal')).not.toBeInTheDocument();
      });
    });
  });

  describe('error handling', () => {
    it('displays save error when save fails', () => {
      vi.mocked(useAutoSave).mockReturnValue({
        isSaving: false,
        hasUnsavedChanges: false,
        lastSavedAt: null,
        error: 'Failed to save content',
        saveNow: vi.fn(),
      });

      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(screen.getByText(/save failed/i)).toBeInTheDocument();
      expect(screen.getByText('Failed to save content')).toBeInTheDocument();
    });

    it('displays metrics error when quality analysis fails', () => {
      vi.mocked(useQualityScore).mockReturnValue({
        metrics: null,
        isLoading: false,
        error: 'Failed to analyze content',
      });

      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(screen.getByText(/quality analysis failed/i)).toBeInTheDocument();
      expect(screen.getByText('Failed to analyze content')).toBeInTheDocument();
    });
  });

  describe('layout', () => {
    it('has layout property defined', () => {
      expect(ContentEditorEdit.layout).toBeDefined();
    });

    it('renders editor and sidebar in grid layout', () => {
      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      expect(screen.getByTestId('tiptap-editor')).toBeInTheDocument();
      expect(screen.getByTestId('content-score-sidebar')).toBeInTheDocument();
    });
  });

  describe('analytics tracking', () => {
    it('fires CONTENT_EDITOR_OPENED on mount with site_id and draft_id', async () => {
      vi.mocked(trackProductEvent).mockClear();

      render(<ContentEditorEdit site={baseSite} draft={baseDraft} />);

      await waitFor(() =>
        expect(vi.mocked(trackProductEvent)).toHaveBeenCalledWith(
          CONTENT_EDITOR_OPENED,
          { site_id: '1', draft_id: 42 },
        ),
      );
    });
  });
});
