/**
 * Tests for the VirtualPrinterSettings component.
 *
 * Tests the virtual printer configuration UI including:
 * - Enable/disable toggle
 * - Access code management
 * - Archive mode selection
 * - Status display
 */

import { describe, it, expect, vi, beforeEach } from 'vitest';
import { screen, waitFor } from '@testing-library/react';
import userEvent from '@testing-library/user-event';
import { render } from '../utils';
import { VirtualPrinterSettings } from '../../components/VirtualPrinterSettings';

// Mock the API client
vi.mock('../../api/client', () => ({
  api: {
    getSettings: vi.fn().mockResolvedValue({}),
    updateSettings: vi.fn().mockResolvedValue({}),
    getPrinters: vi.fn().mockResolvedValue([]),
    getNetworkInterfaces: vi.fn().mockResolvedValue({ interfaces: [] }),
  },
  virtualPrinterApi: {
    getSettings: vi.fn(),
    updateSettings: vi.fn(),
    getModels: vi.fn().mockResolvedValue({
      models: {
        'BL-P001': 'X1C',
        'C12': 'P1S',
        'N7': 'P2S',
      },
    }),
  },
}));

// Import mocked module
import { virtualPrinterApi } from '../../api/client';

// Mock data factory
const createMockSettings = (overrides = {}) => ({
  enabled: false,
  access_code_set: false,
  mode: 'immediate' as const,
  model: 'BL-P001',
  target_printer_id: null as number | null,
  remote_interface_ip: null as string | null,
  status: {
    enabled: false,
    running: false,
    mode: 'immediate',
    name: 'Bambuddy',
    serial: '00M00A391800001',
    model: 'BL-P001',
    model_name: 'X1C',
    pending_files: 0,
  },
  ...overrides,
});

