/**
 * Tests for SEO Content Analyzer
 *
 * @group unit
 * @group seo
 */

import { describe, it, expect, beforeEach } from "vitest";
import { ContentAnalyzer } from "../../../dist/tools/seo/analyzers/ContentAnalyzer.js";

describe("SEO Content Analyzer", () => {
  let analyzer;

  beforeEach(() => {
    analyzer = new ContentAnalyzer();
  });

  describe("Basic functionality", () => {
    it("should be instantiable", () => {
      expect(analyzer).toBeDefined();
      expect(analyzer).toBeInstanceOf(ContentAnalyzer);
    });

    it("should have analyzePost method", () => {
      expect(analyzer.analyzePost).toBeDefined();
      expect(typeof analyzer.analyzePost).toBe("function");
    });
  });

  describe("Content analysis", () => {
    const samplePost = {
      id: 1,
      title: { rendered: "Sample SEO Test Post" },
      content: {
        rendered: `
          <h1>Main Heading</h1>
          <p>This is a test paragraph with some content for SEO analysis.
          It contains multiple sentences to test readability scoring.</p>
          <h2>Subheading</h2>
          <p>Another paragraph with more content. This paragraph also contains
          important information about SEO optimization.</p>
          <img src="test.jpg" alt="Test image">
          <p>A paragraph with <a href="/internal-link">internal link</a> and
          <a href="https://external.com">external link</a>.</p>
        `,
      },
      excerpt: { rendered: "Test excerpt for SEO analysis" },
    };

    const analysisParams = {
      site: "test",
      postId: 1,
      analysisType: "full",
      focusKeywords: ["SEO"],
    };

    it("should analyze post content and return results", async () => {
      const result = await analyzer.analyzePost(samplePost, analysisParams);

      expect(result).toBeDefined();
      expect(result).toHaveProperty("score");
      expect(result).toHaveProperty("status");
      expect(result).toHaveProperty("metrics");
      expect(result).toHaveProperty("recommendations");
      expect(result).toHaveProperty("analyzedAt");

      expect(typeof result.score).toBe("number");
      expect(result.score).toBeGreaterThanOrEqual(0);
      expect(result.score).toBeLessThanOrEqual(100);

      expect(["poor", "needs-improvement", "good", "excellent"]).toContain(result.status);
    });

    it("should calculate basic metrics correctly", async () => {
      const result = await analyzer.analyzePost(samplePost, analysisParams);

      expect(result.metrics).toHaveProperty("wordCount");
      expect(result.metrics).toHaveProperty("fleschReadingEase");
      expect(result.metrics).toHaveProperty("fleschKincaidGrade");
      expect(result.metrics).toHaveProperty("headingCount");
      expect(result.metrics).toHaveProperty("imageCount");
      expect(result.metrics).toHaveProperty("internalLinkCount");
      expect(result.metrics).toHaveProperty("externalLinkCount");

      expect(result.metrics.wordCount).toBeGreaterThan(0);
      expect(result.metrics.headingCount).toBeGreaterThan(0);
      expect(result.metrics.imageCount).toBe(1);
      expect(result.metrics.internalLinkCount).toBeGreaterThanOrEqual(1);
      expect(result.metrics.externalLinkCount).toBeGreaterThanOrEqual(1);
    });

    it("should generate appropriate recommendations", async () => {
      const result = await analyzer.analyzePost(samplePost, analysisParams);

      expect(Array.isArray(result.recommendations)).toBe(true);

      if (result.recommendations.length > 0) {
        const firstRecommendation = result.recommendations[0];
        expect(firstRecommendation).toHaveProperty("type");
        expect(firstRecommendation).toHaveProperty("priority");
        expect(firstRecommendation).toHaveProperty("message");
        expect(firstRecommendation).toHaveProperty("impact");
        expect(firstRecommendation).toHaveProperty("autoFixAvailable");

        expect(["title", "meta", "content", "structure", "keyword", "technical", "performance"]).toContain(
          firstRecommendation.type,
        );
        expect(["low", "medium", "high", "critical"]).toContain(firstRecommendation.priority);
        expect(typeof firstRecommendation.message).toBe("string");
        expect(firstRecommendation.impact).toBeGreaterThan(0);
        expect(firstRecommendation.impact).toBeLessThanOrEqual(100);
      }
    });

    it("should analyze keywords when provided", async () => {
      const result = await analyzer.analyzePost(samplePost, analysisParams);

      expect(result.keywordAnalysis).toBeDefined();
      expect(result.keywordAnalysis).toHaveProperty("primaryKeyword");
      expect(result.keywordAnalysis).toHaveProperty("keywordFound");
      expect(result.keywordAnalysis).toHaveProperty("occurrences");
      expect(result.keywordAnalysis).toHaveProperty("density");
      expect(result.keywordAnalysis).toHaveProperty("semanticKeywords");

      expect(result.keywordAnalysis.primaryKeyword).toBe("SEO");
      expect(typeof result.keywordAnalysis.keywordFound).toBe("boolean");
      expect(typeof result.keywordAnalysis.occurrences).toBe("number");
      expect(typeof result.keywordAnalysis.density).toBe("number");
      expect(Array.isArray(result.keywordAnalysis.semanticKeywords)).toBe(true);
    });

    it("should analyze content structure", async () => {
      const result = await analyzer.analyzePost(samplePost, analysisParams);

      expect(result.structure).toBeDefined();
      expect(result.structure).toHaveProperty("hasH1");
      expect(result.structure).toHaveProperty("h1Text");
      expect(result.structure).toHaveProperty("headingHierarchy");
      expect(result.structure).toHaveProperty("paragraphCount");
      expect(result.structure).toHaveProperty("avgParagraphLength");

      expect(result.structure.hasH1).toBe(true);
      expect(result.structure.h1Text).toBe("Main Heading");
      expect(typeof result.structure.headingHierarchy).toBe("boolean");
      expect(result.structure.paragraphCount).toBeGreaterThan(0);
    });

    it("should handle posts without focus keywords", async () => {
      const paramsWithoutKeywords = {
        site: "test",
        postId: 1,
        analysisType: "full",
      };

      const result = await analyzer.analyzePost(samplePost, paramsWithoutKeywords);

      expect(result.keywordAnalysis).toBeUndefined();
      expect(result.metrics.keywordDensity).toBe(0);
    });

    it("should handle empty or minimal content", async () => {
      const minimalPost = {
        id: 2,
        title: { rendered: "Short" },
        content: { rendered: "<p>Very short content.</p>" },
        excerpt: { rendered: "" },
      };

      const result = await analyzer.analyzePost(minimalPost, analysisParams);

      expect(result).toBeDefined();
      expect(result.metrics.wordCount).toBeLessThan(10);
      expect(result.recommendations.length).toBeGreaterThan(0);

      // Should recommend longer content
      const contentRecommendation = result.recommendations.find(
        (r) => r.type === "content" && r.message.includes("too short"),
      );
      expect(contentRecommendation).toBeDefined();
    });
  });

  describe("Edge cases", () => {
    it("should handle posts with no HTML content", async () => {
      const plainTextPost = {
        id: 3,
        title: "Plain Title",
        content: "Plain text content without HTML tags. This should still be analyzed correctly.",
        excerpt: "",
      };

      const params = {
        site: "test",
        postId: 3,
        analysisType: "full",
        focusKeywords: ["SEO"],
      };

      const result = await analyzer.analyzePost(plainTextPost, params);

      expect(result).toBeDefined();
      expect(result.metrics.wordCount).toBeGreaterThan(0);
      expect(result.metrics.headingCount).toBe(0);
    });

    it("should handle posts with malformed HTML", async () => {
      const malformedPost = {
        id: 4,
        title: { rendered: "Malformed HTML Test" },
        content: { rendered: "<h1>Unclosed heading<p>Paragraph without closing<img src='test.jpg'>" },
        excerpt: { rendered: "" },
      };

      const params = {
        site: "test",
        postId: 4,
        analysisType: "full",
        focusKeywords: ["SEO"],
      };

      const result = await analyzer.analyzePost(malformedPost, params);

      expect(result).toBeDefined();
      expect(result.score).toBeGreaterThanOrEqual(0);
      expect(result.score).toBeLessThanOrEqual(100);
    });

    it("should handle posts with special characters and unicode", async () => {
      const unicodePost = {
        id: 5,
        title: { rendered: "Unicode Test: Café & Résumé 中文" },
        content: {
          rendered: "<p>Content with émojis 🚀 and spëcial characters: àáâãäå</p>",
        },
        excerpt: { rendered: "" },
      };

      const params = {
        site: "test",
        postId: 5,
        analysisType: "full",
        focusKeywords: ["SEO"],
      };

      const result = await analyzer.analyzePost(unicodePost, params);

      expect(result).toBeDefined();
      expect(result.metrics.wordCount).toBeGreaterThan(0);
    });
  });

  describe("Performance", () => {
    it("should complete analysis within reasonable time", async () => {
      const largePost = {
        id: 6,
        title: { rendered: "Performance Test Post" },
        content: {
          rendered: "<p>" + "This is a performance test paragraph. ".repeat(100) + "</p>".repeat(50),
        },
        excerpt: { rendered: "Performance test excerpt" },
      };

      const params = {
        site: "test",
        postId: 6,
        analysisType: "full",
        focusKeywords: ["SEO"],
      };

      const startTime = Date.now();
      const result = await analyzer.analyzePost(largePost, params);
      const endTime = Date.now();

      expect(result).toBeDefined();
      expect(endTime - startTime).toBeLessThan(5000); // Should complete within 5 seconds
    });
  });
});
