import { describe, it, expect, vi, beforeEach } from 'vitest';
import { render, screen, fireEvent } from '@testing-library/react';
import { FirmwareErrorView } from '@/components/firmware/firmware-error-view';
import type { FirmwareProgressEvent, FirmwareReason } from '@/types/device';

/**
 * M9-4 第 2 輪修改補測（Reviewer M5）：
 * 驗證 destructive vs recoverable reason 在 FirmwareErrorView 的 UI 差異。
 *
 * 涵蓋：
 *   - destructive reason 顯示 brick warning
 *   - destructive reason 不顯示 Retry 按鈕、改顯示 ContactSupport 按鈕（enabled、Reviewer M6 已修）
 *   - recoverable reason 顯示 Retry 按鈕（onRetry 有傳）
 *   - errorCode 顯示
 *   - 技術資訊 collapsible 預設收合
 *   - ContactSupport 按鈕點擊會 trigger window.open（mailto:）
 */

function makeEvent(overrides: Partial<FirmwareProgressEvent> = {}): FirmwareProgressEvent {
  return {
    type: 'firmware_progress',
    deviceId: 'dev-1',
    stage: 'error',
    percent: -1,
    elapsedMs: 12000,
    errorCode: 'FW_E102',
    rawError: 'kp_update_kdp_firmware: timeout',
    ...overrides,
  };
}

beforeEach(() => {
  // window.open mock — JSDOM 預設有 window.open、但回傳 null（不會真開新分頁）。
  vi.spyOn(window, 'open').mockImplementation(() => null);
});

describe('FirmwareErrorView — destructive reasons (brick warning + ContactSupport)', () => {
  const destructiveReasons: FirmwareReason[] = [
    'disconnect_during_op',
    'verify_mismatch',
    'verify_not_found',
  ];

  it.each(destructiveReasons)(
    'reason=%s 顯示 brick warning + ContactSupport（不顯示 Retry）',
    (reason) => {
      const onClose = vi.fn();
      const onRetry = vi.fn();
      render(
        <FirmwareErrorView
          progress={makeEvent({ reason })}
          onRetry={onRetry}
          onClose={onClose}
        />,
      );

      // brick warning（role="note"）
      const note = screen.getByRole('note');
      expect(note.textContent).toMatch(/損毀|damaged/i);

      // 不顯示 Retry / ReplugRetry / Rescan 按鈕
      // （ContactSupport 為 destructive variant、唯一 primary action）
      const buttons = screen.getAllByRole('button');
      const labels = buttons.map((b) => b.textContent || '');
      expect(labels.some((l) => /Retry|重試/.test(l))).toBe(false);
      expect(labels.some((l) => /Contact|聯絡技術支援|Support/.test(l))).toBe(true);
    },
  );

  it('ContactSupport 按鈕點擊會開 mailto: handler（不再 disabled）', () => {
    const onClose = vi.fn();
    render(
      <FirmwareErrorView
        progress={makeEvent({ reason: 'verify_mismatch' })}
        onClose={onClose}
      />,
    );

    const contactBtn = screen.getByRole('button', { name: /Contact|聯絡技術支援|Support/ });
    expect((contactBtn as HTMLButtonElement).disabled).toBe(false);

    fireEvent.click(contactBtn);
    expect(window.open).toHaveBeenCalled();
    const [href] = (window.open as ReturnType<typeof vi.fn>).mock.calls[0];
    expect(typeof href).toBe('string');
    expect(href).toMatch(/^mailto:/);
    // body 應該帶上技術資訊
    expect(decodeURIComponent(href)).toContain('stage: error');
    expect(decodeURIComponent(href)).toContain('reason: verify_mismatch');
  });
});

describe('FirmwareErrorView — recoverable reasons show Retry button', () => {
  it('reason=connect_failed 顯示 Retry 按鈕、不顯示 brick warning', () => {
    const onClose = vi.fn();
    const onRetry = vi.fn();
    render(
      <FirmwareErrorView
        progress={makeEvent({ reason: 'connect_failed' })}
        onRetry={onRetry}
        onClose={onClose}
      />,
    );

    // 沒有 brick warning role=note
    expect(screen.queryByRole('note')).toBeNull();

    // 顯示 Retry primary action 按鈕
    const retryBtn = screen.getByRole('button', { name: /Retry|重試|插拔/ });
    expect(retryBtn).toBeTruthy();
    fireEvent.click(retryBtn);
    expect(onRetry).toHaveBeenCalledTimes(1);
  });

  it('reason=scan_not_found 顯示 ReplugRetry 動作', () => {
    const onClose = vi.fn();
    const onRetry = vi.fn();
    render(
      <FirmwareErrorView
        progress={makeEvent({ reason: 'scan_not_found' })}
        onRetry={onRetry}
        onClose={onClose}
      />,
    );
    const btn = screen.getByRole('button', { name: /插拔|Unplug and retry/ });
    expect(btn).toBeTruthy();
  });
});

describe('FirmwareErrorView — common UI elements', () => {
  it('顯示 errorCode（mono 字型小字）', () => {
    render(
      <FirmwareErrorView
        progress={makeEvent({ errorCode: 'FW_E102', reason: 'upgrade_mid_failed' })}
        onClose={vi.fn()}
      />,
    );
    // errorCode 同時出現在「錯誤代碼」<p> 與技術資訊 <pre>、用 getAllByText 確保至少 1 個。
    expect(screen.getAllByText(/FW_E102/).length).toBeGreaterThanOrEqual(1);
  });

  it('技術資訊 collapsible 預設收合', () => {
    const { container } = render(
      <FirmwareErrorView progress={makeEvent({ reason: 'connect_failed' })} onClose={vi.fn()} />,
    );
    const details = container.querySelector('details');
    expect(details).not.toBeNull();
    expect((details as HTMLDetailsElement).open).toBe(false);
  });

  it('Close 按鈕觸發 onClose callback', () => {
    const onClose = vi.fn();
    render(
      <FirmwareErrorView
        progress={makeEvent({ reason: 'connect_failed' })}
        onRetry={vi.fn()}
        onClose={onClose}
      />,
    );
    const closeBtn = screen.getByRole('button', { name: /Close|關閉/ });
    fireEvent.click(closeBtn);
    expect(onClose).toHaveBeenCalledTimes(1);
  });
});
