// @vitest-environment happy-dom
import { describe, expect, it, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent, cleanup } from '@testing-library/react';
import { LoginForm } from '../LoginForm.js';
import { MfaChallenge } from '../MfaChallenge.js';
import { SocialButtons } from '../SocialButtons.js';

describe('@bytelyst/auth-ui', () => {
  beforeEach(() => {
    cleanup();
  });

  describe('SocialButtons', () => {
    it('renders buttons for each provider', () => {
      const onSelect = vi.fn();
      render(<SocialButtons providers={['google', 'microsoft', 'apple']} onSelect={onSelect} />);

      expect(screen.getByTestId('bl-social-google')).toBeDefined();
      expect(screen.getByTestId('bl-social-microsoft')).toBeDefined();
      expect(screen.getByTestId('bl-social-apple')).toBeDefined();
      expect(screen.getByText('Continue with Google')).toBeDefined();
      expect(screen.getByText('Continue with Microsoft')).toBeDefined();
      expect(screen.getByText('Continue with Apple')).toBeDefined();
    });

    it('calls onSelect with provider when clicked', () => {
      const onSelect = vi.fn();
      render(<SocialButtons providers={['google']} onSelect={onSelect} />);

      fireEvent.click(screen.getByTestId('bl-social-google'));
      expect(onSelect).toHaveBeenCalledWith('google');
    });

    it('disables buttons when disabled prop is true', () => {
      const onSelect = vi.fn();
      render(<SocialButtons providers={['google']} onSelect={onSelect} disabled />);

      const btn = screen.getByTestId('bl-social-google');
      expect(btn.getAttribute('disabled')).toBe('');
    });
  });

  describe('LoginForm', () => {
    it('renders email, password, and submit button', () => {
      const onSubmit = vi.fn();
      render(<LoginForm onSubmit={onSubmit} />);

      expect(screen.getByTestId('bl-login-email')).toBeDefined();
      expect(screen.getByTestId('bl-login-password')).toBeDefined();
      expect(screen.getByTestId('bl-login-submit')).toBeDefined();
      expect(screen.getByText('Sign in')).toBeDefined();
    });

    it('calls onSubmit with email and password', () => {
      const onSubmit = vi.fn();
      render(<LoginForm onSubmit={onSubmit} />);

      fireEvent.change(screen.getByTestId('bl-login-email'), {
        target: { value: 'test@example.com' },
      });
      fireEvent.change(screen.getByTestId('bl-login-password'), {
        target: { value: 'password123' },
      });
      fireEvent.submit(screen.getByTestId('bl-login-submit').closest('form')!);

      expect(onSubmit).toHaveBeenCalledWith('test@example.com', 'password123');
    });

    it('displays error message', () => {
      const onSubmit = vi.fn();
      render(<LoginForm onSubmit={onSubmit} error="Invalid credentials" />);

      expect(screen.getByTestId('bl-login-error')).toBeDefined();
      expect(screen.getByText('Invalid credentials')).toBeDefined();
    });

    it('renders social buttons when providers are given', () => {
      const onSubmit = vi.fn();
      const onSocialLogin = vi.fn();
      render(
        <LoginForm
          onSubmit={onSubmit}
          providers={['google', 'apple']}
          onSocialLogin={onSocialLogin}
        />
      );

      expect(screen.getByTestId('bl-social-google')).toBeDefined();
      expect(screen.getByTestId('bl-social-apple')).toBeDefined();

      fireEvent.click(screen.getByTestId('bl-social-google'));
      expect(onSocialLogin).toHaveBeenCalledWith('google');
    });

    it('shows loading state', () => {
      const onSubmit = vi.fn();
      render(<LoginForm onSubmit={onSubmit} isLoading />);

      expect(screen.getByText('Signing in...')).toBeDefined();
      const btn = screen.getByTestId('bl-login-submit');
      expect(btn.getAttribute('disabled')).toBe('');
    });
  });

  describe('MfaChallenge', () => {
    it('renders code input and verify button', () => {
      const onSubmit = vi.fn();
      render(<MfaChallenge onSubmit={onSubmit} />);

      expect(screen.getByTestId('bl-mfa-code')).toBeDefined();
      expect(screen.getByTestId('bl-mfa-submit')).toBeDefined();
      expect(screen.getByText('Verify')).toBeDefined();
    });

    it('calls onSubmit with code', () => {
      const onSubmit = vi.fn();
      render(<MfaChallenge onSubmit={onSubmit} />);

      fireEvent.change(screen.getByTestId('bl-mfa-code'), {
        target: { value: '123456' },
      });
      fireEvent.submit(screen.getByTestId('bl-mfa-submit').closest('form')!);

      expect(onSubmit).toHaveBeenCalledWith('123456');
    });

    it('displays available methods', () => {
      const onSubmit = vi.fn();
      render(<MfaChallenge onSubmit={onSubmit} methods={['totp', 'recovery']} />);

      expect(screen.getByTestId('bl-mfa-methods')).toBeDefined();
      expect(screen.getByText('Available methods: totp, recovery')).toBeDefined();
    });

    it('shows recovery code button when handler provided', () => {
      const onSubmit = vi.fn();
      const onUseRecovery = vi.fn();
      render(<MfaChallenge onSubmit={onSubmit} onUseRecovery={onUseRecovery} />);

      const recoveryBtn = screen.getByTestId('bl-mfa-recovery');
      expect(recoveryBtn).toBeDefined();

      fireEvent.click(recoveryBtn);
      expect(onUseRecovery).toHaveBeenCalledOnce();
    });

    it('displays error message', () => {
      const onSubmit = vi.fn();
      render(<MfaChallenge onSubmit={onSubmit} error="Invalid code" />);

      expect(screen.getByTestId('bl-mfa-error')).toBeDefined();
      expect(screen.getByText('Invalid code')).toBeDefined();
    });
  });
});
