/**
 * Generic SEO parity test harness.
 *
 * Features register their SEO builder functions against this harness.
 * The harness asserts that every builder produces a complete `SeoHeadProps`
 * with all required fields:
 *   - title (non-empty string)
 *   - description (non-empty string)
 *   - canonical (valid URL)
 *   - hreflang (10 entries: 9 languages + x-default)
 *   - og (all required fields present)
 *   - twitter (card field present)
 *
 * Designed for reuse across Phase 3+ features.
 *
 * @module
 */

import { describe, it, expect } from "vitest";
import type { SeoHeadProps } from "@/ui/seo/SeoHead.js";
import type { Language } from "@/i18n/resolver.js";

// ---------------------------------------------------------------------------
// Public config contract
// ---------------------------------------------------------------------------

export interface SeoParityEntry {
  /** Human-readable label for the test (e.g. "start page", "flight search"). */
  label: string;

  /** Call the SEO builder and return the result. */
  render(lang: Language): SeoHeadProps;
}

export interface SeoParityConfig {
  /** Feature slug (used in describe block labels). */
  slug: string;

  /** The entries to test. */
  entries: SeoParityEntry[];

  /** Languages to test each entry against. Defaults to ["ru", "en"]. */
  languages?: Language[];
}

// ---------------------------------------------------------------------------
// Expected hreflang count
// ---------------------------------------------------------------------------

const EXPECTED_HREFLANG_COUNT = 10; // 9 languages + x-default

// ---------------------------------------------------------------------------
// Harness entry point
// ---------------------------------------------------------------------------

/**
 * Defines a full SEO parity test suite for a feature.
 *
 * Call this from a `*.test.ts` file — it registers `describe` / `it` blocks
 * via Vitest globals.
 */
export function defineSeoParityTests(config: SeoParityConfig): void {
  const { slug, entries, languages = ["ru", "en"] } = config;

  describe(`[${slug}] SEO parity`, () => {
    for (const entry of entries) {
      for (const lang of languages) {
        describe(`${entry.label} (${lang})`, () => {
          let result: SeoHeadProps;

          // Build once per describe block
          // Using a beforeAll-style pattern via lazy init
          function getResult(): SeoHeadProps {
            if (!result) {
              result = entry.render(lang);
            }
            return result;
          }

          it("has a non-empty title", () => {
            const r = getResult();
            expect(r.title).toBeTruthy();
            expect(typeof r.title).toBe("string");
          });

          it("has a non-empty description", () => {
            const r = getResult();
            expect(r.description).toBeTruthy();
            expect(typeof r.description).toBe("string");
          });

          it("has a canonical URL containing the locale", () => {
            const r = getResult();
            expect(r.canonical).toBeTruthy();
            expect(r.canonical).toContain(`/${lang}/`);
          });

          it(`has ${EXPECTED_HREFLANG_COUNT} hreflang entries`, () => {
            const r = getResult();
            expect(r.hreflang).toHaveLength(EXPECTED_HREFLANG_COUNT);
          });

          it("has x-default in hreflang entries", () => {
            const r = getResult();
            const xDefault = r.hreflang.find((h) => h.lang === "x-default");
            expect(xDefault).toBeDefined();
            expect(xDefault?.href).toBeTruthy();
          });

          it("has all required OG fields", () => {
            const r = getResult();
            expect(r.og.title).toBeTruthy();
            expect(r.og.description).toBeTruthy();
            expect(r.og.url).toBeTruthy();
            expect(r.og.image).toBeTruthy();
            expect(["website", "article"]).toContain(r.og.type);
            expect(r.og.locale).toBe(lang);
            expect(r.og.siteName).toBeTruthy();
          });

          it("has og.url matching canonical", () => {
            const r = getResult();
            expect(r.og.url).toBe(r.canonical);
          });

          it("has og.title matching title", () => {
            const r = getResult();
            expect(r.og.title).toBe(r.title);
          });

          it("has twitter card defined", () => {
            const r = getResult();
            expect(r.twitter).toBeDefined();
            expect(r.twitter?.card).toBeTruthy();
          });
        });
      }
    }
  });
}
