import { describe, it, expect, vi } from 'vitest';
import type { Page, Locator } from 'playwright';
import { AuthenticationState } from 'apps/companion/main/automation/domain/value-objects/AuthenticationState';
import { BrowserAuthenticationState } from 'apps/companion/main/automation/domain/value-objects/BrowserAuthenticationState';
import type { LoggerPort as Logger } from 'apps/companion/main/automation/application/ports/LoggerPort';
import type { Result } from '@core/shared/application/Result';
import { PlaywrightBrowserSession } from '../core/PlaywrightBrowserSession';
import { IPlaywrightAuthFlow } from './PlaywrightAuthFlow';
import { PlaywrightAuthSessionService } from './PlaywrightAuthSessionService';
import { SessionCookieStore } from './SessionCookieStore';

describe('PlaywrightAuthSessionService.verifyPageAuthentication', () => {
  function createService(deps: {
    pageUrl: string;
    hasLoginUi: boolean;
    hasAuthUi: boolean;
    cookieState: AuthenticationState;
  }) {
    const mockLogger: Logger = {
      debug: vi.fn(),
      info: vi.fn(),
      warn: vi.fn(),
      error: vi.fn(),
      fatal: vi.fn(),
      child: vi.fn(),
      flush: vi.fn().mockResolvedValue(undefined),
    };

    const mockLocator: Locator = {
      first: vi.fn().mockReturnThis(),
      isVisible: vi.fn().mockImplementation(async () => deps.hasLoginUi),
    } as unknown as Locator;

    const mockPage: Page = {
      url: vi.fn().mockReturnValue(deps.pageUrl),
      locator: vi.fn().mockReturnValue(mockLocator),
    } as unknown as Page;

    const mockBrowserSession: PlaywrightBrowserSession = {
      getPersistentContext: vi.fn().mockReturnValue(null),
      getContext: vi.fn().mockReturnValue(null),
      getPage: vi.fn().mockReturnValue(mockPage),
    } as unknown as PlaywrightBrowserSession;

    const mockCookieStore: SessionCookieStore = {
      read: vi.fn().mockResolvedValue({
        cookies: [{ name: 'XSESSIONID', value: 'abc', domain: 'members-ng.iracing.com', path: '/', expires: -1 }],
        origins: [],
      }),
      validateCookies: vi.fn().mockReturnValue(deps.cookieState),
      getSessionExpiry: vi.fn(),
      write: vi.fn(),
      delete: vi.fn(),
    } as unknown as SessionCookieStore;

    const mockAuthFlow: IPlaywrightAuthFlow = {
      getLoginUrl: () => 'https://members-ng.iracing.com/login',
      getPostLoginLandingUrl: () => 'https://members-ng.iracing.com/web/racing/hosted/browse-sessions',
      isLoginUrl: (url: string) => url.includes('/login'),
      isAuthenticatedUrl: (url: string) => url.includes('/web/racing/hosted'),
      isLoginSuccessUrl: (url: string) => url.includes('/web/racing/hosted'),
      detectAuthenticatedUi: vi.fn().mockResolvedValue(deps.hasAuthUi),
      detectLoginUi: vi.fn(),
      navigateToAuthenticatedArea: vi.fn(),
      waitForPostLoginRedirect: vi.fn(),
    } as unknown as IPlaywrightAuthFlow;

    const service = new PlaywrightAuthSessionService(
      mockBrowserSession,
      mockCookieStore,
      mockAuthFlow,
      mockLogger,
    );

    return { service, mockCookieStore, mockAuthFlow, mockPage };
  }

  it('treats cookies-valid + login UI as EXPIRED (page wins over cookies)', async () => {
    const { service } = createService({
      pageUrl: 'https://members-ng.iracing.com/web/racing/hosted/browse-sessions',
      hasLoginUi: true,
      hasAuthUi: false,
      cookieState: AuthenticationState.AUTHENTICATED,
    });

    const result: Result<BrowserAuthenticationState> = await service.verifyPageAuthentication();
    expect(result.isOk()).toBe(true);

    const browserState = result.unwrap();
    expect(browserState.getCookieValidity()).toBe(true);
    expect(browserState.getPageAuthenticationStatus()).toBe(false);
    expect(browserState.getAuthenticationState()).toBe(AuthenticationState.EXPIRED);
    expect(browserState.requiresReauthentication()).toBe(true);
  });

  it('treats cookies-valid + authenticated UI without login UI as AUTHENTICATED', async () => {
    const { service } = createService({
      pageUrl: 'https://members-ng.iracing.com/web/racing/hosted/browse-sessions',
      hasLoginUi: false,
      hasAuthUi: true,
      cookieState: AuthenticationState.AUTHENTICATED,
    });

    const result: Result<BrowserAuthenticationState> = await service.verifyPageAuthentication();
    expect(result.isOk()).toBe(true);

    const browserState = result.unwrap();
    expect(browserState.getCookieValidity()).toBe(true);
    expect(browserState.getPageAuthenticationStatus()).toBe(true);
    expect(browserState.getAuthenticationState()).toBe(AuthenticationState.AUTHENTICATED);
    expect(browserState.requiresReauthentication()).toBe(false);
  });
});