/**
 * @ai-summary Unit tests for MaintenanceScheduleReviewScreen component
 * @ai-context Tests rendering, selection, editing, empty state, and error handling
 */

import { render, screen, fireEvent } from '@testing-library/react';
import { MaintenanceScheduleReviewScreen } from './MaintenanceScheduleReviewScreen';
import type { MaintenanceScheduleItem } from '../../documents/hooks/useManualExtraction';

// Mock matchMedia for responsive tests
function mockMatchMedia(matches: boolean) {
  Object.defineProperty(window, 'matchMedia', {
    writable: true,
    value: jest.fn().mockImplementation((query: string) => ({
      matches,
      media: query,
      onchange: null,
      addListener: jest.fn(),
      removeListener: jest.fn(),
      addEventListener: jest.fn(),
      removeEventListener: jest.fn(),
      dispatchEvent: jest.fn(),
    })),
  });
}

// Mock the create hook
const mockMutateAsync = jest.fn();
jest.mock('../hooks/useCreateSchedulesFromExtraction', () => ({
  useCreateSchedulesFromExtraction: () => ({
    mutateAsync: mockMutateAsync,
    isPending: false,
  }),
}));

// Track SubtypeCheckboxGroup onChange callbacks per instance
const subtypeOnChangeCallbacks: Array<(subtypes: string[]) => void> = [];
jest.mock('./SubtypeCheckboxGroup', () => ({
  SubtypeCheckboxGroup: ({ selected, onChange }: { category: string; selected: string[]; onChange: (subtypes: string[]) => void }) => {
    subtypeOnChangeCallbacks.push(onChange);
    return (
      <div data-testid="subtype-checkbox-group">
        {selected.map((s: string) => (
          <span key={s} data-testid="subtype-chip">{s}</span>
        ))}
      </div>
    );
  },
}));

const sampleItems: MaintenanceScheduleItem[] = [
  {
    service: 'Engine Oil Change',
    intervalMiles: 5000,
    intervalMonths: 6,
    details: 'Use 0W-20 full synthetic oil',
    confidence: 0.95,
    subtypes: ['Engine Oil'],
  },
  {
    service: 'Tire Rotation',
    intervalMiles: 5000,
    intervalMonths: 6,
    details: null,
    confidence: 0.88,
    subtypes: ['Tires'],
  },
  {
    service: 'Cabin Air Filter Replacement',
    intervalMiles: 15000,
    intervalMonths: 12,
    details: null,
    confidence: 0.72,
    subtypes: ['Cabin Air Filter / Purifier'],
  },
];

const sampleItemsWithEmptySubtypes: MaintenanceScheduleItem[] = [
  ...sampleItems,
  {
    service: 'Brake Fluid',
    intervalMiles: 30000,
    intervalMonths: 24,
    details: null,
    confidence: 0.65,
    subtypes: [],
  },
];

const sampleItemsWithMissingIntervals: MaintenanceScheduleItem[] = [
  ...sampleItems,
  {
    service: 'Coolant Flush',
    intervalMiles: null,
    intervalMonths: null,
    details: null,
    confidence: 0.55,
    subtypes: ['Coolant'],
  },
];

