import { Given, When, Then, expect } from '../fixtures/bdd-fixtures';

Given('I open the NPC chat panel', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  if (chatPanel && typeof chatPanel.open === 'function') {
    await chatPanel.open();
  }
  await page.waitForTimeout(300);
});

Given('the chat initializes with {string}', async ({ page }, characterName: string) => {
  const chatPanel = global.fixtures.chatPanel!;
  await chatPanel.selectCharacter(characterName);
  await page.waitForTimeout(500);
});

When('I select {string} from the character selector', async ({ page }, characterName: string) => {
  const chatPanel = global.fixtures.chatPanel!;
  await chatPanel.selectCharacter(characterName);
  await page.waitForTimeout(500);
});

When('I send a message {string}', async ({ page }, message: string) => {
  const chatPanel = global.fixtures.chatPanel!;
  await chatPanel.sendMessage(message);
  await page.waitForTimeout(500);
});

When('I send another message {string}', async ({ page }, message: string) => {
  const chatPanel = global.fixtures.chatPanel!;
  await chatPanel.sendMessage(message);
  await page.waitForTimeout(500);
});

When('I click the reset conversation button', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  if (typeof chatPanel.resetConversation === 'function') {
    await chatPanel.resetConversation();
    await page.waitForTimeout(500);
  }
});

When('I chat with {string}', async ({ page }, characterName: string) => {
  const chatPanel = global.fixtures.chatPanel!;
  await chatPanel.selectCharacter(characterName);
  await page.waitForTimeout(500);
});

When('I chat with Frodo', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  await chatPanel.selectCharacter('Frodo');
  await page.waitForTimeout(500);
});

When('I chat with Sam', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  await chatPanel.selectCharacter('Sam');
  await page.waitForTimeout(500);
});

When('I chat with Gandalf', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  await chatPanel.selectCharacter('Gandalf');
  await page.waitForTimeout(500);
});

Then('the chat should initialize with {string}', async ({ page }, characterName: string) => {
  const testContext = global.fixtures.testContext;
  expect(testContext).toBeDefined();
});

Then('an opening message should appear from {string}', async ({ page }, _character: string) => {
  const chatPanel = global.fixtures.chatPanel!;
  const messages = await chatPanel.getMessages();
  expect(messages.length).toBeGreaterThan(0);
});

Then('the opening message from {string} should be one of:', async ({ page }, _character: string) => {
  const chatPanel = global.fixtures.chatPanel!;
  const messages = await chatPanel.getMessages();
  const firstMessage = messages[0];
  expect(firstMessage).toBeDefined();
});

Then('I should receive another reply from {string}', async ({ page }, _character: string) => {
  const chatPanel = global.fixtures.chatPanel!;
  const messages = await chatPanel.getMessages();
  expect(messages.length).toBeGreaterThanOrEqual(3);
  const lastMessage = messages[messages.length - 1];
  expect(lastMessage).toBeDefined();
});

Then('I should receive a reply from {string}', async ({ page }, _character: string) => {
  const chatPanel = global.fixtures.chatPanel!;
  const messages = await chatPanel.getMessages();
  expect(messages.length).toBeGreaterThan(1);
  const lastMessage = messages[messages.length - 1];
  expect(lastMessage).toBeDefined();
});

Then('the conversation should flow coherently across multiple turns', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  const messages = await chatPanel.getMessages();
  expect(messages.length).toBeGreaterThanOrEqual(2);
  for (const msg of messages) {
    expect(msg.length).toBeGreaterThan(0);
  }
});

Then('the NPC response should include a suggested action', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  const messages = await chatPanel.getMessages();
  // Last message should be from NPC and contain some suggested action text
  expect(messages.length).toBeGreaterThan(0);
  const lastMsg = messages[messages.length - 1];
  expect(lastMsg).toBeDefined();
  expect(lastMsg.length).toBeGreaterThan(0);
});

Then('the suggested action should point to a valid in-app route', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  const actions = await chatPanel.getAvailableActions();
  expect(actions.length).toBeGreaterThan(0);
});

Then('a fresh opening message should appear', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  const messages = await chatPanel.getMessages();
  expect(messages.length).toBe(1);
});

Then('the previous conversation history should be cleared', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  const messages = await chatPanel.getMessages();
  expect(messages.length).toBeLessThanOrEqual(1);
});

When('Frodo responds to my message, the tone should be:', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  await chatPanel.selectCharacter('Frodo');
  await chatPanel.sendMessage('Hello');
  await page.waitForTimeout(500);
  const lastMessage = await chatPanel.getLastNPCMessage();
  expect(lastMessage.length).toBeGreaterThan(0);
});

When('Sam responds to my message, the tone should be:', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  await chatPanel.selectCharacter('Sam');
  await chatPanel.sendMessage('Hello');
  await page.waitForTimeout(500);
  const lastMessage = await chatPanel.getLastNPCMessage();
  expect(lastMessage.length).toBeGreaterThan(0);
});

When('Gandalf responds to my message, the tone should be:', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  await chatPanel.selectCharacter('Gandalf');
  await chatPanel.sendMessage('Hello');
  await page.waitForTimeout(500);
  const lastMessage = await chatPanel.getLastNPCMessage();
  expect(lastMessage.length).toBeGreaterThan(0);
});

Given('the Azure AI service is unavailable', async ({ page }) => {
  const testContext = global.fixtures.testContext;
  (testContext as any).azureServiceUnavailable = true;
});

Given('the Azure service returns an out-of-character response', async ({ page }) => {
  const testContext = global.fixtures.testContext;
  (testContext as any).azureReturnsOOC = true;
});

Then('the chat should still function', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  const messages = await chatPanel.getMessages();
  expect(messages.length).toBeGreaterThan(0);
});

Then('responses should be deterministic in-character fallbacks', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  const messages = await chatPanel.getMessages();
  const lastMessage = messages[messages.length - 1];
  expect(lastMessage.length).toBeGreaterThan(0);
});

Then('feature remains usable without Azure credentials', async ({ page }) => {
  const testContext = global.fixtures.testContext;
  expect(testContext).toBeDefined();
});

When('I chat with any companion', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  await chatPanel.selectCharacter('Gandalf');
  await page.waitForTimeout(500);
});

Then('the system should attempt one strict retry', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  const testContext = global.fixtures.testContext;
  const messages = await chatPanel.getMessages();
  expect(messages.length).toBeGreaterThan(0);
  (testContext as any).systemRetried = true;
});

Then('if the second response is also out-of-character, provide an in-character fallback', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  const messages = await chatPanel.getMessages();
  const lastMessage = messages[messages.length - 1];
  expect(lastMessage.length).toBeGreaterThan(0);
});

When('I send a message', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  await chatPanel.sendMessage('Hello companion');
  await page.waitForTimeout(500);
});

Then('Gandalf should reference {string} in the response', async ({ page }, referredText: string) => {
  const chatPanel = global.fixtures.chatPanel!;
  const lastMessage = await chatPanel.getLastNPCMessage();
  expect(lastMessage.toLowerCase()).toContain(referredText.toLowerCase());
});

Then('the conversation should demonstrate session-scoped memory', async ({ page }) => {
  const chatPanel = global.fixtures.chatPanel!;
  const messages = await chatPanel.getMessages();
  expect(messages.length).toBeGreaterThanOrEqual(2);
});
