/**
 * Tests for CatalogListPanel Component
 *
 * TDD: Tests for the sidebar catalog list with search and filtering.
 */

import React from 'react';
import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, within } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { CatalogListPanel, type CatalogItem } from '../CatalogListPanel';

// Sample plan data
const mockPlans: CatalogItem[] = [
  {
    id: 1,
    type: 'plan',
    code: 'free',
    name: 'Free',
    isActive: true,
    isPublic: true,
    isLegacy: false,
    priceMonthly: 0,
    priceYearly: 0,
    subscriberCount: 50,
  },
  {
    id: 2,
    type: 'plan',
    code: 'starter',
    name: 'Starter',
    isActive: true,
    isPublic: true,
    isLegacy: false,
    priceMonthly: 2900,
    priceYearly: 29000,
    subscriberCount: 25,
  },
  {
    id: 3,
    type: 'plan',
    code: 'pro',
    name: 'Professional',
    isActive: true,
    isPublic: true,
    isLegacy: false,
    priceMonthly: 7900,
    priceYearly: 79000,
    subscriberCount: 10,
  },
  {
    id: 4,
    type: 'plan',
    code: 'enterprise',
    name: 'Enterprise',
    isActive: true,
    isPublic: false, // Hidden plan
    isLegacy: false,
    priceMonthly: 19900,
    priceYearly: 199000,
    subscriberCount: 3,
  },
  {
    id: 5,
    type: 'plan',
    code: 'legacy_pro',
    name: 'Pro (Legacy)',
    isActive: false, // Inactive
    isPublic: false,
    isLegacy: true,
    priceMonthly: 4900,
    priceYearly: 49000,
    subscriberCount: 15,
  },
];

// Sample add-on data
const mockAddons: CatalogItem[] = [
  {
    id: 101,
    type: 'addon',
    code: 'sms_pack',
    name: 'SMS Credits Pack',
    isActive: true,
    isPublic: true,
    isLegacy: false,
    priceMonthly: 500,
  },
  {
    id: 102,
    type: 'addon',
    code: 'api_access',
    name: 'API Access',
    isActive: true,
    isPublic: true,
    isLegacy: false,
    priceMonthly: 2000,
  },
  {
    id: 103,
    type: 'addon',
    code: 'old_addon',
    name: 'Deprecated Add-on',
    isActive: false,
    isPublic: false,
    isLegacy: true,
    priceMonthly: 1000,
  },
];

const allItems = [...mockPlans, ...mockAddons];