describe('MaintenanceScheduleReviewScreen', () => {
  const defaultProps = {
    open: true,
    items: sampleItems,
    vehicleId: 'vehicle-123',
    onClose: jest.fn(),
    onCreated: jest.fn(),
  };

  beforeEach(() => {
    jest.clearAllMocks();
    mockMutateAsync.mockResolvedValue([]);
    subtypeOnChangeCallbacks.length = 0;
  });

  describe('Rendering', () => {
    it('should render extracted items with checkboxes', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} />);

      expect(screen.getByText('Extracted Maintenance Schedules')).toBeInTheDocument();
      expect(screen.getByText('3 of 3 items selected')).toBeInTheDocument();

      // All items should be visible
      expect(screen.getByText('Engine Oil Change')).toBeInTheDocument();
      expect(screen.getByText('Tire Rotation')).toBeInTheDocument();
      expect(screen.getByText('Cabin Air Filter Replacement')).toBeInTheDocument();

      // All checkboxes should be checked by default
      const checkboxes = screen.getAllByRole('checkbox');
      expect(checkboxes).toHaveLength(3);
      checkboxes.forEach((cb) => {
        expect(cb).toBeChecked();
      });
    });

    it('should display interval information', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} />);

      expect(screen.getAllByText('5000 mi')).toHaveLength(2);
      expect(screen.getAllByText('6 mo')).toHaveLength(2);
      expect(screen.getByText('15000 mi')).toBeInTheDocument();
      expect(screen.getByText('12 mo')).toBeInTheDocument();
    });

    it('should display details text when present', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} />);

      expect(screen.getByText('Use 0W-20 full synthetic oil')).toBeInTheDocument();
    });

    it('should display subtypes in SubtypeCheckboxGroup', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} />);

      const groups = screen.getAllByTestId('subtype-checkbox-group');
      expect(groups).toHaveLength(3);

      expect(screen.getByText('Engine Oil')).toBeInTheDocument();
      expect(screen.getByText('Tires')).toBeInTheDocument();
      expect(screen.getByText('Cabin Air Filter / Purifier')).toBeInTheDocument();
    });
  });

  describe('Selection', () => {
    it('should toggle item selection on checkbox click', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} />);

      const checkboxes = screen.getAllByRole('checkbox');

      // Uncheck first item
      fireEvent.click(checkboxes[0]);
      expect(checkboxes[0]).not.toBeChecked();
      expect(screen.getByText('2 of 3 items selected')).toBeInTheDocument();

      // Re-check it
      fireEvent.click(checkboxes[0]);
      expect(checkboxes[0]).toBeChecked();
      expect(screen.getByText('3 of 3 items selected')).toBeInTheDocument();
    });

    it('should deselect all items', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} />);

      fireEvent.click(screen.getByText('Deselect All'));

      const checkboxes = screen.getAllByRole('checkbox');
      checkboxes.forEach((cb) => {
        expect(cb).not.toBeChecked();
      });
      expect(screen.getByText('0 of 3 items selected')).toBeInTheDocument();
    });

    it('should select all items after deselecting', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} />);

      // Deselect all first
      fireEvent.click(screen.getByText('Deselect All'));
      expect(screen.getByText('0 of 3 items selected')).toBeInTheDocument();

      // Select all
      fireEvent.click(screen.getByText('Select All'));

      const checkboxes = screen.getAllByRole('checkbox');
      checkboxes.forEach((cb) => {
        expect(cb).toBeChecked();
      });
      expect(screen.getByText('3 of 3 items selected')).toBeInTheDocument();
    });

    it('should disable create button when no items selected', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} />);

      fireEvent.click(screen.getByText('Deselect All'));

      const createButton = screen.getByRole('button', { name: /create/i });
      expect(createButton).toBeDisabled();
    });
  });

  describe('Empty state', () => {
    it('should show no items found message for empty extraction', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} items={[]} />);

      expect(screen.getByText('No maintenance items found')).toBeInTheDocument();
      expect(screen.getByText(/did not contain any recognizable/)).toBeInTheDocument();

      // Should show Close button instead of Create
      expect(screen.getByText('Close')).toBeInTheDocument();
      expect(screen.queryByText(/Create/)).not.toBeInTheDocument();
    });
  });

  describe('Schedule creation', () => {
    it('should create selected schedules on button click', async () => {
      mockMutateAsync.mockResolvedValue([{ id: '1' }, { id: '2' }, { id: '3' }]);

      render(<MaintenanceScheduleReviewScreen {...defaultProps} />);

      fireEvent.click(screen.getByRole('button', { name: /create 3 schedules/i }));

      expect(mockMutateAsync).toHaveBeenCalledWith({
        vehicleId: 'vehicle-123',
        items: expect.arrayContaining([
          expect.objectContaining({ service: 'Engine Oil Change', selected: true }),
          expect.objectContaining({ service: 'Tire Rotation', selected: true }),
          expect.objectContaining({ service: 'Cabin Air Filter Replacement', selected: true }),
        ]),
      });
    });

    it('should only create selected items', async () => {
      mockMutateAsync.mockResolvedValue([{ id: '1' }]);

      render(<MaintenanceScheduleReviewScreen {...defaultProps} />);

      // Deselect last two items
      const checkboxes = screen.getAllByRole('checkbox');
      fireEvent.click(checkboxes[1]);
      fireEvent.click(checkboxes[2]);

      fireEvent.click(screen.getByRole('button', { name: /create 1 schedule$/i }));

      expect(mockMutateAsync).toHaveBeenCalledWith({
        vehicleId: 'vehicle-123',
        items: expect.arrayContaining([
          expect.objectContaining({ service: 'Engine Oil Change', selected: true }),
        ]),
      });
      // Should not include unselected items
      const callArgs = mockMutateAsync.mock.calls[0][0];
      expect(callArgs.items).toHaveLength(1);
    });

    it('should show error on creation failure', async () => {
      mockMutateAsync.mockRejectedValue(new Error('Network error'));

      render(<MaintenanceScheduleReviewScreen {...defaultProps} />);

      fireEvent.click(screen.getByRole('button', { name: /create 3 schedules/i }));

      // Wait for error to appear (async mutation)
      await screen.findByText('Network error');
    });
  });

  describe('Editing', () => {
    it('should update item data via inline editing', async () => {
      mockMutateAsync.mockResolvedValue([{ id: '1' }]);

      render(<MaintenanceScheduleReviewScreen {...defaultProps} />);

      // Click on the Months field of the third item (unique value: 12 mo)
      const monthsField = screen.getByText('12 mo');
      fireEvent.click(monthsField);

      // Find the input that appeared and change its value
      const monthsInput = screen.getByDisplayValue('12');
      fireEvent.change(monthsInput, { target: { value: '24' } });
      fireEvent.keyDown(monthsInput, { key: 'Enter' });

      // Deselect items 1 and 2 to only create the edited item
      const checkboxes = screen.getAllByRole('checkbox');
      fireEvent.click(checkboxes[0]);
      fireEvent.click(checkboxes[1]);

      // Create the schedule and verify updated value is used
      fireEvent.click(screen.getByRole('button', { name: /create 1 schedule$/i }));

      expect(mockMutateAsync).toHaveBeenCalledWith({
        vehicleId: 'vehicle-123',
        items: [expect.objectContaining({
          service: 'Cabin Air Filter Replacement',
          intervalMonths: 24,
        })],
      });
    });
  });

  describe('Subtype validation', () => {
    it('should disable create button when selected item has empty subtypes', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} items={sampleItemsWithEmptySubtypes} />);

      // All 4 items selected, but Brake Fluid has no subtypes
      const createButton = screen.getByRole('button', { name: /create/i });
      expect(createButton).toBeDisabled();
    });

    it('should enable create button after deselecting item with empty subtypes', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} items={sampleItemsWithEmptySubtypes} />);

      // Deselect the 4th item (Brake Fluid with empty subtypes)
      const checkboxes = screen.getAllByRole('checkbox');
      fireEvent.click(checkboxes[3]);

      const createButton = screen.getByRole('button', { name: /create 3 schedules/i });
      expect(createButton).not.toBeDisabled();
    });

    it('should show warning alert for items missing subtypes', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} items={sampleItemsWithEmptySubtypes} />);

      expect(screen.getByText(/missing subtypes/)).toBeInTheDocument();
    });

    it('should hide warning alert after deselecting items with empty subtypes', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} items={sampleItemsWithEmptySubtypes} />);

      // Deselect the Brake Fluid item
      const checkboxes = screen.getAllByRole('checkbox');
      fireEvent.click(checkboxes[3]);

      expect(screen.queryByText(/missing subtypes/)).not.toBeInTheDocument();
    });
  });

  describe('Interval validation', () => {
    it('should disable create button when selected item has no intervals', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} items={sampleItemsWithMissingIntervals} />);

      const createButton = screen.getByRole('button', { name: /create/i });
      expect(createButton).toBeDisabled();
    });

    it('should enable create button after deselecting item with missing intervals', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} items={sampleItemsWithMissingIntervals} />);

      // Deselect the 4th item (Coolant Flush with null intervals)
      const checkboxes = screen.getAllByRole('checkbox');
      fireEvent.click(checkboxes[3]);

      const createButton = screen.getByRole('button', { name: /create 3 schedules/i });
      expect(createButton).not.toBeDisabled();
    });

    it('should show warning alert for items missing intervals', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} items={sampleItemsWithMissingIntervals} />);

      expect(screen.getByText(/missing intervals/)).toBeInTheDocument();
    });

    it('should enable create button after editing interval on item', () => {
      render(<MaintenanceScheduleReviewScreen {...defaultProps} items={sampleItemsWithMissingIntervals} />);

      // The Coolant Flush item shows '-' for both intervals. Click the Miles '-' to edit.
      // There are multiple '-' on screen, so find all and pick the right one.
      const dashTexts = screen.getAllByText('-');
      // Click the first dash (Miles field of the Coolant Flush item - last item's first dash)
      fireEvent.click(dashTexts[dashTexts.length - 2]);

      // Type a value and save
      const input = screen.getByDisplayValue('');
      fireEvent.change(input, { target: { value: '50000' } });
      fireEvent.keyDown(input, { key: 'Enter' });

      const createButton = screen.getByRole('button', { name: /create 4 schedules/i });
      expect(createButton).not.toBeDisabled();
    });
  });

  describe('Responsive layout', () => {
    afterEach(() => {
      // Reset matchMedia after each test
      mockMatchMedia(false);
    });

    it('should render in fullscreen mode on mobile viewports', () => {
      // Simulate mobile: breakpoints.down('sm') returns true
      mockMatchMedia(true);

      render(<MaintenanceScheduleReviewScreen {...defaultProps} />);

      // On mobile, dialog renders with fullScreen prop - check that the MuiDialog-paperFullScreen
      // class is applied. MUI renders the dialog in a portal, so query from document.
      const paper = document.querySelector('.MuiDialog-paperFullScreen');
      expect(paper).not.toBeNull();
    });

    it('should render as modal dialog on desktop viewports', () => {
      // Simulate desktop: breakpoints.down('sm') returns false
      mockMatchMedia(false);

      render(<MaintenanceScheduleReviewScreen {...defaultProps} />);

      // On desktop, dialog should NOT have fullScreen class
      const fullScreenPaper = document.querySelector('.MuiDialog-paperFullScreen');
      expect(fullScreenPaper).toBeNull();

      // But the dialog should still render
      expect(screen.getByText('Extracted Maintenance Schedules')).toBeInTheDocument();
    });
  });
});
