import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { MemoryRouter } from 'react-router-dom';
import BookingSettings from '../BookingSettings';

// Mock react-i18next
vi.mock('react-i18next', () => ({
  useTranslation: () => ({
    t: (key: string, defaultValue?: string) => defaultValue || key,
  }),
}));

// Mock react-router-dom hooks
const mockOutletContext = vi.fn();

vi.mock('react-router-dom', async () => {
  const actual = await vi.importActual('react-router-dom');
  return {
    ...actual,
    useOutletContext: () => mockOutletContext(),
  };
});

// Mock clipboard API
Object.assign(navigator, {
  clipboard: {
    writeText: vi.fn(),
  },
});

describe('BookingSettings', () => {
  const mockUpdateBusiness = vi.fn();

  const ownerContext = {
    user: { id: '1', role: 'owner', email: 'owner@test.com' },
    business: {
      id: '1',
      name: 'Test Business',
      subdomain: 'test-business',
      bookingReturnUrl: 'https://example.com/thank-you',
    },
    updateBusiness: mockUpdateBusiness,
  };

  const ownerContextNoReturnUrl = {
    ...ownerContext,
    business: {
      ...ownerContext.business,
      bookingReturnUrl: null,
    },
  };

  const staffContext = {
    ...ownerContext,
    user: { id: '2', role: 'staff', email: 'staff@test.com' },
  };

  beforeEach(() => {
    vi.clearAllMocks();
    mockUpdateBusiness.mockResolvedValue(undefined);
  });

  it('renders the title for owner', () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );
    expect(screen.getByText('Booking')).toBeInTheDocument();
  });

  it('renders the subtitle for owner', () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );
    expect(screen.getByText('Configure your booking page URL and customer redirect settings')).toBeInTheDocument();
  });

  it('shows owner only message for non-owner', () => {
    mockOutletContext.mockReturnValue(staffContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );
    expect(screen.getByText('Only the business owner can access these settings.')).toBeInTheDocument();
  });

  it('renders booking URL section', () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );
    expect(screen.getByText('Your Booking URL')).toBeInTheDocument();
    expect(screen.getByText('Share this URL with your customers so they can book appointments with you.')).toBeInTheDocument();
  });

  it('displays booking URL with subdomain', () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );
    expect(screen.getByText('test-business.smoothschedule.com')).toBeInTheDocument();
  });

  it('copies booking URL to clipboard when copy button clicked', async () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );

    const copyButton = screen.getByTitle('Copy to clipboard');
    fireEvent.click(copyButton);

    expect(navigator.clipboard.writeText).toHaveBeenCalledWith('https://test-business.smoothschedule.com');

    // Check toast appears
    await waitFor(() => {
      expect(screen.getByText('Copied to clipboard')).toBeInTheDocument();
    });
  });

  it('shows toast message after copying', async () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );

    const copyButton = screen.getByTitle('Copy to clipboard');
    fireEvent.click(copyButton);

    await waitFor(() => {
      expect(screen.getByText('Copied to clipboard')).toBeInTheDocument();
    });
  });

  it('has external link to booking page', () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );

    const externalLink = screen.getByTitle('Open booking page');
    expect(externalLink).toHaveAttribute('href', 'https://test-business.smoothschedule.com');
    expect(externalLink).toHaveAttribute('target', '_blank');
    expect(externalLink).toHaveAttribute('rel', 'noopener noreferrer');
  });

  it('renders return URL section', () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );
    expect(screen.getByText('Return URL')).toBeInTheDocument();
    expect(screen.getByText('After a customer completes a booking, redirect them to this URL (e.g., a thank you page on your website).')).toBeInTheDocument();
  });

  it('displays return URL input with current value', () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );
    const input = screen.getByDisplayValue('https://example.com/thank-you');
    expect(input).toBeInTheDocument();
    expect(input).toHaveAttribute('type', 'url');
  });

  it('displays empty return URL input when not set', () => {
    mockOutletContext.mockReturnValue(ownerContextNoReturnUrl);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );
    const input = screen.getByPlaceholderText('https://yourbusiness.com/thank-you');
    expect(input).toHaveValue('');
  });

  it('updates return URL input on change', () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );

    const input = screen.getByDisplayValue('https://example.com/thank-you');
    fireEvent.change(input, { target: { value: 'https://newurl.com/thanks' } });

    expect(screen.getByDisplayValue('https://newurl.com/thanks')).toBeInTheDocument();
  });

  it('renders save button for return URL', () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );
    expect(screen.getByText('Save')).toBeInTheDocument();
  });

  it('calls updateBusiness when save button clicked', async () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );

    const saveButton = screen.getByText('Save');
    fireEvent.click(saveButton);

    await waitFor(() => {
      expect(mockUpdateBusiness).toHaveBeenCalledWith({
        bookingReturnUrl: 'https://example.com/thank-you',
      });
    });
  });

  it('shows toast after saving return URL', async () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );

    const saveButton = screen.getByText('Save');
    fireEvent.click(saveButton);

    await waitFor(() => {
      expect(screen.getByText('Copied to clipboard')).toBeInTheDocument();
    });
  });

  it('disables save button while saving', async () => {
    mockUpdateBusiness.mockImplementation(() => new Promise((resolve) => setTimeout(resolve, 100)));

    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );

    const saveButton = screen.getByText('Save');
    fireEvent.click(saveButton);

    await waitFor(() => {
      expect(screen.getByText('Saving...')).toBeInTheDocument();
    });

    expect(saveButton).toBeDisabled();
  });

  it('shows saving text while saving', async () => {
    mockUpdateBusiness.mockImplementation(() => new Promise((resolve) => setTimeout(resolve, 100)));

    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );

    const saveButton = screen.getByText('Save');
    fireEvent.click(saveButton);

    await waitFor(() => {
      expect(screen.getByText('Saving...')).toBeInTheDocument();
    });
  });

  it('shows error alert when save fails', async () => {
    const alertMock = vi.spyOn(window, 'alert').mockImplementation(() => {});
    mockUpdateBusiness.mockRejectedValue(new Error('Network error'));

    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );

    const saveButton = screen.getByText('Save');
    fireEvent.click(saveButton);

    await waitFor(() => {
      expect(alertMock).toHaveBeenCalledWith('Failed to save return URL');
    });

    alertMock.mockRestore();
  });

  it('renders custom domain help text', () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );
    expect(screen.getByText(/Want to use your own domain/)).toBeInTheDocument();
  });

  it('has link to custom domains settings', () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );
    const link = screen.getByText('custom domain');
    expect(link).toHaveAttribute('href', '/settings/custom-domains');
  });

  it('renders leave empty help text for return URL', () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );
    expect(screen.getByText('Leave empty to keep customers on the booking confirmation page.')).toBeInTheDocument();
  });

  it('has Calendar icon in header', () => {
    mockOutletContext.mockReturnValue(ownerContext);
    const { container } = render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );
    // Check for Calendar icon (Lucide icons render as SVG)
    const calendarIcon = container.querySelector('svg');
    expect(calendarIcon).toBeInTheDocument();
  });

  it('has proper section styling', () => {
    mockOutletContext.mockReturnValue(ownerContext);
    const { container } = render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );
    const sections = container.querySelectorAll('.bg-white');
    expect(sections.length).toBeGreaterThan(0);
  });

  it('saves updated return URL value', async () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );

    const input = screen.getByDisplayValue('https://example.com/thank-you');
    fireEvent.change(input, { target: { value: 'https://newurl.com/success' } });

    const saveButton = screen.getByText('Save');
    fireEvent.click(saveButton);

    await waitFor(() => {
      expect(mockUpdateBusiness).toHaveBeenCalledWith({
        bookingReturnUrl: 'https://newurl.com/success',
      });
    });
  });

  it('can clear return URL', async () => {
    mockOutletContext.mockReturnValue(ownerContext);
    render(
      <MemoryRouter>
        <BookingSettings />
      </MemoryRouter>
    );

    const input = screen.getByDisplayValue('https://example.com/thank-you');
    fireEvent.change(input, { target: { value: '' } });

    const saveButton = screen.getByText('Save');
    fireEvent.click(saveButton);

    await waitFor(() => {
      expect(mockUpdateBusiness).toHaveBeenCalledWith({
        bookingReturnUrl: '',
      });
    });
  });
});