describe('VirtualPrinterSettings', () => {
  beforeEach(() => {
    vi.clearAllMocks();
    // Default mock implementation
    vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(createMockSettings());
    vi.mocked(virtualPrinterApi.updateSettings).mockResolvedValue(createMockSettings());
  });

  describe('rendering', () => {
    it('renders loading state initially', () => {
      // Delay the API response to catch loading state
      vi.mocked(virtualPrinterApi.getSettings).mockImplementation(
        () => new Promise(() => {}) // Never resolves
      );
      render(<VirtualPrinterSettings />);

      // Should show loading spinner
      expect(document.querySelector('.animate-spin')).toBeInTheDocument();
    });

    it('renders component title', async () => {
      render(<VirtualPrinterSettings />);

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

    it('renders enable toggle', async () => {
      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Enable Virtual Printer')).toBeInTheDocument();
      });
    });

    it('renders access code section', async () => {
      render(<VirtualPrinterSettings />);

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

    it('renders mode section', async () => {
      render(<VirtualPrinterSettings />);

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

    it('renders how it works info', async () => {
      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('How it works:')).toBeInTheDocument();
      });
    });
  });

  describe('status indicator', () => {
    it('shows Stopped when not running', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ status: { ...createMockSettings().status, running: false } })
      );

      render(<VirtualPrinterSettings />);

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

    it('shows Running when active', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({
          enabled: true,
          status: { ...createMockSettings().status, enabled: true, running: true },
        })
      );

      render(<VirtualPrinterSettings />);

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

    it('shows status details when running', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({
          enabled: true,
          status: {
            enabled: true,
            running: true,
            mode: 'immediate',
            name: 'Bambuddy',
            serial: '00M00A391800001',
            model: 'BL-P001',
            model_name: 'X1C',
            pending_files: 0,
          },
        })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Status Details')).toBeInTheDocument();
        expect(screen.getByText('Bambuddy')).toBeInTheDocument();
        expect(screen.getByText('00M00A391800001')).toBeInTheDocument();
      });
    });
  });

  describe('access code', () => {
    it('shows warning when access code not set', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ access_code_set: false })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('No access code set - required to enable')).toBeInTheDocument();
      });
    });

    it('shows success when access code is set', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ access_code_set: true })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Access code is set')).toBeInTheDocument();
      });
    });

    it('shows character count while typing', async () => {
      const user = userEvent.setup();
      render(<VirtualPrinterSettings />);

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

      const input = screen.getByPlaceholderText('Enter 8-char code');
      await user.type(input, '1234');

      expect(screen.getByText('(4/8)')).toBeInTheDocument();
    });

    it('saves access code on button click', async () => {
      const user = userEvent.setup();
      vi.mocked(virtualPrinterApi.updateSettings).mockResolvedValue(
        createMockSettings({ access_code_set: true })
      );

      render(<VirtualPrinterSettings />);

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

      const input = screen.getByPlaceholderText('Enter 8-char code');
      await user.type(input, '12345678');

      const saveButton = screen.getByRole('button', { name: 'Save' });
      await user.click(saveButton);

      await waitFor(() => {
        expect(virtualPrinterApi.updateSettings).toHaveBeenCalledWith({
          access_code: '12345678',
        });
      });
    });

    it('toggles password visibility', async () => {
      const user = userEvent.setup();
      render(<VirtualPrinterSettings />);

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

      const input = screen.getByPlaceholderText('Enter 8-char code');
      expect(input).toHaveAttribute('type', 'password');

      // Find and click the visibility toggle (eye icon button)
      const toggleButtons = screen.getAllByRole('button');
      const visibilityToggle = toggleButtons.find(
        (btn) => btn.querySelector('svg') && btn.className.includes('absolute')
      );

      if (visibilityToggle) {
        await user.click(visibilityToggle);
        expect(input).toHaveAttribute('type', 'text');
      }
    });
  });

  describe('mode selection', () => {
    it('renders Archive mode option', async () => {
      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Archive')).toBeInTheDocument();
        expect(screen.getByText('Archive files immediately')).toBeInTheDocument();
      });
    });

    it('renders Review mode option', async () => {
      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Review')).toBeInTheDocument();
        expect(screen.getByText('Review before archiving')).toBeInTheDocument();
      });
    });

    it('renders Queue mode option', async () => {
      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Queue')).toBeInTheDocument();
        expect(screen.getByText('Archive and add to queue')).toBeInTheDocument();
      });
    });

    it('highlights current mode (review)', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ mode: 'review' })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        const reviewButton = screen.getByText('Review').closest('button');
        expect(reviewButton?.className).toContain('border-bambu-green');
      });
    });

    it('highlights current mode (legacy queue maps to review)', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ mode: 'queue' })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        const reviewButton = screen.getByText('Review').closest('button');
        expect(reviewButton?.className).toContain('border-bambu-green');
      });
    });

    it('changes mode to review on click', async () => {
      const user = userEvent.setup();
      vi.mocked(virtualPrinterApi.updateSettings).mockResolvedValue(
        createMockSettings({ mode: 'review' })
      );

      render(<VirtualPrinterSettings />);

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

      const reviewButton = screen.getByText('Review').closest('button');
      if (reviewButton) {
        await user.click(reviewButton);
      }

      await waitFor(() => {
        expect(virtualPrinterApi.updateSettings).toHaveBeenCalledWith({ mode: 'review' });
      });
    });

    it('changes mode to print_queue on click', async () => {
      const user = userEvent.setup();
      vi.mocked(virtualPrinterApi.updateSettings).mockResolvedValue(
        createMockSettings({ mode: 'print_queue' })
      );

      render(<VirtualPrinterSettings />);

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

      const queueButton = screen.getByText('Queue').closest('button');
      if (queueButton) {
        await user.click(queueButton);
      }

      await waitFor(() => {
        expect(virtualPrinterApi.updateSettings).toHaveBeenCalledWith({ mode: 'print_queue' });
      });
    });
  });

  describe('enable/disable toggle', () => {
    it('cannot enable without access code', async () => {
      const user = userEvent.setup();
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ enabled: false, access_code_set: false })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Enable Virtual Printer')).toBeInTheDocument();
      });

      // Find the toggle switch (it's a button with relative class containing the slider)
      const allButtons = screen.getAllByRole('button');
      const toggle = allButtons.find((btn) => btn.className.includes('rounded-full') && btn.className.includes('w-12'));

      if (toggle) {
        await user.click(toggle);
      }

      // Should not call update API (no access code set)
      expect(virtualPrinterApi.updateSettings).not.toHaveBeenCalled();
    });

    it('can enable when access code is set', async () => {
      const user = userEvent.setup();
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ enabled: false, access_code_set: true })
      );
      vi.mocked(virtualPrinterApi.updateSettings).mockResolvedValue(
        createMockSettings({ enabled: true, access_code_set: true })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Enable Virtual Printer')).toBeInTheDocument();
      });

      // Find the toggle switch (it's a button with rounded-full and w-12 classes)
      const allButtons = screen.getAllByRole('button');
      const toggle = allButtons.find((btn) => btn.className.includes('rounded-full') && btn.className.includes('w-12'));

      expect(toggle).toBeDefined();
      if (toggle) {
        await user.click(toggle);
      }

      await waitFor(() => {
        expect(virtualPrinterApi.updateSettings).toHaveBeenCalledWith(
          expect.objectContaining({ enabled: true })
        );
      });
    });

    it('can disable when enabled', async () => {
      const user = userEvent.setup();
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ enabled: true, access_code_set: true })
      );
      vi.mocked(virtualPrinterApi.updateSettings).mockResolvedValue(
        createMockSettings({ enabled: false, access_code_set: true })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Enable Virtual Printer')).toBeInTheDocument();
      });

      // Find the toggle switch
      const allButtons = screen.getAllByRole('button');
      const toggle = allButtons.find((btn) => btn.className.includes('rounded-full') && btn.className.includes('w-12'));

      expect(toggle).toBeDefined();
      if (toggle) {
        await user.click(toggle);
      }

      await waitFor(() => {
        expect(virtualPrinterApi.updateSettings).toHaveBeenCalledWith(
          expect.objectContaining({ enabled: false })
        );
      });
    });
  });

  describe('info section', () => {
    it('shows setup required warning', async () => {
      render(<VirtualPrinterSettings />);

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

    it('shows link to setup guide', async () => {
      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Read the setup guide before enabling')).toBeInTheDocument();
      });
    });

    it('shows how it works section', async () => {
      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('How it works:')).toBeInTheDocument();
        expect(screen.getByText(/virtual printers appear in your slicer/)).toBeInTheDocument();
      });
    });
  });

  describe('proxy mode', () => {
    it('renders Proxy mode option', async () => {
      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Proxy')).toBeInTheDocument();
        expect(screen.getByText('Relay to real printer')).toBeInTheDocument();
      });
    });

    it('highlights proxy mode when selected', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ mode: 'proxy', target_printer_id: 1 })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        const proxyButton = screen.getByText('Proxy').closest('button');
        expect(proxyButton?.className).toContain('border-blue-500');
      });
    });

    it('shows proxy status details when running in proxy mode', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({
          enabled: true,
          mode: 'proxy',
          target_printer_id: 1,
          status: {
            enabled: true,
            running: true,
            mode: 'proxy',
            name: 'Bambuddy (Proxy)',
            serial: '00M00A391800001',
            model: 'BL-P001',
            model_name: 'X1C',
            pending_files: 0,
            proxy: {
              running: true,
              target_host: '192.168.1.100',
              ftp_port: 990,  // Privileged port for Bambu Studio compatibility
              mqtt_port: 8883,
              ftp_connections: 1,
              mqtt_connections: 2,
            },
          },
        })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Running')).toBeInTheDocument();
        expect(screen.getByText('Status Details')).toBeInTheDocument();
        // IP address appears in multiple places (target printer and status details)
        expect(screen.getAllByText('192.168.1.100').length).toBeGreaterThan(0);
      });
    });

    it('shows target printer dropdown in proxy mode', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ mode: 'proxy' })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Target Printer')).toBeInTheDocument();
        expect(screen.getByText('Select a printer...')).toBeInTheDocument();
      });
    });

    it('changes mode to proxy on click', async () => {
      const user = userEvent.setup();
      vi.mocked(virtualPrinterApi.updateSettings).mockResolvedValue(
        createMockSettings({ mode: 'proxy' })
      );

      render(<VirtualPrinterSettings />);

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

      const proxyButton = screen.getByText('Proxy').closest('button');
      if (proxyButton) {
        await user.click(proxyButton);
      }

      await waitFor(() => {
        expect(virtualPrinterApi.updateSettings).toHaveBeenCalledWith({ mode: 'proxy' });
      });
    });
  });

  describe('network interface override', () => {
    it('shows interface dropdown when enabled in immediate mode', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ enabled: true, mode: 'immediate' })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Network Interface Override')).toBeInTheDocument();
      });
    });

    it('shows interface dropdown when enabled in review mode', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ enabled: true, mode: 'review' })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Network Interface Override')).toBeInTheDocument();
      });
    });

    it('shows interface dropdown when enabled in print_queue mode', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ enabled: true, mode: 'print_queue' })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Network Interface Override')).toBeInTheDocument();
      });
    });

    it('shows interface dropdown when enabled in proxy mode', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ enabled: true, mode: 'proxy', target_printer_id: 1 })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Network Interface Override')).toBeInTheDocument();
      });
    });

    it('hides interface dropdown when disabled', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ enabled: false, mode: 'immediate' })
      );

      render(<VirtualPrinterSettings />);

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

      expect(screen.queryByText('Network Interface Override')).not.toBeInTheDocument();
    });

    it('shows configured status when interface is set', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ enabled: true, mode: 'immediate', remote_interface_ip: '10.0.0.50' })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText('Interface override active')).toBeInTheDocument();
      });
    });

    it('shows optional hint when no interface is set', async () => {
      vi.mocked(virtualPrinterApi.getSettings).mockResolvedValue(
        createMockSettings({ enabled: true, mode: 'immediate', remote_interface_ip: '' })
      );

      render(<VirtualPrinterSettings />);

      await waitFor(() => {
        expect(screen.getByText(/Optional.*auto-detected IP/)).toBeInTheDocument();
      });
    });
  });
});
