import { z, SKILLS } from '@zibby/core';
import { formatRecordedActions, formatAssertionsWithResults, loadRecordedActions, detectLoginPattern, formatSetupHint } from './utils.mjs';

const GenerateScriptOutputSchema = z.object({
  success: z.boolean(),
  scriptPath: z.string(),
  method: z.string()
});

export const generateScriptNode = {
  name: 'generate_script',
  skills: [SKILLS.MEMORY],
  outputSchema: GenerateScriptOutputSchema,
  timeout: 1200000,

  prompt: (state) => {
    const exec = state.execute_live || {};
    const preflight = state.preflight || {};

    const actionsBlock = formatRecordedActions(state.sessionPath, exec.actions);
    const assertionsBlock = formatAssertionsWithResults(
      preflight.assertions,
      exec.assertions,
      exec.notes,
      exec.finalUrl
    );

    const recorded = loadRecordedActions(state.sessionPath);
    const setupHint = formatSetupHint(detectLoginPattern(recorded));

    return `Generate and verify Playwright test at ${state.outputPath}

Test Spec:
${state.testSpec}

Live Execution Summary:
- Success: ${exec.success}
- Steps: ${JSON.stringify(exec.steps)}
- Final URL: ${exec.finalUrl || 'unknown'}
${actionsBlock}
${assertionsBlock}
${setupHint}
IMPORTS AND PATTERN:
\`\`\`javascript
import { test, expect } from '@playwright/test';
import { StableIdRuntime } from '@zibby/core';

async function clickSafe(page, stableId, fallback) {
  try { await StableIdRuntime.clickWithRetry(page, stableId); }
  catch { await fallback.click(); }
}

test('Test Name', async ({ page }) => {
  await page.goto('https://...');
  await StableIdRuntime.injectStableIds(page);
  // Elements WITH stable IDs + fallback — use clickSafe:
  await clickSafe(page, 'zibby-xxxxx', page.getByRole('button', { name: '...' }));
  await StableIdRuntime.fillWithRetry(page, 'zibby-xxxxx', 'value');
  // Elements WITHOUT stable IDs (NO_STABLE_ID) — use native Playwright selectors:
  await page.getByText('visible text').click();
  await page.getByRole('button', { name: 'Submit' }).click();
  await page.getByPlaceholder('placeholder text').fill('value');
  await expect(page).toHaveURL(/expected-url/);
});
\`\`\`

RULES:
1. First navigate → page.goto(), skip subsequent navigates
2. After goto, call StableIdRuntime.injectStableIds(page)
3. Selector priority:
   a. If memory/insights flag a stableId as unreliable → use the fallback selector instead
   b. If action is marked [DUPLICATE_STABLE_ID] → always use the provided fallback
   c. Cross-reference stableIds against memory "Reliable Selectors" and "Flaky Selectors" — prefer proven selectors, avoid flaky ones
   d. Otherwise use EXACT stable IDs from recorded actions
4. For [NO_STABLE_ID] actions, use the fallback selector (getByText, getByRole, getByPlaceholder)
5. Skip duplicate consecutive clicks on same stableId
6. No comments in generated code
7. Implement ALL assertions from the list above
8. If an assertion fails after retries, comment it out with a TODO (don't delete it)
9. Selector failure handling:
   - When a stableId fails and you switch to a fallback, IMMEDIATELY call memory_save_insight (category: selector_tip) with which stableId failed, which fallback worked, and the page URL
   - Note the specific Playwright locator strategy that succeeded
10. Navigation order: always complete setup/login FIRST from the base URL, then navigate to the target page. Never go to a deep URL before setup is done.
11. The generated test runs in a FRESH browser with no prior state. Even if the live execution skipped setup steps, the test must include them. Check memory insights for any required setup.

WORKFLOW:
1. Study the codebase FIRST — search tests/ for existing helpers, fixtures, and shared setup files. Read them. Reuse what exists. Do NOT create files that duplicate existing ones.
2. Write test to ${state.outputPath} (after the run, a copy is mirrored under ${state.sessionPath}/generate_script/ for Studio — you may also write directly there if you prefer)
3. Verify syntax: run node --check on the file. If it fails, fix and re-check before proceeding.
4. Run: PLAYWRIGHT_HEADLESS=1 npx playwright test ${state.outputPath} --reporter=line --timeout=60000
5. If fails: try selectors in order — (a) getByRole (b) getByText (c) getByTestId (d) add waitForSelector. Never retry the same selector twice.
6. MAX 2 ATTEMPTS then STOP

The test runs in: ${state.cwd || 'project root'}
`;
  },
};
