/**
 * Tests for FeatureGate component
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen } from '@testing-library/react';
import React from 'react';
import { FeatureGate, LimitGate } from '../FeatureGate';
import * as useEntitlementsModule from '../../hooks/useEntitlements';

// Mock the useEntitlements hook
vi.mock('../../hooks/useEntitlements', () => ({
  useEntitlements: vi.fn(),
}));

describe('FeatureGate', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('renders children when feature is enabled', () => {
    vi.mocked(useEntitlementsModule.useEntitlements).mockReturnValue({
      entitlements: { can_use_sms_reminders: true },
      isLoading: false,
      hasFeature: (key: string) => key === 'can_use_sms_reminders',
      getLimit: () => null,
      refetch: vi.fn(),
    });

    render(
      <FeatureGate feature="can_use_sms_reminders">
        <div>SMS Feature Content</div>
      </FeatureGate>
    );

    expect(screen.getByText('SMS Feature Content')).toBeInTheDocument();
  });

  it('does not render children when feature is disabled', () => {
    vi.mocked(useEntitlementsModule.useEntitlements).mockReturnValue({
      entitlements: { can_use_sms_reminders: false },
      isLoading: false,
      hasFeature: () => false,
      getLimit: () => null,
      refetch: vi.fn(),
    });

    render(
      <FeatureGate feature="can_use_sms_reminders">
        <div>SMS Feature Content</div>
      </FeatureGate>
    );

    expect(screen.queryByText('SMS Feature Content')).not.toBeInTheDocument();
  });

  it('renders fallback when feature is disabled', () => {
    vi.mocked(useEntitlementsModule.useEntitlements).mockReturnValue({
      entitlements: { can_use_sms_reminders: false },
      isLoading: false,
      hasFeature: () => false,
      getLimit: () => null,
      refetch: vi.fn(),
    });

    render(
      <FeatureGate
        feature="can_use_sms_reminders"
        fallback={<div>Upgrade to access SMS</div>}
      >
        <div>SMS Feature Content</div>
      </FeatureGate>
    );

    expect(screen.queryByText('SMS Feature Content')).not.toBeInTheDocument();
    expect(screen.getByText('Upgrade to access SMS')).toBeInTheDocument();
  });

  it('renders nothing while loading', () => {
    vi.mocked(useEntitlementsModule.useEntitlements).mockReturnValue({
      entitlements: {},
      isLoading: true,
      hasFeature: () => false,
      getLimit: () => null,
      refetch: vi.fn(),
    });

    render(
      <FeatureGate feature="can_use_sms_reminders">
        <div>SMS Feature Content</div>
      </FeatureGate>
    );

    expect(screen.queryByText('SMS Feature Content')).not.toBeInTheDocument();
  });

  it('renders loading component when provided and loading', () => {
    vi.mocked(useEntitlementsModule.useEntitlements).mockReturnValue({
      entitlements: {},
      isLoading: true,
      hasFeature: () => false,
      getLimit: () => null,
      refetch: vi.fn(),
    });

    render(
      <FeatureGate
        feature="can_use_sms_reminders"
        loadingFallback={<div>Loading...</div>}
      >
        <div>SMS Feature Content</div>
      </FeatureGate>
    );

    expect(screen.getByText('Loading...')).toBeInTheDocument();
    expect(screen.queryByText('SMS Feature Content')).not.toBeInTheDocument();
  });

  it('checks multiple features with requireAll=true', () => {
    vi.mocked(useEntitlementsModule.useEntitlements).mockReturnValue({
      entitlements: {
        can_use_sms_reminders: true,
        can_use_mobile_app: false,
      },
      isLoading: false,
      hasFeature: (key: string) => key === 'can_use_sms_reminders',
      getLimit: () => null,
      refetch: vi.fn(),
    });

    render(
      <FeatureGate
        features={['can_use_sms_reminders', 'can_use_mobile_app']}
        requireAll={true}
      >
        <div>Multi Feature Content</div>
      </FeatureGate>
    );

    // Should not render because mobile_app is disabled
    expect(screen.queryByText('Multi Feature Content')).not.toBeInTheDocument();
  });

  it('checks multiple features with requireAll=false (any)', () => {
    vi.mocked(useEntitlementsModule.useEntitlements).mockReturnValue({
      entitlements: {
        can_use_sms_reminders: true,
        can_use_mobile_app: false,
      },
      isLoading: false,
      hasFeature: (key: string) => key === 'can_use_sms_reminders',
      getLimit: () => null,
      refetch: vi.fn(),
    });

    render(
      <FeatureGate
        features={['can_use_sms_reminders', 'can_use_mobile_app']}
        requireAll={false}
      >
        <div>Multi Feature Content</div>
      </FeatureGate>
    );

    // Should render because at least one (sms) is enabled
    expect(screen.getByText('Multi Feature Content')).toBeInTheDocument();
  });
});

describe('LimitGate', () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  it('renders children when under limit', () => {
    vi.mocked(useEntitlementsModule.useEntitlements).mockReturnValue({
      entitlements: { max_users: 10 },
      isLoading: false,
      hasFeature: () => false,
      getLimit: (key: string) => (key === 'max_users' ? 10 : null),
      refetch: vi.fn(),
    });

    render(
      <LimitGate limit="max_users" currentUsage={5}>
        <div>Under Limit Content</div>
      </LimitGate>
    );

    expect(screen.getByText('Under Limit Content')).toBeInTheDocument();
  });

  it('does not render children when at limit', () => {
    vi.mocked(useEntitlementsModule.useEntitlements).mockReturnValue({
      entitlements: { max_users: 10 },
      isLoading: false,
      hasFeature: () => false,
      getLimit: (key: string) => (key === 'max_users' ? 10 : null),
      refetch: vi.fn(),
    });

    render(
      <LimitGate limit="max_users" currentUsage={10}>
        <div>Under Limit Content</div>
      </LimitGate>
    );

    expect(screen.queryByText('Under Limit Content')).not.toBeInTheDocument();
  });

  it('does not render children when over limit', () => {
    vi.mocked(useEntitlementsModule.useEntitlements).mockReturnValue({
      entitlements: { max_users: 10 },
      isLoading: false,
      hasFeature: () => false,
      getLimit: (key: string) => (key === 'max_users' ? 10 : null),
      refetch: vi.fn(),
    });

    render(
      <LimitGate limit="max_users" currentUsage={15}>
        <div>Under Limit Content</div>
      </LimitGate>
    );

    expect(screen.queryByText('Under Limit Content')).not.toBeInTheDocument();
  });

  it('renders fallback when over limit', () => {
    vi.mocked(useEntitlementsModule.useEntitlements).mockReturnValue({
      entitlements: { max_users: 10 },
      isLoading: false,
      hasFeature: () => false,
      getLimit: (key: string) => (key === 'max_users' ? 10 : null),
      refetch: vi.fn(),
    });

    render(
      <LimitGate
        limit="max_users"
        currentUsage={15}
        fallback={<div>Upgrade for more users</div>}
      >
        <div>Under Limit Content</div>
      </LimitGate>
    );

    expect(screen.queryByText('Under Limit Content')).not.toBeInTheDocument();
    expect(screen.getByText('Upgrade for more users')).toBeInTheDocument();
  });

  it('renders children when limit is null (unlimited)', () => {
    vi.mocked(useEntitlementsModule.useEntitlements).mockReturnValue({
      entitlements: {},
      isLoading: false,
      hasFeature: () => false,
      getLimit: () => null,
      refetch: vi.fn(),
    });

    render(
      <LimitGate limit="max_users" currentUsage={1000}>
        <div>Unlimited Content</div>
      </LimitGate>
    );

    // When limit is null, treat as unlimited
    expect(screen.getByText('Unlimited Content')).toBeInTheDocument();
  });
});
