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

const mockSig = {
  // Map pad par ordre de creation -> {onOK, onEmpty}
  pads: [] as Array<{ onOK?: (d: string) => void; onEmpty?: () => void; readSignature: () => void }>,
};

jest.mock("react-native-signature-canvas", () => {
  const ReactLocal = require("react") as typeof import("react");
  const { View } = require("react-native");
  function SignatureCanvas(
    props: { onOK?: (d: string) => void; onEmpty?: () => void; dataURL?: string },
    ref: React.Ref<{ readSignature: () => void }>
  ) {
    const idxRef = ReactLocal.useRef<number>(-1);
    if (idxRef.current === -1) {
      idxRef.current = mockSig.pads.length;
      mockSig.pads.push({
        onOK: props.onOK,
        onEmpty: props.onEmpty,
        readSignature: () => {},
      });
    } else {
      mockSig.pads[idxRef.current].onOK = props.onOK;
      mockSig.pads[idxRef.current].onEmpty = props.onEmpty;
    }

    ReactLocal.useImperativeHandle(ref, () => ({
      readSignature: () => {
        // Par defaut ne fait rien — les tests appellent onOK/onEmpty manuellement
      },
    }));
    return ReactLocal.createElement(View, null);
  }
  return { __esModule: true, default: ReactLocal.forwardRef(SignatureCanvas) };
});

import SignatureFinishCard from "../../../src/features/missions/SignatureFinishCard";

const baseProps = {
  brandColor: "#1E56A8",
  saving: false,
  errorMessage: null as string | null,
  onCancel: jest.fn(),
  onConfirm: jest.fn(),
};

