import { Page, expect } from '@playwright/test';
import { BasePage } from './BasePage';

/**
 * Dashboard Page Object
 * Handles all interactions on the /dashboard route
 * Includes The Council Chamber UI, stats, NPC chat panel, etc.
 */
export class DashboardPage extends BasePage {
  // Navigation — actual link text in the nav bar
  private readonly logoutButton = () => this.page.getByRole('button', { name: /leave fellowship|log out|logout|sign out/i }).first();
  private readonly questsLink = () => this.page.getByRole('link', { name: /scrolls.*middle-earth|quests/i }).first();
  private readonly mapLink = () => this.page.getByTestId('header-nav-map');
  private readonly inventoryLink = () => this.page.getByRole('link', { name: /^inventory$/i }).first();

  // Greeting — "Welcome, {user.role}! Track the Fellowship's journey"
  private readonly greeting = () => this.page.getByText(/welcome,/i).first();

  // Quest stat cards — use text labels (no data-testid on these elements)
  private readonly totalQuestsCard = () =>
    this.page.locator('div.text-center').filter({ hasText: 'Total Quest Objectives' });
  private readonly completedQuestsCard = () =>
    this.page.locator('div.text-center').filter({ hasText: 'It Is Done' });

  // Mission briefing card HAS data-testid="mission-briefing" from Card component
  private readonly missionBriefing = () => this.page.locator('[data-testid="mission-briefing"]').first();

  // Recent quests — heading + h3 titles (text-lg distinguishes from CharacterPanel's text-xl h3)
  private readonly recentQuestsHeading = () =>
    this.page.getByText(/recent quest objectives|filtered quests/i).first();
  private readonly recentQuestItems = () =>
    this.page.locator('h3.font-epic.text-lg');

  // Dark magic warning Alert — title text "Dark Magic Detected!"
  private readonly darkMagicWarning = () =>
    this.page.getByText(/dark magic detected/i).first();

  // NPC chat panel — CharacterPanel renders with data-testid="character-panel"
  private readonly chatPanel = () => this.page.locator('[data-testid="character-panel"]').first();
  private readonly chatButton = () => this.page.getByRole('button', { name: /chat|companion|talk/i }).first();

  async goto(): Promise<void> {
    await super.goto('/dashboard');
  }

  /**
   * Check if dashboard is fully loaded
   * Uses active polling to verify dashboard is ready
   * Handles loading states and async data
   */
  async isLoaded(): Promise<boolean> {
    try {
      // First wait for loading state to clear
      const isStillLoading = await this.page
        .getByText(/opening the gates of rivendell/i)
        .isVisible({ timeout: 1000 })
        .catch(() => false);

      if (isStillLoading) {
        await this.pollUntil(
          async () => {
            const loading = await this.page
              .getByText(/opening the gates of rivendell/i)
              .isVisible()
              .catch(() => false);
            return !loading;
          },
          20000,
          1000,
        );
      }

      // Poll for mission briefing which is a primary dashboard element
      await this.pollForElementVisible(
        this.page.locator('[data-testid="mission-briefing"]'),
        15000, // 15 second timeout
        500, // Poll every 500ms
      );
      return true;
    } catch {
      return false;
    }
  }

  /**
   * Get personalized greeting text
   */
  async getGreeting(): Promise<string> {
    await this.page.waitForLoadState('networkidle').catch(() => {});
    return this.greeting().textContent().then(t => t || '').catch(() => '');
  }

  /**
   * Verify personalized greeting contains character name
   * The dashboard shows "Welcome, {user.role}!" — match via the greeting paragraph specifically
   */
  async expectGreetingForCharacter(characterName: string): Promise<void> {
    // Use greeting() locator which is the <p> with greeting text, filtered to avoid strict mode violation
    const greetingWithName = this.greeting().filter({ hasText: new RegExp(characterName, 'i') });
    await expect(greetingWithName).toBeVisible({ timeout: 10000 });
  }

  /**
   * Get total quest count from the stats card
   * Dashboard renders <div class="text-4xl">{stats.total}</div> above label
   */
  async getTotalQuestCount(): Promise<number> {
    try {
      await this.totalQuestsCard().waitFor({ state: 'visible', timeout: 10000 });
    } catch {
      return 0;
    }
    const text = await this.totalQuestsCard().locator('.text-4xl, [class*="text-4xl"]').textContent();
    return parseInt(text?.match(/\d+/)?.[0] || '0', 10);
  }

