/**
 * Accessibility tests for asset management components
 */

import React from 'react';
import { render, screen, fireEvent, waitFor } from '@testing-library/react';
import { axe, toHaveNoViolations } from 'jest-axe';
import userEvent from '@testing-library/user-event';
import { QueryClient, QueryClientProvider } from '@tanstack/react-query';
import { BrowserRouter } from 'react-router-dom';

import AssetList from '../AssetList';
import AssetForm from '../AssetForm';
import AssetDetail from '../AssetDetail';
import ConfirmDialog from '../shared/ConfirmDialog';
import Pagination from '../shared/Pagination';
import { Asset, AssetAssignment, SystemDetails } from '@/types/asset-management';

// Extend Jest matchers
expect.extend(toHaveNoViolations);

// Mock data
const mockAssets: Asset[] = [
  {
    assetID: 1,
    assetType: 'Laptop',
    brandModel: 'Dell Latitude 7420',
    serialNumber: 'DL123456',
    assetCondition: 'Excellent'
  },
  {
    assetID: 2,
    assetType: 'Monitor',
    brandModel: 'Samsung 27" 4K',
    serialNumber: 'SM789012',
    assetCondition: 'Good'
  }
];

const mockAssignments: AssetAssignment[] = [
  {
    assignmentID: 1,
    assetID: 1,
    employeeID: 101,
    assignedDate: '2024-01-15T00:00:00Z',
    returnedDate: null,
    remarks: 'Assigned for development work'
  }
];

const mockSystemDetails: SystemDetails = {
  systemDetailsID: 1,
  assetID: 1,
  systemModel: 'Latitude 7420',
  processor: 'Intel i7-1185G7',
  installedRAM: '16GB DDR4',
  graphics: 'Intel Iris Xe',
  screenResolution: '1920x1080',
  diskModel: 'Samsung SSD 980',
  diskSize: '512GB',
  manufacturer: 'Dell'
};

// Test wrapper component
const TestWrapper: React.FC<{ children: React.ReactNode }> = ({ children }) => {
  const queryClient = new QueryClient({
    defaultOptions: {
      queries: { retry: false },
      mutations: { retry: false }
    }
  });

  return (
    <QueryClientProvider client={queryClient}>
      <BrowserRouter>
        {children}
      </BrowserRouter>
    </QueryClientProvider>
  );
};