describe("SignatureFinishCard", () => {
  beforeEach(() => {
    mockSig.pads = [];
    baseProps.onCancel = jest.fn();
    baseProps.onConfirm = jest.fn();
  });

  it("affiche l'etape tech par defaut", () => {
    const { getByText } = render(<SignatureFinishCard {...baseProps} />);
    expect(getByText("Signature du technicien")).toBeTruthy();
    expect(getByText("1/3 Technicien")).toBeTruthy();
  });

  it("bouton Annuler appelle onCancel", () => {
    const onCancel = jest.fn();
    const { getByText } = render(<SignatureFinishCard {...baseProps} onCancel={onCancel} />);
    fireEvent.press(getByText("← Annuler"));
    expect(onCancel).toHaveBeenCalled();
  });

  it("tech: Suivant sans signature -> affiche erreur via onEmpty", async () => {
    const { getByText, findByText } = render(<SignatureFinishCard {...baseProps} />);
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      mockSig.pads[0].onEmpty?.();
    });
    await findByText(/avant de passer a l'etape suivante/);
  });

  it("tech: Suivant avec signature -> onOK puis passe a client_presence", async () => {
    const { getByText } = render(<SignatureFinishCard {...baseProps} />);
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      mockSig.pads[0].onOK?.("TECH_SIG");
    });
    await waitFor(() => expect(getByText("2/3 Client")).toBeTruthy());
  });

  it("client_presence: client absent -> appelle onConfirm avec ABSENT", async () => {
    const onConfirm = jest.fn();
    const { getByText } = render(<SignatureFinishCard {...baseProps} onConfirm={onConfirm} />);
    // tech -> onOK -> client_presence
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      mockSig.pads[0].onOK?.("TECH_SIG");
    });
    // Select "Client absent"
    await act(async () => {
      fireEvent.press(getByText("✗ Client absent"));
    });
    await act(async () => {
      fireEvent.press(getByText("✅ Terminer (client absent)"));
    });
    expect(onConfirm).toHaveBeenCalledWith({
      signature_technicien: "TECH_SIG",
      signature_client: "ABSENT",
      client_present: false,
    });
  });

  it("client_presence: client present -> passe a client_sig", async () => {
    const { getByText } = render(<SignatureFinishCard {...baseProps} />);
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      mockSig.pads[0].onOK?.("TECH_SIG");
    });
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await waitFor(() => expect(getByText("3/3 Signature client")).toBeTruthy());
  });

  it("client_sig: Confirmer sans signature -> onEmpty + erreur", async () => {
    const { getByText, findByText } = render(<SignatureFinishCard {...baseProps} />);
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      mockSig.pads[0].onOK?.("TECH_SIG");
    });
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      fireEvent.press(getByText("✅ Confirmer et terminer"));
    });
    await act(async () => {
      mockSig.pads[1].onEmpty?.();
    });
    await findByText(/Le client doit signer/);
  });

  it("client_sig: Confirmer avec signature -> onConfirm avec les 2 sigs", async () => {
    const onConfirm = jest.fn();
    const { getByText } = render(<SignatureFinishCard {...baseProps} onConfirm={onConfirm} />);
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      mockSig.pads[0].onOK?.("TECH_SIG");
    });
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      fireEvent.press(getByText("✅ Confirmer et terminer"));
    });
    await act(async () => {
      mockSig.pads[1].onOK?.("CLIENT_SIG");
    });
    await waitFor(() =>
      expect(onConfirm).toHaveBeenCalledWith({
        signature_technicien: "TECH_SIG",
        signature_client: "CLIENT_SIG",
        client_present: true,
      })
    );
  });

  it("Revenir depuis client_presence -> retour tech", async () => {
    const { getByText } = render(<SignatureFinishCard {...baseProps} />);
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      mockSig.pads[0].onOK?.("TECH_SIG");
    });
    await act(async () => {
      fireEvent.press(getByText("← Revenir"));
    });
    expect(getByText("1/3 Technicien")).toBeTruthy();
  });

  it("Revenir depuis client_sig -> retour client_presence", async () => {
    const { getByText } = render(<SignatureFinishCard {...baseProps} />);
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      mockSig.pads[0].onOK?.("TECH_SIG");
    });
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      fireEvent.press(getByText("← Revenir"));
    });
    expect(getByText("2/3 Client")).toBeTruthy();
  });

  it("affiche errorMessage prop", () => {
    const { getByText } = render(
      <SignatureFinishCard {...baseProps} errorMessage="Erreur serveur" />
    );
    expect(getByText("Erreur serveur")).toBeTruthy();
  });

  it("tech saving=true applique style buttonDisabled", () => {
    const { getByText } = render(<SignatureFinishCard {...baseProps} saving={true} />);
    // Le bouton est toujours rendu (texte "Suivant →"), saving applique le style disabled
    expect(getByText("Suivant →")).toBeTruthy();
  });

  it("saving=true affiche ActivityIndicator sur presence/client_sig", async () => {
    const { getByText, UNSAFE_getByType, rerender } = render(
      <SignatureFinishCard {...baseProps} />
    );
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      mockSig.pads[0].onOK?.("TECH_SIG");
    });
    // Maintenant sur client_presence, saving=true
    rerender(<SignatureFinishCard {...baseProps} saving={true} />);
    const { ActivityIndicator } = require("react-native");
    expect(UNSAFE_getByType(ActivityIndicator)).toBeTruthy();
  });

  it("saving=true sur client_sig affiche ActivityIndicator", async () => {
    const { getByText, UNSAFE_getByType, rerender } = render(
      <SignatureFinishCard {...baseProps} />
    );
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      mockSig.pads[0].onOK?.("TECH_SIG");
    });
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    rerender(<SignatureFinishCard {...baseProps} saving={true} />);
    const { ActivityIndicator } = require("react-native");
    expect(UNSAFE_getByType(ActivityIndicator)).toBeTruthy();
  });

  it("initialTechData pre-remplit, draft callback invoque", () => {
    const onDraftChange = jest.fn();
    render(
      <SignatureFinishCard
        {...baseProps}
        initialTechData="INIT_TECH"
        initialClientData="INIT_CLIENT"
        initialClientPresent={false}
        onDraftChange={onDraftChange}
      />
    );
    expect(onDraftChange).toHaveBeenCalledWith(
      expect.objectContaining({
        techData: "INIT_TECH",
        clientData: "INIT_CLIENT",
        clientPresent: false,
      })
    );
  });

  it("dataURL prop None quand initialTechData vide", () => {
    // Ce test verifie qu'aucun crash quand initialTechData est "" (branche || undefined)
    const { getByText } = render(
      <SignatureFinishCard {...baseProps} initialTechData="" />
    );
    expect(getByText("Signature du technicien")).toBeTruthy();
  });

  it("onEmpty sans pendingAction -> efface juste techData (branche negative)", async () => {
    const { getByText } = render(<SignatureFinishCard {...baseProps} initialTechData="OLD" />);
    await act(async () => {
      mockSig.pads[0].onEmpty?.();
    });
    // Pas d'erreur affichee car pas de pendingAction
    expect(() => getByText(/Signez dans le cadre avant/)).toThrow();
  });

  it("click 'Client present' apres 'Client absent' rebascule state", async () => {
    const { getByText } = render(
      <SignatureFinishCard {...baseProps} initialClientPresent={false} />
    );
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      mockSig.pads[0].onOK?.("TECH_SIG");
    });
    // Sur client_presence, initialement clientPresent=false
    await act(async () => {
      fireEvent.press(getByText("✓ Client present"));
    });
    // Le bouton "Suivant" doit apparaitre (pas "Terminer")
    expect(getByText("Suivant →")).toBeTruthy();
  });

  it("client_sig onEmpty sans pending -> efface clientData", async () => {
    const { getByText } = render(<SignatureFinishCard {...baseProps} />);
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    await act(async () => {
      mockSig.pads[0].onOK?.("TECH_SIG");
    });
    await act(async () => {
      fireEvent.press(getByText("Suivant →"));
    });
    // Pas de pending_confirm -> juste clear
    await act(async () => {
      mockSig.pads[1].onEmpty?.();
    });
    expect(getByText("3/3 Signature client")).toBeTruthy();
  });
});