describe('CatalogListPanel', () => {
  const defaultProps = {
    items: allItems,
    selectedId: null,
    onSelect: vi.fn(),
    onCreatePlan: vi.fn(),
    onCreateAddon: vi.fn(),
  };

  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe('Rendering', () => {
    it('renders all items by default', () => {
      render(<CatalogListPanel {...defaultProps} />);

      // Should show all plans
      expect(screen.getByText('Free')).toBeInTheDocument();
      expect(screen.getByText('Starter')).toBeInTheDocument();
      expect(screen.getByText('Professional')).toBeInTheDocument();
      expect(screen.getByText('Enterprise')).toBeInTheDocument();

      // Should show all addons
      expect(screen.getByText('SMS Credits Pack')).toBeInTheDocument();
      expect(screen.getByText('API Access')).toBeInTheDocument();
    });

    it('shows item code as badge', () => {
      render(<CatalogListPanel {...defaultProps} />);

      expect(screen.getByText('free')).toBeInTheDocument();
      expect(screen.getByText('starter')).toBeInTheDocument();
      expect(screen.getByText('sms_pack')).toBeInTheDocument();
    });

    it('shows price for items', () => {
      render(<CatalogListPanel {...defaultProps} />);

      // Free plan shows "Free/mo" - use getAllByText since "free" appears multiple times
      const freeElements = screen.getAllByText(/free/i);
      expect(freeElements.length).toBeGreaterThan(0);

      // Starter plan shows $29.00/mo
      expect(screen.getByText(/\$29/)).toBeInTheDocument();
    });

    it('shows type badges for plans and add-ons', () => {
      render(<CatalogListPanel {...defaultProps} />);

      // Should have Base Plan badges for plans
      const baseBadges = screen.getAllByText(/base/i);
      expect(baseBadges.length).toBeGreaterThan(0);

      // Should have Add-on badges
      const addonBadges = screen.getAllByText(/add-on/i);
      expect(addonBadges.length).toBeGreaterThan(0);
    });

    it('shows status badges for inactive items', () => {
      render(<CatalogListPanel {...defaultProps} />);

      // Legacy plan should show inactive badge
      const inactiveBadges = screen.getAllByText(/inactive/i);
      expect(inactiveBadges.length).toBeGreaterThan(0);
    });

    it('shows legacy badge for legacy items', () => {
      render(<CatalogListPanel {...defaultProps} />);

      const legacyBadges = screen.getAllByText(/legacy/i);
      expect(legacyBadges.length).toBeGreaterThan(0);
    });

    it('shows hidden badge for non-public items', () => {
      render(<CatalogListPanel {...defaultProps} />);

      const hiddenBadges = screen.getAllByText(/hidden/i);
      expect(hiddenBadges.length).toBeGreaterThan(0);
    });
  });

  describe('Type Filtering', () => {
    it('filters to show only base plans', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      // Click the "Base Plans" filter
      const typeFilter = screen.getByRole('combobox', { name: /type/i });
      await user.selectOptions(typeFilter, 'plan');

      // Should show plans
      expect(screen.getByText('Free')).toBeInTheDocument();
      expect(screen.getByText('Starter')).toBeInTheDocument();

      // Should NOT show addons
      expect(screen.queryByText('SMS Credits Pack')).not.toBeInTheDocument();
    });

    it('filters to show only add-ons', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      const typeFilter = screen.getByRole('combobox', { name: /type/i });
      await user.selectOptions(typeFilter, 'addon');

      // Should show addons
      expect(screen.getByText('SMS Credits Pack')).toBeInTheDocument();
      expect(screen.getByText('API Access')).toBeInTheDocument();

      // Should NOT show plans
      expect(screen.queryByText('Free')).not.toBeInTheDocument();
      expect(screen.queryByText('Starter')).not.toBeInTheDocument();
    });

    it('shows all types when "All" is selected', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      // First filter to plans only
      const typeFilter = screen.getByRole('combobox', { name: /type/i });
      await user.selectOptions(typeFilter, 'plan');

      // Then select "All"
      await user.selectOptions(typeFilter, 'all');

      // Should show both
      expect(screen.getByText('Free')).toBeInTheDocument();
      expect(screen.getByText('SMS Credits Pack')).toBeInTheDocument();
    });
  });

  describe('Status Filtering', () => {
    it('filters to show only active items', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      const statusFilter = screen.getByRole('combobox', { name: /status/i });
      await user.selectOptions(statusFilter, 'active');

      // Should show active items
      expect(screen.getByText('Free')).toBeInTheDocument();
      expect(screen.getByText('Starter')).toBeInTheDocument();

      // Should NOT show inactive items
      expect(screen.queryByText('Pro (Legacy)')).not.toBeInTheDocument();
      expect(screen.queryByText('Deprecated Add-on')).not.toBeInTheDocument();
    });

    it('filters to show only inactive items', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      const statusFilter = screen.getByRole('combobox', { name: /status/i });
      await user.selectOptions(statusFilter, 'inactive');

      // Should show inactive items
      expect(screen.getByText('Pro (Legacy)')).toBeInTheDocument();
      expect(screen.getByText('Deprecated Add-on')).toBeInTheDocument();

      // Should NOT show active items
      expect(screen.queryByText('Free')).not.toBeInTheDocument();
    });
  });

  describe('Visibility Filtering', () => {
    it('filters to show only public items', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      const visibilityFilter = screen.getByRole('combobox', { name: /visibility/i });
      await user.selectOptions(visibilityFilter, 'public');

      // Should show public items
      expect(screen.getByText('Free')).toBeInTheDocument();
      expect(screen.getByText('Starter')).toBeInTheDocument();

      // Should NOT show hidden items
      expect(screen.queryByText('Enterprise')).not.toBeInTheDocument();
    });

    it('filters to show only hidden items', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      const visibilityFilter = screen.getByRole('combobox', { name: /visibility/i });
      await user.selectOptions(visibilityFilter, 'hidden');

      // Should show hidden items
      expect(screen.getByText('Enterprise')).toBeInTheDocument();

      // Should NOT show public items
      expect(screen.queryByText('Starter')).not.toBeInTheDocument();
    });
  });

  describe('Legacy Filtering', () => {
    it('filters to show only current (non-legacy) items', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      const legacyFilter = screen.getByRole('combobox', { name: /legacy/i });
      await user.selectOptions(legacyFilter, 'current');

      // Should show current items
      expect(screen.getByText('Free')).toBeInTheDocument();

      // Should NOT show legacy items
      expect(screen.queryByText('Pro (Legacy)')).not.toBeInTheDocument();
    });

    it('filters to show only legacy items', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      const legacyFilter = screen.getByRole('combobox', { name: /legacy/i });
      await user.selectOptions(legacyFilter, 'legacy');

      // Should show legacy items
      expect(screen.getByText('Pro (Legacy)')).toBeInTheDocument();

      // Should NOT show current items
      expect(screen.queryByText('Free')).not.toBeInTheDocument();
    });
  });

  describe('Search Functionality', () => {
    it('filters items by name when searching', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText(/search/i);
      await user.type(searchInput, 'starter');

      // Should show Starter plan
      expect(screen.getByText('Starter')).toBeInTheDocument();

      // Should NOT show other items
      expect(screen.queryByText('Free')).not.toBeInTheDocument();
      expect(screen.queryByText('Professional')).not.toBeInTheDocument();
    });

    it('filters items by code when searching', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText(/search/i);
      await user.type(searchInput, 'sms_pack');

      // Should show SMS Credits Pack
      expect(screen.getByText('SMS Credits Pack')).toBeInTheDocument();

      // Should NOT show other items
      expect(screen.queryByText('Free')).not.toBeInTheDocument();
    });

    it('shows no results message when search has no matches', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText(/search/i);
      await user.type(searchInput, 'nonexistent');

      expect(screen.getByText(/no items found/i)).toBeInTheDocument();
    });

    it('search is case-insensitive', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      const searchInput = screen.getByPlaceholderText(/search/i);
      await user.type(searchInput, 'STARTER');

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

  describe('Selection', () => {
    it('calls onSelect when an item is clicked', async () => {
      const onSelect = vi.fn();
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} onSelect={onSelect} />);

      const starterItem = screen.getByText('Starter').closest('button');
      await user.click(starterItem!);

      expect(onSelect).toHaveBeenCalledWith(expect.objectContaining({
        id: 2,
        code: 'starter',
      }));
    });

    it('highlights the selected item', () => {
      render(<CatalogListPanel {...defaultProps} selectedId={2} />);

      // The selected item should have a different style
      const starterItem = screen.getByText('Starter').closest('button');
      expect(starterItem).toHaveClass('bg-blue-50');
    });
  });

  describe('Create Actions', () => {
    it('calls onCreatePlan when "Create Plan" is clicked', async () => {
      const onCreatePlan = vi.fn();
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} onCreatePlan={onCreatePlan} />);

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

      expect(onCreatePlan).toHaveBeenCalled();
    });

    it('calls onCreateAddon when "Create Add-on" is clicked', async () => {
      const onCreateAddon = vi.fn();
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} onCreateAddon={onCreateAddon} />);

      const createAddonButton = screen.getByRole('button', { name: /create add-on/i });
      await user.click(createAddonButton);

      expect(onCreateAddon).toHaveBeenCalled();
    });
  });

  describe('Combined Filters', () => {
    it('combines type and status filters', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      // Filter to inactive plans only
      const typeFilter = screen.getByRole('combobox', { name: /type/i });
      const statusFilter = screen.getByRole('combobox', { name: /status/i });

      await user.selectOptions(typeFilter, 'plan');
      await user.selectOptions(statusFilter, 'inactive');

      // Should only show inactive plans
      expect(screen.getByText('Pro (Legacy)')).toBeInTheDocument();

      // Should NOT show active plans or addons
      expect(screen.queryByText('Free')).not.toBeInTheDocument();
      expect(screen.queryByText('Deprecated Add-on')).not.toBeInTheDocument();
    });

    it('combines search with filters', async () => {
      const user = userEvent.setup();
      render(<CatalogListPanel {...defaultProps} />);

      // Filter to plans and search for "pro"
      const typeFilter = screen.getByRole('combobox', { name: /type/i });
      await user.selectOptions(typeFilter, 'plan');

      const searchInput = screen.getByPlaceholderText(/search/i);
      await user.type(searchInput, 'pro');

      // Should show Professional and Pro (Legacy)
      expect(screen.getByText('Professional')).toBeInTheDocument();
      expect(screen.getByText('Pro (Legacy)')).toBeInTheDocument();

      // Should NOT show other items
      expect(screen.queryByText('Free')).not.toBeInTheDocument();
    });
  });
});