describe('Asset Management Accessibility Tests', () => {
  describe('AssetList Component', () => {
    it('should not have accessibility violations', async () => {
      const { container } = render(
        <TestWrapper>
          <AssetList
            assets={mockAssets}
            assignments={mockAssignments}
            isLoading={false}
            showActions={true}
          />
        </TestWrapper>
      );

      const results = await axe(container);
      expect(results).toHaveNoViolations();
    });

    it('should have proper ARIA labels for interactive elements', () => {
      render(
        <TestWrapper>
          <AssetList
            assets={mockAssets}
            assignments={mockAssignments}
            isLoading={false}
            showActions={true}
          />
        </TestWrapper>
      );

      // Check search input has proper labeling
      const searchInput = screen.getByRole('searchbox');
      expect(searchInput).toHaveAttribute('aria-label');

      // Check filter selects have proper labeling
      const typeFilter = screen.getByLabelText(/filter by asset type/i);
      expect(typeFilter).toBeInTheDocument();

      const conditionFilter = screen.getByLabelText(/filter by asset condition/i);
      expect(conditionFilter).toBeInTheDocument();

      const assignmentFilter = screen.getByLabelText(/filter by assignment status/i);
      expect(assignmentFilter).toBeInTheDocument();
    });

    it('should support keyboard navigation for sortable headers', async () => {
      const user = userEvent.setup();
      
      render(
        <TestWrapper>
          <AssetList
            assets={mockAssets}
            assignments={mockAssignments}
            isLoading={false}
            showActions={true}
          />
        </TestWrapper>
      );

      // Find sortable header (desktop view)
      const idHeader = screen.getByRole('button', { name: /sort by id/i });
      expect(idHeader).toBeInTheDocument();

      // Test keyboard activation
      idHeader.focus();
      await user.keyboard('{Enter}');
      
      // Should have proper ARIA attributes
      expect(idHeader).toHaveAttribute('aria-label');
      expect(idHeader).toHaveAttribute('tabIndex', '0');
    });

    it('should announce filter results to screen readers', async () => {
      render(
        <TestWrapper>
          <AssetList
            assets={mockAssets}
            assignments={mockAssignments}
            isLoading={false}
            showActions={true}
          />
        </TestWrapper>
      );

      // Check results count has live region
      const resultsCount = screen.getByText(/showing \d+ of \d+ assets/i);
      expect(resultsCount).toHaveAttribute('aria-live', 'polite');
      expect(resultsCount).toHaveAttribute('aria-atomic', 'true');
    });

    it('should provide proper action button labels', () => {
      const mockOnView = jest.fn();
      const mockOnEdit = jest.fn();
      const mockOnDelete = jest.fn();

      render(
        <TestWrapper>
          <AssetList
            assets={mockAssets}
            assignments={mockAssignments}
            isLoading={false}
            onView={mockOnView}
            onEdit={mockOnEdit}
            onDelete={mockOnDelete}
            showActions={true}
          />
        </TestWrapper>
      );

      // Check action buttons have descriptive labels
      const viewButtons = screen.getAllByLabelText(/view asset/i);
      const editButtons = screen.getAllByLabelText(/edit asset/i);
      const deleteButtons = screen.getAllByLabelText(/delete asset/i);

      expect(viewButtons.length).toBeGreaterThan(0);
      expect(editButtons.length).toBeGreaterThan(0);
      expect(deleteButtons.length).toBeGreaterThan(0);

      // Each button should include asset information in the label
      viewButtons.forEach(button => {
        expect(button.getAttribute('aria-label')).toMatch(/Dell Latitude 7420|Samsung 27" 4K/);
      });
    });
  });

  describe('AssetForm Component', () => {
    it('should not have accessibility violations', async () => {
      const mockOnSubmit = jest.fn();
      const mockOnCancel = jest.fn();

      const { container } = render(
        <TestWrapper>
          <AssetForm
            onSubmit={mockOnSubmit}
            onCancel={mockOnCancel}
            isSubmitting={false}
          />
        </TestWrapper>
      );

      const results = await axe(container);
      expect(results).toHaveNoViolations();
    });

    it('should have proper form labels and error handling', async () => {
      const mockOnSubmit = jest.fn().mockRejectedValue(new Error('Serial number already exists'));
      const mockOnCancel = jest.fn();

      render(
        <TestWrapper>
          <AssetForm
            onSubmit={mockOnSubmit}
            onCancel={mockOnCancel}
            isSubmitting={false}
          />
        </TestWrapper>
      );

      // Check all form fields have proper labels
      expect(screen.getByLabelText(/asset type/i)).toBeInTheDocument();
      expect(screen.getByLabelText(/brand\/model/i)).toBeInTheDocument();
      expect(screen.getByLabelText(/serial number/i)).toBeInTheDocument();
      expect(screen.getByLabelText(/asset condition/i)).toBeInTheDocument();
    });

    it('should announce form errors to screen readers', async () => {
      const mockOnSubmit = jest.fn();
      const mockOnCancel = jest.fn();

      render(
        <TestWrapper>
          <AssetForm
            onSubmit={mockOnSubmit}
            onCancel={mockOnCancel}
            isSubmitting={false}
          />
        </TestWrapper>
      );

      // Submit form without filling required fields
      const submitButton = screen.getByRole('button', { name: /create asset/i });
      fireEvent.click(submitButton);

      await waitFor(() => {
        // Check for error messages with proper ARIA attributes
        const errorMessages = screen.getAllByRole('alert');
        expect(errorMessages.length).toBeGreaterThan(0);
      });
    });

    it('should provide loading state feedback', () => {
      const mockOnSubmit = jest.fn();
      const mockOnCancel = jest.fn();

      render(
        <TestWrapper>
          <AssetForm
            onSubmit={mockOnSubmit}
            onCancel={mockOnCancel}
            isSubmitting={true}
          />
        </TestWrapper>
      );

      const submitButton = screen.getByRole('button', { name: /creating/i });
      expect(submitButton).toBeDisabled();
      expect(submitButton).toHaveAttribute('aria-describedby');
    });
  });

  describe('ConfirmDialog Component', () => {
    it('should not have accessibility violations', async () => {
      const mockOnClose = jest.fn();
      const mockOnConfirm = jest.fn();

      const { container } = render(
        <ConfirmDialog
          isOpen={true}
          onClose={mockOnClose}
          onConfirm={mockOnConfirm}
          title="Delete Asset"
          description="Are you sure you want to delete this asset?"
        />
      );

      const results = await axe(container);
      expect(results).toHaveNoViolations();
    });

    it('should have proper dialog ARIA attributes', () => {
      const mockOnClose = jest.fn();
      const mockOnConfirm = jest.fn();

      render(
        <ConfirmDialog
          isOpen={true}
          onClose={mockOnClose}
          onConfirm={mockOnConfirm}
          title="Delete Asset"
          description="Are you sure you want to delete this asset?"
        />
      );

      const dialog = screen.getByRole('dialog');
      expect(dialog).toHaveAttribute('aria-modal', 'true');
      expect(dialog).toHaveAttribute('aria-labelledby');
      expect(dialog).toHaveAttribute('aria-describedby');
    });

    it('should trap focus within the dialog', async () => {
      const user = userEvent.setup();
      const mockOnClose = jest.fn();
      const mockOnConfirm = jest.fn();

      render(
        <ConfirmDialog
          isOpen={true}
          onClose={mockOnClose}
          onConfirm={mockOnConfirm}
          title="Delete Asset"
          description="Are you sure you want to delete this asset?"
        />
      );

      // Focus should be on the cancel button initially
      const cancelButton = screen.getByRole('button', { name: /cancel/i });
      expect(cancelButton).toHaveFocus();

      // Tab should move to confirm button
      await user.tab();
      const confirmButton = screen.getByRole('button', { name: /confirm/i });
      expect(confirmButton).toHaveFocus();

      // Tab again should cycle back to cancel
      await user.tab();
      expect(cancelButton).toHaveFocus();
    });

    it('should close on Escape key', async () => {
      const user = userEvent.setup();
      const mockOnClose = jest.fn();
      const mockOnConfirm = jest.fn();

      render(
        <ConfirmDialog
          isOpen={true}
          onClose={mockOnClose}
          onConfirm={mockOnConfirm}
          title="Delete Asset"
          description="Are you sure you want to delete this asset?"
        />
      );

      await user.keyboard('{Escape}');
      expect(mockOnClose).toHaveBeenCalled();
    });
  });

  describe('Pagination Component', () => {
    it('should not have accessibility violations', async () => {
      const mockOnPageChange = jest.fn();
      const mockOnItemsPerPageChange = jest.fn();

      const { container } = render(
        <Pagination
          currentPage={1}
          totalPages={5}
          totalItems={50}
          itemsPerPage={10}
          onPageChange={mockOnPageChange}
          onItemsPerPageChange={mockOnItemsPerPageChange}
        />
      );

      const results = await axe(container);
      expect(results).toHaveNoViolations();
    });

    it('should have proper navigation structure', () => {
      const mockOnPageChange = jest.fn();
      const mockOnItemsPerPageChange = jest.fn();

      render(
        <Pagination
          currentPage={2}
          totalPages={5}
          totalItems={50}
          itemsPerPage={10}
          onPageChange={mockOnPageChange}
          onItemsPerPageChange={mockOnItemsPerPageChange}
        />
      );

      // Should have navigation landmark
      const nav = screen.getByRole('navigation');
      expect(nav).toHaveAttribute('aria-label', 'Pagination Navigation');

      // Should have proper button labels
      expect(screen.getByLabelText(/go to first page/i)).toBeInTheDocument();
      expect(screen.getByLabelText(/go to previous page/i)).toBeInTheDocument();
      expect(screen.getByLabelText(/go to next page/i)).toBeInTheDocument();
      expect(screen.getByLabelText(/go to last page/i)).toBeInTheDocument();
    });

    it('should indicate current page', () => {
      const mockOnPageChange = jest.fn();
      const mockOnItemsPerPageChange = jest.fn();

      render(
        <Pagination
          currentPage={2}
          totalPages={5}
          totalItems={50}
          itemsPerPage={10}
          onPageChange={mockOnPageChange}
          onItemsPerPageChange={mockOnItemsPerPageChange}
        />
      );

      const currentPageButton = screen.getByRole('button', { name: /go to page 2/i });
      expect(currentPageButton).toHaveAttribute('aria-current', 'page');
    });

    it('should announce page changes', () => {
      const mockOnPageChange = jest.fn();
      const mockOnItemsPerPageChange = jest.fn();

      render(
        <Pagination
          currentPage={1}
          totalPages={5}
          totalItems={50}
          itemsPerPage={10}
          onPageChange={mockOnPageChange}
          onItemsPerPageChange={mockOnItemsPerPageChange}
        />
      );

      // Page info should have live region
      const pageInfo = screen.getByText(/showing 1 to 10 of 50 items/i);
      expect(pageInfo).toHaveAttribute('aria-live', 'polite');
      expect(pageInfo).toHaveAttribute('aria-atomic', 'true');
    });
  });

  describe('AssetDetail Component', () => {
    it('should not have accessibility violations', async () => {
      const { container } = render(
        <TestWrapper>
          <AssetDetail
            asset={{ ...mockAssets[0], systemDetails: mockSystemDetails, assignments: mockAssignments }}
            systemDetails={mockSystemDetails}
            assignments={mockAssignments}
            isLoading={false}
          />
        </TestWrapper>
      );

      const results = await axe(container);
      expect(results).toHaveNoViolations();
    });

    it('should have proper tab structure', () => {
      render(
        <TestWrapper>
          <AssetDetail
            asset={{ ...mockAssets[0], systemDetails: mockSystemDetails, assignments: mockAssignments }}
            systemDetails={mockSystemDetails}
            assignments={mockAssignments}
            isLoading={false}
          />
        </TestWrapper>
      );

      // Check tab list and panels
      const tabList = screen.getByRole('tablist');
      expect(tabList).toBeInTheDocument();

      const systemDetailsTab = screen.getByRole('tab', { name: /system details/i });
      const assignmentsTab = screen.getByRole('tab', { name: /assignment history/i });

      expect(systemDetailsTab).toHaveAttribute('aria-controls');
      expect(assignmentsTab).toHaveAttribute('aria-controls');
    });

    it('should have proper field labeling', () => {
      render(
        <TestWrapper>
          <AssetDetail
            asset={{ ...mockAssets[0], systemDetails: mockSystemDetails, assignments: mockAssignments }}
            systemDetails={mockSystemDetails}
            assignments={mockAssignments}
            isLoading={false}
          />
        </TestWrapper>
      );

      // Check that data fields have proper labeling
      expect(screen.getByLabelText(/asset id/i)).toBeInTheDocument();
      expect(screen.getByLabelText(/condition/i)).toBeInTheDocument();
      expect(screen.getByLabelText(/serial number/i)).toBeInTheDocument();
      expect(screen.getByLabelText(/assignment status/i)).toBeInTheDocument();
    });
  });

  describe('Responsive Design Tests', () => {
    beforeEach(() => {
      // Mock window.matchMedia for responsive tests
      Object.defineProperty(window, 'matchMedia', {
        writable: true,
        value: jest.fn().mockImplementation(query => ({
          matches: query.includes('max-width: 767px'), // Mock mobile
          media: query,
          onchange: null,
          addListener: jest.fn(),
          removeListener: jest.fn(),
          addEventListener: jest.fn(),
          removeEventListener: jest.fn(),
          dispatchEvent: jest.fn(),
        })),
      });
    });

    it('should show mobile card view on small screens', () => {
      // Mock mobile viewport
      Object.defineProperty(window, 'innerWidth', {
        writable: true,
        configurable: true,
        value: 600,
      });

      render(
        <TestWrapper>
          <AssetList
            assets={mockAssets}
            assignments={mockAssignments}
            isLoading={false}
            showActions={true}
          />
        </TestWrapper>
      );

      // Mobile view should show cards instead of table
      // The table should be hidden on mobile (md:block class)
      const mobileCards = document.querySelectorAll('.md\\:hidden');
      expect(mobileCards.length).toBeGreaterThan(0);
    });

    it('should have proper touch target sizes on mobile', () => {
      render(
        <TestWrapper>
          <AssetList
            assets={mockAssets}
            assignments={mockAssignments}
            isLoading={false}
            showActions={true}
          />
        </TestWrapper>
      );

      // Check that buttons have minimum touch target size
      const buttons = screen.getAllByRole('button');
      buttons.forEach(button => {
        const styles = window.getComputedStyle(button);
        // Note: In a real test environment, you'd check computed styles
        // Here we're just ensuring the buttons exist and are accessible
        expect(button).toBeInTheDocument();
      });
    });
  });

  describe('Keyboard Navigation Tests', () => {
    it('should support full keyboard navigation in AssetList', async () => {
      const user = userEvent.setup();
      
      render(
        <TestWrapper>
          <AssetList
            assets={mockAssets}
            assignments={mockAssignments}
            isLoading={false}
            showActions={true}
          />
        </TestWrapper>
      );

      // Tab through interactive elements
      await user.tab(); // Search input
      expect(screen.getByRole('searchbox')).toHaveFocus();

      await user.tab(); // Type filter
      await user.tab(); // Condition filter  
      await user.tab(); // Assignment filter
      await user.tab(); // Create button (if present)
      
      // Should be able to navigate to table headers
      const sortableHeaders = screen.getAllByRole('button', { name: /sort by/i });
      if (sortableHeaders.length > 0) {
        sortableHeaders[0].focus();
        expect(sortableHeaders[0]).toHaveFocus();
      }
    });

    it('should support keyboard activation of interactive elements', async () => {
      const user = userEvent.setup();
      const mockOnView = jest.fn();
      
      render(
        <TestWrapper>
          <AssetList
            assets={mockAssets}
            assignments={mockAssignments}
            isLoading={false}
            onView={mockOnView}
            showActions={true}
          />
        </TestWrapper>
      );

      // Find and activate view button with keyboard
      const viewButtons = screen.getAllByLabelText(/view asset/i);
      if (viewButtons.length > 0) {
        viewButtons[0].focus();
        await user.keyboard('{Enter}');
        expect(mockOnView).toHaveBeenCalled();
      }
    });
  });
});