/**
 * Unit tests for UpgradePrompt, LockedSection, and LockedButton components
 *
 * Tests upgrade prompts that appear when features are not available in the current plan.
 * Covers:
 * - Different variants (inline, banner, overlay)
 * - Different sizes (sm, md, lg)
 * - Feature names and descriptions
 * - Navigation to billing page
 * - LockedSection wrapper behavior
 * - LockedButton disabled state and tooltip
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent, within } from '@testing-library/react';
import { BrowserRouter } from 'react-router-dom';
import {
  UpgradePrompt,
  LockedSection,
  LockedButton,
} from '../UpgradePrompt';
import { FeatureKey } from '../../hooks/usePlanFeatures';

// Mock react-router-dom's Link component
vi.mock('react-router-dom', async () => {
  const actual = await vi.importActual('react-router-dom');
  return {
    ...actual,
    Link: ({ to, children, className, ...props }: any) => (
      <a href={to} className={className} {...props}>
        {children}
      </a>
    ),
  };
});

// Wrapper component that provides router context
const renderWithRouter = (ui: React.ReactElement) => {
  return render(<BrowserRouter>{ui}</BrowserRouter>);
};

describe('UpgradePrompt', () => {
  describe('Inline Variant', () => {
    it('should render inline upgrade prompt with lock icon', () => {
      renderWithRouter(<UpgradePrompt feature="sms_reminders" variant="inline" />);

      expect(screen.getByText('Upgrade Required')).toBeInTheDocument();
      // Check for styling classes
      const container = screen.getByText('Upgrade Required').parentElement;
      expect(container).toHaveClass('bg-amber-50', 'text-amber-700');
    });

    it('should render small badge style for inline variant', () => {
      const { container } = renderWithRouter(
        <UpgradePrompt feature="webhooks" variant="inline" />
      );

      const badge = container.querySelector('.bg-amber-50');
      expect(badge).toBeInTheDocument();
      expect(badge).toHaveClass('text-xs', 'rounded-md');
    });

    it('should not show description or upgrade button in inline variant', () => {
      renderWithRouter(<UpgradePrompt feature="api_access" variant="inline" />);

      expect(screen.queryByText(/integrate with external/i)).not.toBeInTheDocument();
      expect(screen.queryByRole('link', { name: /upgrade your plan/i })).not.toBeInTheDocument();
    });

    it('should render for any feature in inline mode', () => {
      const features: FeatureKey[] = ['plugins', 'custom_domain', 'white_label'];

      features.forEach((feature) => {
        const { unmount } = renderWithRouter(
          <UpgradePrompt feature={feature} variant="inline" />
        );
        expect(screen.getByText('Upgrade Required')).toBeInTheDocument();
        unmount();
      });
    });
  });

  describe('Banner Variant', () => {
    it('should render banner with feature name and crown icon', () => {
      renderWithRouter(<UpgradePrompt feature="sms_reminders" variant="banner" />);

      expect(screen.getByText(/sms reminders.*upgrade required/i)).toBeInTheDocument();
    });

    it('should render feature description by default', () => {
      renderWithRouter(<UpgradePrompt feature="sms_reminders" variant="banner" />);

      expect(
        screen.getByText(/send automated sms reminders to customers and staff/i)
      ).toBeInTheDocument();
    });

    it('should hide description when showDescription is false', () => {
      renderWithRouter(
        <UpgradePrompt
          feature="sms_reminders"
          variant="banner"
          showDescription={false}
        />
      );

      expect(
        screen.queryByText(/send automated sms reminders/i)
      ).not.toBeInTheDocument();
    });

    it('should render upgrade button linking to billing settings', () => {
      renderWithRouter(<UpgradePrompt feature="webhooks" variant="banner" />);

      const upgradeLink = screen.getByRole('link', { name: /upgrade your plan/i });
      expect(upgradeLink).toBeInTheDocument();
      expect(upgradeLink).toHaveAttribute('href', '/settings/billing');
    });

    it('should have gradient styling for banner variant', () => {
      const { container } = renderWithRouter(
        <UpgradePrompt feature="api_access" variant="banner" />
      );

      const banner = container.querySelector('.bg-gradient-to-br.from-amber-50');
      expect(banner).toBeInTheDocument();
      expect(banner).toHaveClass('border-2', 'border-amber-300');
    });

    it('should render crown icon in banner', () => {
      renderWithRouter(<UpgradePrompt feature="custom_domain" variant="banner" />);

      // Crown icon should be in the button text
      const upgradeButton = screen.getByRole('link', { name: /upgrade your plan/i });
      expect(upgradeButton).toBeInTheDocument();
    });

    it('should render all feature names correctly', () => {
      const features: FeatureKey[] = [
        'webhooks',
        'api_access',
        'custom_domain',
        'white_label',
        'plugins',
      ];

      features.forEach((feature) => {
        const { unmount } = renderWithRouter(
          <UpgradePrompt feature={feature} variant="banner" />
        );
        // Feature name should be in the heading
        expect(screen.getByRole('heading', { level: 3 })).toBeInTheDocument();
        unmount();
      });
    });
  });

  describe('Overlay Variant', () => {
    it('should render overlay with blurred children', () => {
      renderWithRouter(
        <UpgradePrompt feature="sms_reminders" variant="overlay">
          <div data-testid="locked-content">Locked Content</div>
        </UpgradePrompt>
      );

      const lockedContent = screen.getByTestId('locked-content');
      expect(lockedContent).toBeInTheDocument();

      // Check that parent has blur styling
      const parent = lockedContent.parentElement;
      expect(parent).toHaveClass('blur-sm', 'opacity-50');
    });

    it('should render feature name and description in overlay', () => {
      renderWithRouter(
        <UpgradePrompt feature="webhooks" variant="overlay">
          <div>Content</div>
        </UpgradePrompt>
      );

      expect(screen.getByText('Webhooks')).toBeInTheDocument();
      expect(
        screen.getByText(/integrate with external services using webhooks/i)
      ).toBeInTheDocument();
    });

    it('should render lock icon in overlay', () => {
      const { container } = renderWithRouter(
        <UpgradePrompt feature="api_access" variant="overlay">
          <div>Content</div>
        </UpgradePrompt>
      );

      // Lock icon should be in a rounded circle
      const iconCircle = container.querySelector('.rounded-full.bg-gradient-to-br');
      expect(iconCircle).toBeInTheDocument();
    });

    it('should render upgrade button in overlay', () => {
      renderWithRouter(
        <UpgradePrompt feature="custom_domain" variant="overlay">
          <div>Content</div>
        </UpgradePrompt>
      );

      const upgradeLink = screen.getByRole('link', { name: /upgrade your plan/i });
      expect(upgradeLink).toBeInTheDocument();
      expect(upgradeLink).toHaveAttribute('href', '/settings/billing');
    });

    it('should apply small size styling', () => {
      const { container } = renderWithRouter(
        <UpgradePrompt feature="plugins" variant="overlay" size="sm">
          <div>Content</div>
        </UpgradePrompt>
      );

      const overlayContent = container.querySelector('.p-4');
      expect(overlayContent).toBeInTheDocument();
    });

    it('should apply medium size styling by default', () => {
      const { container } = renderWithRouter(
        <UpgradePrompt feature="plugins" variant="overlay">
          <div>Content</div>
        </UpgradePrompt>
      );

      const overlayContent = container.querySelector('.p-6');
      expect(overlayContent).toBeInTheDocument();
    });

    it('should apply large size styling', () => {
      const { container } = renderWithRouter(
        <UpgradePrompt feature="plugins" variant="overlay" size="lg">
          <div>Content</div>
        </UpgradePrompt>
      );

      const overlayContent = container.querySelector('.p-8');
      expect(overlayContent).toBeInTheDocument();
    });

    it('should make children non-interactive', () => {
      renderWithRouter(
        <UpgradePrompt feature="white_label" variant="overlay">
          <button data-testid="locked-button">Click Me</button>
        </UpgradePrompt>
      );

      const button = screen.getByTestId('locked-button');
      const parent = button.parentElement;
      expect(parent).toHaveClass('pointer-events-none');
    });
  });

  describe('Default Behavior', () => {
    it('should default to banner variant when no variant specified', () => {
      renderWithRouter(<UpgradePrompt feature="sms_reminders" />);

      // Banner should show feature name in heading
      expect(screen.getByRole('heading', { level: 3 })).toBeInTheDocument();
      expect(screen.getByText(/sms reminders.*upgrade required/i)).toBeInTheDocument();
    });

    it('should show description by default', () => {
      renderWithRouter(<UpgradePrompt feature="webhooks" />);

      expect(
        screen.getByText(/integrate with external services/i)
      ).toBeInTheDocument();
    });

    it('should use medium size by default', () => {
      const { container } = renderWithRouter(
        <UpgradePrompt feature="plugins" variant="overlay">
          <div>Content</div>
        </UpgradePrompt>
      );

      const overlayContent = container.querySelector('.p-6');
      expect(overlayContent).toBeInTheDocument();
    });
  });
});

describe('LockedSection', () => {
  describe('Unlocked State', () => {
    it('should render children when not locked', () => {
      renderWithRouter(
        <LockedSection feature="sms_reminders" isLocked={false}>
          <div data-testid="content">Available Content</div>
        </LockedSection>
      );

      expect(screen.getByTestId('content')).toBeInTheDocument();
      expect(screen.getByText('Available Content')).toBeInTheDocument();
    });

    it('should not show upgrade prompt when unlocked', () => {
      renderWithRouter(
        <LockedSection feature="webhooks" isLocked={false}>
          <div>Content</div>
        </LockedSection>
      );

      expect(screen.queryByText(/upgrade required/i)).not.toBeInTheDocument();
      expect(screen.queryByRole('link', { name: /upgrade your plan/i })).not.toBeInTheDocument();
    });
  });

  describe('Locked State', () => {
    it('should show banner prompt by default when locked', () => {
      renderWithRouter(
        <LockedSection feature="sms_reminders" isLocked={true}>
          <div>Content</div>
        </LockedSection>
      );

      expect(screen.getByText(/sms reminders.*upgrade required/i)).toBeInTheDocument();
    });

    it('should show overlay prompt when variant is overlay', () => {
      renderWithRouter(
        <LockedSection feature="api_access" isLocked={true} variant="overlay">
          <div data-testid="locked-content">Locked Content</div>
        </LockedSection>
      );

      expect(screen.getByTestId('locked-content')).toBeInTheDocument();
      expect(screen.getByText('API Access')).toBeInTheDocument();
    });

    it('should show fallback content instead of upgrade prompt when provided', () => {
      renderWithRouter(
        <LockedSection
          feature="custom_domain"
          isLocked={true}
          fallback={<div data-testid="fallback">Custom Fallback</div>}
        >
          <div>Original Content</div>
        </LockedSection>
      );

      expect(screen.getByTestId('fallback')).toBeInTheDocument();
      expect(screen.getByText('Custom Fallback')).toBeInTheDocument();
      expect(screen.queryByText(/upgrade required/i)).not.toBeInTheDocument();
    });

    it('should not render original children when locked without overlay', () => {
      renderWithRouter(
        <LockedSection feature="webhooks" isLocked={true} variant="banner">
          <div data-testid="original">Original Content</div>
        </LockedSection>
      );

      expect(screen.queryByTestId('original')).not.toBeInTheDocument();
      expect(screen.getByText(/webhooks.*upgrade required/i)).toBeInTheDocument();
    });

    it('should render blurred children with overlay variant', () => {
      renderWithRouter(
        <LockedSection feature="plugins" isLocked={true} variant="overlay">
          <div data-testid="blurred-content">Blurred Content</div>
        </LockedSection>
      );

      const content = screen.getByTestId('blurred-content');
      expect(content).toBeInTheDocument();
      expect(content.parentElement).toHaveClass('blur-sm');
    });
  });

  describe('Different Features', () => {
    it('should work with different feature keys', () => {
      const features: FeatureKey[] = [
        'white_label',
        'custom_oauth',
        'can_create_plugins',
        'tasks',
      ];

      features.forEach((feature) => {
        const { unmount } = renderWithRouter(
          <LockedSection feature={feature} isLocked={true}>
            <div>Content</div>
          </LockedSection>
        );
        expect(screen.getByRole('heading', { level: 3 })).toBeInTheDocument();
        unmount();
      });
    });
  });
});

describe('LockedButton', () => {
  describe('Unlocked State', () => {
    it('should render normal clickable button when not locked', () => {
      const handleClick = vi.fn();
      renderWithRouter(
        <LockedButton
          feature="sms_reminders"
          isLocked={false}
          onClick={handleClick}
          className="custom-class"
        >
          Click Me
        </LockedButton>
      );

      const button = screen.getByRole('button', { name: /click me/i });
      expect(button).toBeInTheDocument();
      expect(button).not.toBeDisabled();
      expect(button).toHaveClass('custom-class');

      fireEvent.click(button);
      expect(handleClick).toHaveBeenCalledTimes(1);
    });

    it('should not show lock icon when unlocked', () => {
      renderWithRouter(
        <LockedButton feature="webhooks" isLocked={false}>
          Submit
        </LockedButton>
      );

      const button = screen.getByRole('button', { name: /submit/i });
      expect(button.querySelector('svg')).not.toBeInTheDocument();
    });
  });

  describe('Locked State', () => {
    it('should render disabled button with lock icon when locked', () => {
      renderWithRouter(
        <LockedButton feature="api_access" isLocked={true}>
          Submit
        </LockedButton>
      );

      const button = screen.getByRole('button', { name: /submit/i });
      expect(button).toBeDisabled();
      expect(button).toHaveClass('opacity-50', 'cursor-not-allowed');
    });

    it('should display lock icon when locked', () => {
      renderWithRouter(
        <LockedButton feature="custom_domain" isLocked={true}>
          Save
        </LockedButton>
      );

      const button = screen.getByRole('button');
      expect(button.textContent).toContain('Save');
    });

    it('should show tooltip on hover when locked', () => {
      const { container } = renderWithRouter(
        <LockedButton feature="plugins" isLocked={true}>
          Create Plugin
        </LockedButton>
      );

      // Tooltip should exist in DOM
      const tooltip = container.querySelector('.opacity-0');
      expect(tooltip).toBeInTheDocument();
      expect(tooltip?.textContent).toContain('Upgrade Required');
    });

    it('should not trigger onClick when locked', () => {
      const handleClick = vi.fn();
      renderWithRouter(
        <LockedButton
          feature="white_label"
          isLocked={true}
          onClick={handleClick}
        >
          Click Me
        </LockedButton>
      );

      const button = screen.getByRole('button');
      fireEvent.click(button);
      expect(handleClick).not.toHaveBeenCalled();
    });

    it('should apply custom className even when locked', () => {
      renderWithRouter(
        <LockedButton
          feature="webhooks"
          isLocked={true}
          className="custom-btn"
        >
          Submit
        </LockedButton>
      );

      const button = screen.getByRole('button');
      expect(button).toHaveClass('custom-btn');
    });

    it('should display feature name in tooltip', () => {
      const { container } = renderWithRouter(
        <LockedButton feature="sms_reminders" isLocked={true}>
          Send SMS
        </LockedButton>
      );

      const tooltip = container.querySelector('.whitespace-nowrap');
      expect(tooltip?.textContent).toContain('SMS Reminders');
    });
  });

  describe('Different Features', () => {
    it('should work with various feature keys', () => {
      const features: FeatureKey[] = [
        'export_data',
        'video_conferencing',
        'two_factor_auth',
        'masked_calling',
      ];

      features.forEach((feature) => {
        const { unmount } = renderWithRouter(
          <LockedButton feature={feature} isLocked={true}>
            Action
          </LockedButton>
        );
        const button = screen.getByRole('button');
        expect(button).toBeDisabled();
        unmount();
      });
    });
  });

  describe('Accessibility', () => {
    it('should have proper button role when unlocked', () => {
      renderWithRouter(
        <LockedButton feature="plugins" isLocked={false}>
          Save
        </LockedButton>
      );

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

    it('should have proper button role when locked', () => {
      renderWithRouter(
        <LockedButton feature="webhooks" isLocked={true}>
          Submit
        </LockedButton>
      );

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

    it('should indicate disabled state for screen readers', () => {
      renderWithRouter(
        <LockedButton feature="api_access" isLocked={true}>
          Create
        </LockedButton>
      );

      const button = screen.getByRole('button');
      expect(button).toHaveAttribute('disabled');
    });
  });
});
