/**
 * WorkflowList Tests
 *
 * Tests the workflow list component including:
 * - Basic rendering
 * - Search and filtering
 * - Sort functionality
 * - Filter persistence
 * - Empty states
 * - Loading/error states
 * - Delete workflow
 * - Callback invocations
 */
import { describe, it, expect, vi, beforeEach, afterEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import WorkflowList from './WorkflowList';
import { Workflow } from '../types/workflow';

// Mock workflowService
vi.mock('../services/workflows', () => ({
  workflowService: {
    deleteWorkflow: vi.fn(),
  },
}));

// Mock toast
vi.mock('../lib/toast', () => ({
  toast: {
    success: vi.fn(),
    error: vi.fn(),
    info: vi.fn(),
  },
}));

import { workflowService } from '../services/workflows';
import { toast } from '../lib/toast';

describe('WorkflowList', () => {
  const mockWorkflows: Workflow[] = [
    {
      id: 1,
      name: 'User Registration Workflow',
      description: 'Handles new user signups',
      status: 'active',
      trigger_type: 'wordpress/user_registration',
      draft_config: {
        trigger: { type: 'wordpress/user_registration', config: {} },
        actions: { 'action-1': { id: 'action-1', type: 'wordpress/send_email', config: {} } },
      },
      created_at: '2024-01-01T00:00:00Z',
      updated_at: '2024-01-15T10:30:00Z',
      published_version_id: null,
      last_published_at: null,
    },
    {
      id: 2,
      name: 'Post Published Notification',
      description: '',
      status: 'inactive',
      trigger_type: 'wordpress/post_published',
      draft_config: {
        trigger: { type: 'wordpress/post_published', config: {} },
        actions: { 'action-2': { id: 'action-2', type: 'slack/slack_message', config: {} } },
      },
      created_at: '2024-01-05T00:00:00Z',
      updated_at: '2024-01-10T08:00:00Z',
      published_version_id: null,
      last_published_at: null,
    },
    {
      id: 3,
      name: 'Comment Moderation',
      description: 'Auto-moderate comments',
      status: 'active',
      trigger_type: 'wordpress/comment_submitted',
      draft_config: {
        trigger: { type: 'wordpress/comment_submitted', config: {} },
        actions: { 'action-3': { id: 'action-3', type: 'wordpress/send_email', config: {} } },
      },
      created_at: '2024-01-08T00:00:00Z',
      updated_at: '2024-01-20T15:00:00Z',
      published_version_id: null,
      last_published_at: null,
    },
  ];

  const defaultProps = {
    workflows: mockWorkflows,
    loading: false,
    error: null,
    onEditWorkflow: vi.fn(),
    onCreateNew: vi.fn(),
    onRefresh: vi.fn(),
  };

  // Mock localStorage
  const localStorageMock = {
    getItem: vi.fn(),
    setItem: vi.fn(),
    removeItem: vi.fn(),
    clear: vi.fn(),
  };
  Object.defineProperty(window, 'localStorage', { value: localStorageMock });

  // Mock confirm
  const confirmMock = vi.fn();
  Object.defineProperty(window, 'confirm', { value: confirmMock, writable: true });

  beforeEach(() => {
    vi.clearAllMocks();
    localStorageMock.getItem.mockReturnValue(null);
    confirmMock.mockReturnValue(true);
    vi.useFakeTimers();
  });

  afterEach(() => {
    vi.useRealTimers();
  });

  // ==========================================================================
  // Basic Rendering Tests
  // ==========================================================================

  describe('basic rendering', () => {
    it('renders page title', () => {
      render(<WorkflowList {...defaultProps} />);

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

    it('renders workflow count summary', () => {
      render(<WorkflowList {...defaultProps} />);

      expect(screen.getByText(/2 of 3 workflows active/)).toBeInTheDocument();
    });

    it('renders create workflow button', () => {
      render(<WorkflowList {...defaultProps} />);

      expect(screen.getByText('Create Workflow')).toBeInTheDocument();
    });

    it('renders all workflows in table', () => {
      render(<WorkflowList {...defaultProps} />);

      expect(screen.getByText('User Registration Workflow')).toBeInTheDocument();
      expect(screen.getByText('Post Published Notification')).toBeInTheDocument();
      expect(screen.getByText('Comment Moderation')).toBeInTheDocument();
    });

    it('renders workflow descriptions when present', () => {
      render(<WorkflowList {...defaultProps} />);

      expect(screen.getByText('Handles new user signups')).toBeInTheDocument();
      expect(screen.getByText('Auto-moderate comments')).toBeInTheDocument();
    });

    it('renders status badges correctly', () => {
      render(<WorkflowList {...defaultProps} />);

      const activeBadges = screen.getAllByText('Active');
      const inactiveBadges = screen.getAllByText('Inactive');

      expect(activeBadges).toHaveLength(2);
      expect(inactiveBadges).toHaveLength(1);
    });
  });

  // ==========================================================================
  // Search Filtering Tests
  // ==========================================================================

  describe('search filtering', () => {
    it('filters workflows by name (case-insensitive)', () => {
      render(<WorkflowList {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText('Search workflows...');
      fireEvent.change(searchInput, { target: { value: 'user' } });

      expect(screen.getByText('User Registration Workflow')).toBeInTheDocument();
      expect(screen.queryByText('Post Published Notification')).not.toBeInTheDocument();
      expect(screen.queryByText('Comment Moderation')).not.toBeInTheDocument();
    });

    it('filters with partial match', () => {
      render(<WorkflowList {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText('Search workflows...');
      fireEvent.change(searchInput, { target: { value: 'mod' } });

      expect(screen.getByText('Comment Moderation')).toBeInTheDocument();
      expect(screen.queryByText('User Registration Workflow')).not.toBeInTheDocument();
    });

    it('shows search filter pill when searching', () => {
      render(<WorkflowList {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText('Search workflows...');
      fireEvent.change(searchInput, { target: { value: 'test' } });

      expect(screen.getByText(/Search: "test"/)).toBeInTheDocument();
    });

    it('clears search when X clicked on pill', () => {
      render(<WorkflowList {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText('Search workflows...');
      fireEvent.change(searchInput, { target: { value: 'test' } });

      // Click the X button on the search pill
      const clearButtons = screen.getAllByRole('button');
      const searchPillClear = clearButtons.find((btn) =>
        btn.parentElement?.textContent?.includes('Search:'),
      );
      if (searchPillClear) {
        fireEvent.click(searchPillClear);
      }

      expect(screen.queryByText(/Search: "test"/)).not.toBeInTheDocument();
    });
  });

  // ==========================================================================
  // Status Filtering Tests
  // ==========================================================================

  describe('status filtering', () => {
    it('shows all workflows by default', () => {
      render(<WorkflowList {...defaultProps} />);

      expect(screen.getByText('User Registration Workflow')).toBeInTheDocument();
      expect(screen.getByText('Post Published Notification')).toBeInTheDocument();
      expect(screen.getByText('Comment Moderation')).toBeInTheDocument();
    });

    it('renders status filter dropdown', () => {
      render(<WorkflowList {...defaultProps} />);

      expect(screen.getByText('All Status')).toBeInTheDocument();
    });
  });

  // ==========================================================================
  // Sort Functionality Tests
  // ==========================================================================

  describe('sort functionality', () => {
    it('renders sort dropdown with default "Most Recent"', () => {
      render(<WorkflowList {...defaultProps} />);

      expect(screen.getByText('Most Recent')).toBeInTheDocument();
    });

    it('sorts by most recent by default (updated_at descending)', () => {
      render(<WorkflowList {...defaultProps} />);

      const rows = screen.getAllByRole('row');
      // First row is header, so data starts at index 1
      // Comment Moderation was updated most recently (Jan 20)
      expect(rows[1]).toHaveTextContent('Comment Moderation');
    });
  });

  // ==========================================================================
  // Filter Persistence Tests
  // ==========================================================================

  describe('filter persistence', () => {
    it('loads persisted filters from localStorage', () => {
      localStorageMock.getItem.mockReturnValue(
        JSON.stringify({
          searchQuery: 'persisted search',
          statusFilter: 'active',
          triggerFilter: 'all',
          sortBy: 'name',
        }),
      );

      render(<WorkflowList {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText('Search workflows...');
      expect(searchInput).toHaveValue('persisted search');
    });

    it('saves filter state to localStorage with debounce', async () => {
      render(<WorkflowList {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText('Search workflows...');
      fireEvent.change(searchInput, { target: { value: 'new search' } });

      // Fast-forward past debounce timer
      vi.advanceTimersByTime(350);

      expect(localStorageMock.setItem).toHaveBeenCalledWith(
        'sequensy_workflow_filters',
        expect.stringContaining('new search'),
      );
    });

    it('handles localStorage parse errors gracefully', () => {
      localStorageMock.getItem.mockReturnValue('invalid json');

      // Should not throw
      expect(() => render(<WorkflowList {...defaultProps} />)).not.toThrow();
    });
  });

  // ==========================================================================
  // Empty States Tests
  // ==========================================================================

  describe('empty states', () => {
    it('shows empty state when no workflows exist', () => {
      render(<WorkflowList {...defaultProps} workflows={[]} />);

      expect(screen.getByText('No workflows yet')).toBeInTheDocument();
      expect(screen.getByText('Create Your First Workflow')).toBeInTheDocument();
    });

    it('shows no matches state when filter returns empty', () => {
      render(<WorkflowList {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText('Search workflows...');
      fireEvent.change(searchInput, { target: { value: 'nonexistent workflow xyz' } });

      expect(screen.getByText('No matching workflows')).toBeInTheDocument();
      expect(screen.getByText('Clear all filters')).toBeInTheDocument();
    });

    it('clears filters from no matches empty state', () => {
      render(<WorkflowList {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText('Search workflows...');
      fireEvent.change(searchInput, { target: { value: 'nonexistent' } });

      fireEvent.click(screen.getByText('Clear all filters'));

      // All workflows should be visible again
      expect(screen.getByText('User Registration Workflow')).toBeInTheDocument();
    });
  });

  // ==========================================================================
  // Loading State Tests
  // ==========================================================================

  describe('loading state', () => {
    it('shows skeleton loading state', () => {
      render(<WorkflowList {...defaultProps} loading={true} />);

      // Should show table headers but skeleton rows
      expect(screen.getAllByText('Workflow')[0]).toBeInTheDocument();
      expect(screen.queryByText('User Registration Workflow')).not.toBeInTheDocument();
    });
  });

  // ==========================================================================
  // Error State Tests
  // ==========================================================================

  describe('error state', () => {
    it('displays error message', () => {
      render(<WorkflowList {...defaultProps} error="Failed to load workflows" />);

      expect(screen.getByText('Error Loading Workflows')).toBeInTheDocument();
      expect(screen.getByText('Failed to load workflows')).toBeInTheDocument();
    });

    it('shows retry button on error', () => {
      render(<WorkflowList {...defaultProps} error="Network error" />);

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

    it('calls onRefresh when retry clicked', () => {
      render(<WorkflowList {...defaultProps} error="Network error" />);

      fireEvent.click(screen.getByText('Retry'));

      expect(defaultProps.onRefresh).toHaveBeenCalled();
    });
  });

  // ==========================================================================
  // Delete Workflow Tests
  // ==========================================================================

  describe('delete workflow', () => {
    it('shows confirmation dialog before delete', () => {
      render(<WorkflowList {...defaultProps} />);

      const deleteButtons = screen.getAllByRole('button').filter((btn) => {
        const svg = btn.querySelector('svg');
        return svg?.classList.contains('text-error');
      });

      fireEvent.click(deleteButtons[0]);

      expect(confirmMock).toHaveBeenCalledWith(
        'Are you sure you want to delete this workflow? This action cannot be undone.',
      );
    });

    it('does not delete if confirmation cancelled', () => {
      confirmMock.mockReturnValue(false);

      render(<WorkflowList {...defaultProps} />);

      const deleteButtons = screen.getAllByRole('button').filter((btn) => {
        const svg = btn.querySelector('svg');
        return svg?.classList.contains('text-error');
      });

      fireEvent.click(deleteButtons[0]);

      expect(workflowService.deleteWorkflow).not.toHaveBeenCalled();
    });

    it('calls delete service on confirmation', async () => {
      vi.useRealTimers(); // Use real timers for async test
      vi.mocked(workflowService.deleteWorkflow).mockResolvedValue(undefined);

      render(<WorkflowList {...defaultProps} />);

      const deleteButtons = screen.getAllByRole('button').filter((btn) => {
        const svg = btn.querySelector('svg');
        return svg?.classList.contains('text-error');
      });

      fireEvent.click(deleteButtons[0]);

      await waitFor(() => {
        expect(workflowService.deleteWorkflow).toHaveBeenCalled();
      });

      vi.useFakeTimers(); // Restore fake timers
    });

    it('shows success toast after delete', async () => {
      vi.useRealTimers();
      vi.mocked(workflowService.deleteWorkflow).mockResolvedValue(undefined);

      render(<WorkflowList {...defaultProps} />);

      const deleteButtons = screen.getAllByRole('button').filter((btn) => {
        const svg = btn.querySelector('svg');
        return svg?.classList.contains('text-error');
      });

      fireEvent.click(deleteButtons[0]);

      await waitFor(() => {
        expect(toast.success).toHaveBeenCalledWith('Workflow deleted', expect.any(Object));
      });

      vi.useFakeTimers();
    });

    it('shows error toast on delete failure', async () => {
      vi.useRealTimers();
      vi.mocked(workflowService.deleteWorkflow).mockRejectedValue(new Error('Delete failed'));

      render(<WorkflowList {...defaultProps} />);

      const deleteButtons = screen.getAllByRole('button').filter((btn) => {
        const svg = btn.querySelector('svg');
        return svg?.classList.contains('text-error');
      });

      fireEvent.click(deleteButtons[0]);

      await waitFor(() => {
        expect(toast.error).toHaveBeenCalledWith('Failed to delete workflow', expect.any(Object));
      });

      vi.useFakeTimers();
    });

    it('calls onRefresh after successful delete', async () => {
      vi.useRealTimers();
      vi.mocked(workflowService.deleteWorkflow).mockResolvedValue(undefined);

      render(<WorkflowList {...defaultProps} />);

      const deleteButtons = screen.getAllByRole('button').filter((btn) => {
        const svg = btn.querySelector('svg');
        return svg?.classList.contains('text-error');
      });

      fireEvent.click(deleteButtons[0]);

      await waitFor(() => {
        expect(defaultProps.onRefresh).toHaveBeenCalled();
      });

      vi.useFakeTimers();
    });
  });

  // ==========================================================================
  // Callback Tests
  // ==========================================================================

  describe('callbacks', () => {
    it('calls onCreateNew when create button clicked', () => {
      render(<WorkflowList {...defaultProps} />);

      fireEvent.click(screen.getByText('Create Workflow'));

      expect(defaultProps.onCreateNew).toHaveBeenCalled();
    });

    it('calls onEditWorkflow with workflow id when edit clicked', () => {
      render(<WorkflowList {...defaultProps} />);

      const editButtons = screen.getAllByRole('button').filter((btn) => {
        const svg = btn.querySelector('svg');
        return svg?.classList.contains('text-slate-500') && btn.closest('td');
      });

      fireEvent.click(editButtons[0]);

      expect(defaultProps.onEditWorkflow).toHaveBeenCalled();
    });

    it('calls onCreateNew from empty state button', () => {
      render(<WorkflowList {...defaultProps} workflows={[]} />);

      fireEvent.click(screen.getByText('Create Your First Workflow'));

      expect(defaultProps.onCreateNew).toHaveBeenCalled();
    });
  });

  // ==========================================================================
  // Result Count Tests
  // ==========================================================================

  describe('result count', () => {
    it('shows filtered result count when filters active', () => {
      render(<WorkflowList {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText('Search workflows...');
      fireEvent.change(searchInput, { target: { value: 'user' } });

      expect(screen.getByText(/Showing 1 of 3 workflows/)).toBeInTheDocument();
    });

    it('does not show result count when no filters', () => {
      render(<WorkflowList {...defaultProps} />);

      expect(screen.queryByText(/Showing \d+ of \d+ workflows/)).not.toBeInTheDocument();
    });
  });

  // ==========================================================================
  // Clear All Filters Tests
  // ==========================================================================

  describe('clear all filters', () => {
    it('shows clear all button when filters active', () => {
      render(<WorkflowList {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText('Search workflows...');
      fireEvent.change(searchInput, { target: { value: 'test' } });

      expect(screen.getByText('Clear all')).toBeInTheDocument();
    });

    it('clears all filters when clear all clicked', () => {
      render(<WorkflowList {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText('Search workflows...');
      fireEvent.change(searchInput, { target: { value: 'test' } });

      fireEvent.click(screen.getByText('Clear all'));

      expect(searchInput).toHaveValue('');
      expect(screen.queryByText('Filters:')).not.toBeInTheDocument();
    });
  });
});