  /**
   * Get completed quest count from "It Is Done" stats card
   */
  async getCompletedQuestCount(): Promise<number> {
    try {
      await this.completedQuestsCard().waitFor({ state: 'visible', timeout: 10000 });
    } catch {
      return 0;
    }
    const text = await this.completedQuestsCard().locator('.text-4xl, [class*="text-4xl"]').textContent();
    return parseInt(text?.match(/\d+/)?.[0] || '0', 10);
  }

  /**
   * Check if journey progress visualization is visible
   * Maps to the Mission Briefing card (data-testid="mission-briefing") which
   * always shows completion-related status on the dashboard
   */
  async isJourneyProgressVisible(): Promise<boolean> {
    return this.missionBriefing().isVisible({ timeout: 10000 }).catch(() => false);
  }

  /**
   * Get journey progress percentage (completion rate from personal stats)
   */
  async getJourneyProgress(): Promise<number> {
    // Completion rate is shown as "{n}%" in personal journey stats
    const rateText = await this.page.getByText(/%$/).first().textContent().catch(() => '0%');
    return parseInt(rateText?.replace('%', '') || '0', 10);
  }

  /**
   * Check if recent quests panel is visible (heading "Recent Quest Objectives")
   */
  async isRecentQuestsPanelVisible(): Promise<boolean> {
    return this.recentQuestsHeading().isVisible({ timeout: 10000 }).catch(() => false);
  }

  /**
   * Get list of recent quest titles from h3.font-epic elements
   */
  async getRecentQuestTitles(): Promise<string[]> {
    try {
      await this.recentQuestsHeading().waitFor({ state: 'visible', timeout: 10000 });
    } catch {
      return [];
    }
    const items = this.recentQuestItems();
    const count = await items.count();
    const titles: string[] = [];
    for (let i = 0; i < count; i++) {
      const text = await items.nth(i).textContent();
      if (text) titles.push(text.trim());
    }
    return titles;
  }

  /**
   * Check if dark magic warning banner is visible
   * Alert renders with title "Dark Magic Detected!"
   */
  async isDarkMagicWarningVisible(): Promise<boolean> {
    return this.darkMagicWarning().isVisible({ timeout: 5000 }).catch(() => false);
  }

  /**
   * Check if NPC chat panel is visible
   * CharacterPanel renders data-testid="character-panel"
   */
  async isChatPanelVisible(): Promise<boolean> {
    return this.chatPanel().isVisible({ timeout: 8000 }).catch(() => false);
  }

  /**
   * Open NPC chat panel
   * Polls for button and panel to appear
   */
  async openChatPanel(): Promise<void> {
    // First check if panel is already visible
    const alreadyVisible = await this.isChatPanelVisible();
    if (alreadyVisible) {
      return;
    }

    // Poll for button to be visible
    try {
      await this.pollForElementVisible(
        this.chatButton(),
        10000,
        500,
      );
    } catch {
      // Button might not exist, continue anyway
    }

    // Click the button
    try {
      await this.chatButton().click();
    } catch {
      // Button not found or not clickable
      throw new Error('Chat button not found on dashboard. The chat panel might not be implemented.');
    }

    // Poll for chat panel to appear
    try {
      await this.pollForElementVisible(
        this.chatPanel(),
        10000,
        500,
      );
    } catch {
      throw new Error('Chat panel did not appear after clicking button');
    }
  }

  /**
   * Navigate to quests via "Scrolls of Middle-earth" nav link
   */
  async goToQuests(): Promise<void> {
    await this.questsLink().click();
    await this.page.waitForURL('**/quests', { timeout: 10000 });
  }

  /**
   * Navigate to map via "Map of Middle-earth" nav link
   */
  async goToMap(): Promise<void> {
    await this.mapLink().click();
    await this.page.waitForURL('**/map', { timeout: 10000 });
  }

  /**
   * Navigate to inventory via "Inventory" nav link
   */
  async goToInventory(): Promise<void> {
    await this.inventoryLink().click();
    await this.page.waitForURL('**/inventory', { timeout: 10000 });
  }

  /**
   * Logout
   */
  async logout(): Promise<void> {
    await this.logoutButton().click();
    await this.page.waitForURL('**/login');
  }
}
