import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { MemoryRouter, Route, Routes } from 'react-router-dom';
import React from 'react';

// Mock react-i18next
vi.mock('react-i18next', () => ({
  useTranslation: () => ({
    t: (key: string, options?: any) => {
      if (typeof options === 'object' && options.customerName) {
        return `Contract for ${options.customerName}`;
      }
      return key;
    },
  }),
}));

// Mock hooks
const mockUsePublicContract = vi.fn();
const mockUseSignContract = vi.fn();

vi.mock('../../hooks/useContracts', () => ({
  usePublicContract: (token: string) => mockUsePublicContract(token),
  useSignContract: () => mockUseSignContract(),
}));

import ContractSigning from '../ContractSigning';

describe('ContractSigning', () => {
  const mockContractData = {
    contract: {
      id: '123',
      content: '<h1>Contract Title</h1><p>Contract terms and conditions...</p>',
      status: 'PENDING',
    },
    template: {
      name: 'Service Agreement',
    },
    business: {
      id: '1',
      name: 'Test Business',
      logo_url: 'https://example.com/logo.png',
    },
    customer: {
      name: 'John Doe',
      email: 'john@example.com',
    },
    can_sign: true,
    is_expired: false,
  };

  const mockSignature = {
    signer_name: 'John Doe',
    signer_email: 'john@example.com',
    signed_at: '2024-01-15T10:30:00Z',
  };

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

    mockUsePublicContract.mockReturnValue({
      data: mockContractData,
      isLoading: false,
      error: null,
      refetch: vi.fn(),
    });

    mockUseSignContract.mockReturnValue({
      mutateAsync: vi.fn().mockResolvedValue({}),
      isPending: false,
      isSuccess: false,
      isError: false,
    });
  });

  const renderComponent = (token = 'test-token') => {
    const queryClient = new QueryClient({
      defaultOptions: {
        queries: { retry: false },
        mutations: { retry: false },
      },
    });

    return render(
      <QueryClientProvider client={queryClient}>
        <MemoryRouter initialEntries={[`/contracts/sign/${token}`]}>
          <Routes>
            <Route path="/contracts/sign/:token" element={<ContractSigning />} />
          </Routes>
        </MemoryRouter>
      </QueryClientProvider>
    );
  };

  it('renders loading state', () => {
    mockUsePublicContract.mockReturnValue({
      data: null,
      isLoading: true,
      error: null,
      refetch: vi.fn(),
    });

    renderComponent();

    expect(screen.getByText('common.loading')).toBeInTheDocument();
    const loader = document.querySelector('.animate-spin');
    expect(loader).toBeInTheDocument();
  });

  it('renders contract not found error', () => {
    mockUsePublicContract.mockReturnValue({
      data: null,
      isLoading: false,
      error: new Error('Not found'),
      refetch: vi.fn(),
    });

    renderComponent();

    expect(screen.getByText('contracts.signing.notFound')).toBeInTheDocument();
    expect(screen.getByText(/invalid or has expired/i)).toBeInTheDocument();
  });

  it('renders expired contract message', () => {
    mockUsePublicContract.mockReturnValue({
      data: { ...mockContractData, is_expired: true },
      isLoading: false,
      error: null,
      refetch: vi.fn(),
    });

    renderComponent();

    expect(screen.getByText('contracts.signing.expired')).toBeInTheDocument();
    expect(screen.getByText(/can no longer be signed/i)).toBeInTheDocument();
  });

  it('renders contract signing form', () => {
    renderComponent();

    expect(screen.getByText('Test Business')).toBeInTheDocument();
    expect(screen.getByText('Service Agreement')).toBeInTheDocument();
    expect(screen.getByText('Contract for John Doe')).toBeInTheDocument();
    expect(screen.getByPlaceholderText('Enter your full name')).toBeInTheDocument();
  });

  it('renders contract content', () => {
    renderComponent();

    const contractContent = document.querySelector('.prose');
    expect(contractContent).toBeInTheDocument();
    expect(contractContent?.innerHTML).toContain('Contract Title');
    expect(contractContent?.innerHTML).toContain('Contract terms and conditions');
  });

  it('displays business logo when available', () => {
    renderComponent();

    const logo = screen.getByAltText('Test Business');
    expect(logo).toBeInTheDocument();
    expect(logo).toHaveAttribute('src', 'https://example.com/logo.png');
  });

  it('shows signature input and preview', async () => {
    const user = userEvent.setup();
    renderComponent();

    const nameInput = screen.getByPlaceholderText('Enter your full name');
    await user.type(nameInput, 'John Doe');

    expect(nameInput).toHaveValue('John Doe');

    // Check for signature preview
    await waitFor(() => {
      expect(screen.getByText('Signature Preview:')).toBeInTheDocument();
    });

    // Preview should show the typed name in cursive
    const preview = document.querySelector('[style*="cursive"]');
    expect(preview).toBeInTheDocument();
    expect(preview?.textContent).toBe('John Doe');
  });

  it('requires all consent checkboxes', async () => {
    const user = userEvent.setup();
    renderComponent();

    const nameInput = screen.getByPlaceholderText('Enter your full name');
    await user.type(nameInput, 'John Doe');

    const signButton = screen.getByRole('button', { name: /sign contract/i });

    // Button should be disabled without consent
    expect(signButton).toBeDisabled();

    // Check first checkbox
    const checkbox1 = screen.getByLabelText(/have read and agree/i);
    await user.click(checkbox1);

    // Still disabled without second checkbox
    expect(signButton).toBeDisabled();

    // Check second checkbox
    const checkbox2 = screen.getByLabelText(/consent to conduct business electronically/i);
    await user.click(checkbox2);

    // Now should be enabled
    expect(signButton).toBeEnabled();
  });

  it('submits signature when all fields are valid', async () => {
    const user = userEvent.setup();
    const mockMutate = vi.fn().mockResolvedValue({});
    mockUseSignContract.mockReturnValue({
      mutateAsync: mockMutate,
      isPending: false,
      isSuccess: false,
      isError: false,
    });

    renderComponent();

    // Fill name
    const nameInput = screen.getByPlaceholderText('Enter your full name');
    await user.type(nameInput, 'John Doe');

    // Check both checkboxes
    const checkbox1 = screen.getByLabelText(/have read and agree/i);
    const checkbox2 = screen.getByLabelText(/consent to conduct business electronically/i);
    await user.click(checkbox1);
    await user.click(checkbox2);

    // Submit
    const signButton = screen.getByRole('button', { name: /sign contract/i });
    await user.click(signButton);

    await waitFor(() => {
      expect(mockMutate).toHaveBeenCalledWith({
        token: 'test-token',
        signer_name: 'John Doe',
        consent_checkbox_checked: true,
        electronic_consent_given: true,
      });
    });
  });

  it('shows loading state while signing', async () => {
    const user = userEvent.setup();
    mockUseSignContract.mockReturnValue({
      mutateAsync: vi.fn().mockImplementation(() => new Promise(() => {})),
      isPending: true,
      isSuccess: false,
      isError: false,
    });

    renderComponent();

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

  it('shows error message when signing fails', async () => {
    const user = userEvent.setup();
    mockUseSignContract.mockReturnValue({
      mutateAsync: vi.fn().mockRejectedValue(new Error('Signing failed')),
      isPending: false,
      isSuccess: false,
      isError: true,
    });

    renderComponent();

    await waitFor(() => {
      expect(screen.getByText(/failed to sign the contract/i)).toBeInTheDocument();
    });
  });

  it('renders signed contract view after successful signing', () => {
    mockUsePublicContract.mockReturnValue({
      data: {
        ...mockContractData,
        contract: { ...mockContractData.contract, status: 'SIGNED' },
        signature: mockSignature,
      },
      isLoading: false,
      error: null,
      refetch: vi.fn(),
    });

    renderComponent();

    expect(screen.getByText(/contract successfully signed/i)).toBeInTheDocument();
    expect(screen.getByRole('button', { name: /print contract/i })).toBeInTheDocument();
  });

  it('displays signature details in signed view', () => {
    mockUsePublicContract.mockReturnValue({
      data: {
        ...mockContractData,
        contract: { ...mockContractData.contract, status: 'SIGNED' },
        signature: mockSignature,
      },
      isLoading: false,
      error: null,
      refetch: vi.fn(),
    });

    renderComponent();

    // Use getAllByText since "John Doe" and "john@example.com" appear multiple times
    expect(screen.getAllByText('John Doe').length).toBeGreaterThan(0);
    expect(screen.getAllByText('john@example.com').length).toBeGreaterThan(0);

    // Check for "Signed" status badge
    const signedBadges = screen.queryAllByText(/^signed$/i);
    expect(signedBadges.length).toBeGreaterThan(0);
  });

  it('handles print button click', async () => {
    const user = userEvent.setup();
    const mockPrint = vi.fn();
    window.print = mockPrint;

    mockUsePublicContract.mockReturnValue({
      data: {
        ...mockContractData,
        contract: { ...mockContractData.contract, status: 'SIGNED' },
        signature: mockSignature,
      },
      isLoading: false,
      error: null,
      refetch: vi.fn(),
    });

    renderComponent();

    const printButton = screen.getByRole('button', { name: /print contract/i });
    await user.click(printButton);

    expect(mockPrint).toHaveBeenCalled();
  });

  it('shows legal compliance notice in signing form', () => {
    renderComponent();

    expect(screen.getByText(/ESIGN Act/i)).toBeInTheDocument();
    expect(screen.getByText(/UETA/i)).toBeInTheDocument();
  });

  it('shows electronic consent disclosure', () => {
    renderComponent();

    expect(screen.getByText(/conduct business electronically/i)).toBeInTheDocument();
    expect(screen.getByText(/right to receive documents in paper form/i)).toBeInTheDocument();
  });

  it('prevents signing when cannot sign', () => {
    mockUsePublicContract.mockReturnValue({
      data: {
        ...mockContractData,
        can_sign: false,
      },
      isLoading: false,
      error: null,
      refetch: vi.fn(),
    });

    renderComponent();

    // Should not show the signing form
    expect(screen.queryByPlaceholderText('Enter your full name')).not.toBeInTheDocument();
  });

  it('validates name is not empty before enabling submit', async () => {
    const user = userEvent.setup();
    renderComponent();

    const checkbox1 = screen.getByLabelText(/have read and agree/i);
    const checkbox2 = screen.getByLabelText(/consent to conduct business electronically/i);
    await user.click(checkbox1);
    await user.click(checkbox2);

    const signButton = screen.getByRole('button', { name: /sign contract/i });

    // Should be disabled with empty name
    expect(signButton).toBeDisabled();

    // Type name
    const nameInput = screen.getByPlaceholderText('Enter your full name');
    await user.type(nameInput, 'John Doe');

    // Should be enabled now
    expect(signButton).toBeEnabled();
  });
});
