// Encounter characterization. Lock setDoc path + payload on encounter actions.

import React from 'react';
import { screen, fireEvent, waitFor } from '@testing-library/react';
import '@testing-library/jest-dom';
import { getCalls } from '../__mocks__/firebase/_mock-db';
import { renderApp, createCampaignViaUI, selectCampaignByName, createEncounterViaUI, selectEncounterByName } from './testHelpers';

function findCall(fn, pathSub) {
  return getCalls().find(c => c.fn === fn && (pathSub ? c.path.includes(pathSub) : true));
}
function findCalls(fn, pathSub) {
  return getCalls().filter(c => c.fn === fn && (pathSub ? c.path.includes(pathSub) : true));
}

async function setupCampaignAndEncounter(campName, encName) {
  await renderApp();
  await createCampaignViaUI(campName);
  await selectCampaignByName(campName);
  await createEncounterViaUI(encName);
}

describe('Encounter -> Firebase', () => {
  test('createEncounter: setDoc with encounter path + payload', async () => {
    await setupCampaignAndEncounter('Camp E', 'Boss Fight');
    const call = findCall('setDoc', '/encounters/');
    expect(call.path).toMatch(/encounters\/.+$/);
    expect(call.data).toMatchObject({
      name: 'Boss Fight',
      participants: [],
      round: 0,
      currentTurnParticipantId: null,
      isStarted: false,
      isPaused: false,
    });
    expect(call.data).toHaveProperty('createdAt');
  });

  test('createEncounter: path nested under campaign', async () => {
    await setupCampaignAndEncounter('Camp N', 'Enc N');
    const call = findCall('setDoc', '/encounters/');
    expect(call.path).toMatch(/campaigns\/[^/]+\/encounters\//);
  });

  test('togglePlayerDisplay: setDoc{merge} patch on activeDisplay/status', async () => {
    await setupCampaignAndEncounter('Camp D', 'Enc D');
    await selectEncounterByName('Enc D');

    // Eye button (icon-only, title attr)
    const eyeBtn = await screen.findByTitle('Activate for Player Display');
    fireEvent.click(eyeBtn);

    await waitFor(() => findCall('setDoc', 'activeDisplay/status'));
    const call = findCall('setDoc', 'activeDisplay/status');
    // main truth: setDoc{merge} patch, not replace (would clobber fields)
    expect(call.data).toMatchObject({
      activeCampaignId: expect.any(String),
      activeEncounterId: expect.any(String),
    });
  });

  test('togglePlayerDisplay off: setDoc{merge} nulls active ids', async () => {
    await setupCampaignAndEncounter('Camp O', 'Enc O');
    await selectEncounterByName('Enc O');

    // turn ON
    const onBtn = await screen.findByTitle('Activate for Player Display');
    fireEvent.click(onBtn);
    await waitFor(() => findCall('setDoc', 'activeDisplay/status'));

    // turn OFF
    const offBtn = await screen.findByTitle('Deactivate for Player Display');
    fireEvent.click(offBtn);
    await waitFor(() => {
      const calls = findCalls('setDoc', 'activeDisplay/status');
      const last = calls[calls.length - 1];
      return last.data.activeCampaignId === null;
    });
    const calls = findCalls('setDoc', 'activeDisplay/status');
    const last = calls[calls.length - 1];
    expect(last.data).toMatchObject({ activeCampaignId: null, activeEncounterId: null });
  });

  test('deleteEncounter: deleteDoc on encounter path', async () => {
    await setupCampaignAndEncounter('Camp X', 'Enc X');
    await selectEncounterByName('Enc X');

    // trash icon on encounter card
    const trashBtn = screen.getAllByTitle('Delete Encounter')[0];
    fireEvent.click(trashBtn);
    // confirm modal
    fireEvent.click(await screen.findByRole('button', { name: /Confirm/i }));

    await waitFor(() => findCall('deleteDoc', '/encounters/'));
    const del = findCall('deleteDoc', '/encounters/');
    expect(del.path).toMatch(/campaigns\/[^/]+\/encounters\//);
  });

  test('deleteEncounter clears activeDisplay if it was active', async () => {
    await setupCampaignAndEncounter('Camp A', 'Enc A');
    await selectEncounterByName('Enc A');

    // activate display first
    const onBtn = await screen.findByTitle('Activate for Player Display');
    fireEvent.click(onBtn);
    await waitFor(() => findCall('updateDoc', 'activeDisplay/status'));

    // delete the active encounter
    const trashBtn = screen.getAllByTitle('Delete Encounter')[0];
    fireEvent.click(trashBtn);
    fireEvent.click(await screen.findByRole('button', { name: /Confirm/i }));

    await waitFor(() => {
      const adCalls = findCalls('updateDoc', 'activeDisplay/status');
      const last = adCalls[adCalls.length - 1];
      return last.data.activeEncounterId === null;
    });
    const adCalls = findCalls('updateDoc', 'activeDisplay/status');
    const last = adCalls[adCalls.length - 1];
    expect(last.data).toMatchObject({ activeCampaignId: null, activeEncounterId: null });
  });
});
