import React from "react";
import { render, fireEvent, act, waitFor } from "@testing-library/react-native";

const mockCamera = {
  granted: true,
  requestResult: { granted: true } as { granted: boolean },
  lastOnBarcodeScanned: null as null | ((ev: { data: string }) => void),
};

jest.mock("expo-camera", () => {
  const ReactLocal = require("react");
  const { View } = require("react-native");
  const CameraView = (props: { onBarcodeScanned?: (e: { data: string }) => void }) => {
    mockCamera.lastOnBarcodeScanned = props.onBarcodeScanned ?? null;
    return ReactLocal.createElement(View, null);
  };
  return {
    CameraView,
    useCameraPermissions: () => [
      { granted: mockCamera.granted },
      jest.fn().mockResolvedValue(mockCamera.requestResult),
    ],
  };
});

import OnboardingScreen from "../../../src/features/onboarding/OnboardingScreen";

const baseProps = {
  appDisplayName: "MissioFlow",
  brandColor: "#1E56A8",
  logoUrl: null as string | null,
  instanceUrl: "",
  onboardingError: null as string | null,
  validatingInstance: false,
  onChangeInstanceUrl: jest.fn(),
  onSaveEnvironment: jest.fn(),
  onScanPayload: jest.fn().mockResolvedValue(undefined),
  savedInstances: [] as never[],
  onSelectInstance: jest.fn(),
  onRemoveInstance: jest.fn(),
};

describe("OnboardingScreen", () => {
  beforeEach(() => {
    mockCamera.granted = true;
    mockCamera.requestResult = { granted: true };
    mockCamera.lastOnBarcodeScanned = null;
    baseProps.onChangeInstanceUrl = jest.fn();
    baseProps.onSaveEnvironment = jest.fn();
    baseProps.onScanPayload = jest.fn().mockResolvedValue(undefined);
  });

  it("rendu de base", () => {
    const { getByText, getByPlaceholderText } = render(<OnboardingScreen {...baseProps} />);
    expect(getByText("MissioFlow")).toBeTruthy();
    expect(getByText("Enregistrer URL")).toBeTruthy();
    expect(getByText("Scanner QR")).toBeTruthy();
    expect(getByPlaceholderText(/instance.example.com/)).toBeTruthy();
  });

  it("logoUrl affiche Image", () => {
    const { UNSAFE_getAllByType } = render(
      <OnboardingScreen {...baseProps} logoUrl="https://a.b/logo.png" />
    );
    const { Image } = require("react-native");
    expect(UNSAFE_getAllByType(Image).length).toBeGreaterThan(0);
  });

  it("onChangeInstanceUrl propage", () => {
    const onChange = jest.fn();
    const { getByPlaceholderText } = render(
      <OnboardingScreen {...baseProps} onChangeInstanceUrl={onChange} />
    );
    fireEvent.changeText(getByPlaceholderText(/instance/), "https://a.b");
    expect(onChange).toHaveBeenCalledWith("https://a.b");
  });

  it("onSaveEnvironment appele au clic Enregistrer", () => {
    const onSave = jest.fn();
    const { getByText } = render(
      <OnboardingScreen {...baseProps} onSaveEnvironment={onSave} />
    );
    fireEvent.press(getByText("Enregistrer URL"));
    expect(onSave).toHaveBeenCalled();
  });

  it("onboardingError affiche le message", () => {
    const { getByText } = render(
      <OnboardingScreen {...baseProps} onboardingError="Erreur" />
    );
    expect(getByText("Erreur")).toBeTruthy();
  });

  it("validatingInstance=true : texte + loader + bouton disabled", () => {
    const { getByText, UNSAFE_getByType } = render(
      <OnboardingScreen {...baseProps} validatingInstance={true} />
    );
    expect(getByText("Validation...")).toBeTruthy();
    expect(getByText("Validation de l'instance...")).toBeTruthy();
    const { ActivityIndicator } = require("react-native");
    expect(UNSAFE_getByType(ActivityIndicator)).toBeTruthy();
  });

  it("Scanner QR : permission accordee ouvre scanner", async () => {
    const { getByText } = render(<OnboardingScreen {...baseProps} />);
    await act(async () => {
      fireEvent.press(getByText("Scanner QR"));
    });
    expect(getByText("Fermer le scanner")).toBeTruthy();
  });

  it("Scanner QR : demande permission puis ouvre", async () => {
    mockCamera.granted = false;
    mockCamera.requestResult = { granted: true };
    const { getByText } = render(<OnboardingScreen {...baseProps} />);
    await act(async () => {
      fireEvent.press(getByText("Scanner QR"));
    });
    expect(getByText("Fermer le scanner")).toBeTruthy();
  });

  it("Scanner QR : permission refusee ne rien faire", async () => {
    mockCamera.granted = false;
    mockCamera.requestResult = { granted: false };
    const { getByText, queryByText } = render(<OnboardingScreen {...baseProps} />);
    await act(async () => {
      fireEvent.press(getByText("Scanner QR"));
    });
    expect(queryByText("Fermer le scanner")).toBeNull();
  });

  it("Fermer le scanner ferme", async () => {
    const { getByText, queryByText } = render(<OnboardingScreen {...baseProps} />);
    await act(async () => {
      fireEvent.press(getByText("Scanner QR"));
    });
    await act(async () => {
      fireEvent.press(getByText("Fermer le scanner"));
    });
    expect(queryByText("Fermer le scanner")).toBeNull();
  });

  it("Barcode scan -> appelle onScanPayload", async () => {
    const onScanPayload = jest.fn().mockResolvedValue(undefined);
    const { getByText } = render(
      <OnboardingScreen {...baseProps} onScanPayload={onScanPayload} />
    );
    await act(async () => {
      fireEvent.press(getByText("Scanner QR"));
    });
    await act(async () => {
      await mockCamera.lastOnBarcodeScanned?.({ data: "PAYLOAD" });
    });
    await waitFor(() => expect(onScanPayload).toHaveBeenCalledWith("PAYLOAD"));
  });

  it("Barcode scan double -> 2eme appel ignore (qrLocked)", async () => {
    const onScanPayload = jest.fn().mockResolvedValue(undefined);
    const { getByText } = render(
      <OnboardingScreen {...baseProps} onScanPayload={onScanPayload} />
    );
    await act(async () => {
      fireEvent.press(getByText("Scanner QR"));
    });
    await act(async () => {
      await mockCamera.lastOnBarcodeScanned?.({ data: "FIRST" });
    });
    await act(async () => {
      await mockCamera.lastOnBarcodeScanned?.({ data: "SECOND" });
    });
    expect(onScanPayload).toHaveBeenCalledTimes(1);
    expect(onScanPayload).toHaveBeenCalledWith("FIRST");
  });

  it("affiche les instances enregistrees et selectionne au tap", () => {
    const onSelect = jest.fn();
    const saved = [
      {
        base_url: "https://a.test",
        app_name: "Alpha Mobile",
        primary_color: "#111111",
        logo_url: null,
        tenant_id: "a",
        last_email: "tech@a.fr",
        saved_at: "",
      },
    ];
    const { getByText } = render(
      <OnboardingScreen {...baseProps} savedInstances={saved} onSelectInstance={onSelect} />
    );
    expect(getByText("Mes instances")).toBeTruthy();
    fireEvent.press(getByText("Alpha Mobile"));
    expect(onSelect).toHaveBeenCalledWith(saved[0]);
  });
});
