import { describe, it, expect, vi, beforeEach } from "vitest";
import { AISocialMediaService, type SocialMediaGenerationRequest } from "./aiSocialMedia";
import * as llm from "../_core/llm.ts";
import * as imageGen from "../_core/imageGeneration.ts";

// Mock the LLM and image generation modules
vi.mock("../_core/llm");
vi.mock("../_core/imageGeneration");

describe("AISocialMediaService", () => {
  beforeEach(() => {
    vi.clearAllMocks();
  });

  describe("generatePost", () => {
    it("should generate a valid social media post", async () => {
      const mockPost = {
        caption: "🎰 Join CoinKrazy today and win big! Play our exclusive slot games now.",
        hashtags: ["#CoinKrazy", "#SlotGames", "#OnlineCasino", "#SweepstakesCasino"],
        mentions: ["@CoinKrazy", "@PlayCoinKrazy"],
        callToAction: "Join CoinKrazy today!",
        imagePrompt: "A vibrant casino slot game scene with coins and excitement",
      };

      vi.mocked(llm.invokeLLM).mockResolvedValueOnce({
        choices: [{ message: { content: JSON.stringify(mockPost) } }],
      } as any);

      const request: SocialMediaGenerationRequest = {
        platform: "twitter",
        topic: "New slot game launch",
        tone: "casual",
        includeHashtags: true,
        includeEmoji: true,
        callToAction: "Join CoinKrazy today!",
      };

      const result = await AISocialMediaService.generatePost(request);

      expect(result.caption).toBeDefined();
      expect(result.hashtags).toBeInstanceOf(Array);
      expect(result.mentions).toBeInstanceOf(Array);
      expect(result.imagePrompt).toBeDefined();
    });

    it("should generate platform-specific content", async () => {
      const platforms = ["twitter", "instagram", "tiktok", "facebook"] as const;

      for (const platform of platforms) {
        const mockPost = {
          caption: `Post for ${platform}`,
          hashtags: ["#test"],
          mentions: ["@test"],
          callToAction: "Test CTA",
          imagePrompt: "Test image",
        };

        vi.mocked(llm.invokeLLM).mockResolvedValueOnce({
          choices: [{ message: { content: JSON.stringify(mockPost) } }],
        } as any);

        const result = await AISocialMediaService.generatePost({
          platform,
          topic: "Test topic",
          tone: "casual",
        });

        expect(result.caption).toContain(platform);
      }
    });

    it("should handle different tones", async () => {
      const tones = ["professional", "casual", "humorous", "motivational"] as const;

      for (const tone of tones) {
        const mockPost = {
          caption: `${tone} post`,
          hashtags: ["#test"],
          mentions: ["@test"],
          callToAction: "Test",
          imagePrompt: "Test",
        };

        vi.mocked(llm.invokeLLM).mockResolvedValueOnce({
          choices: [{ message: { content: JSON.stringify(mockPost) } }],
        } as any);

        const result = await AISocialMediaService.generatePost({
          platform: "twitter",
          topic: "Test topic",
          tone,
        });

        expect(result.caption).toContain(tone);
      }
    });

    it("should throw error on invalid LLM response", async () => {
      vi.mocked(llm.invokeLLM).mockResolvedValueOnce({
        choices: [{ message: { content: "invalid json" } }],
      } as any);

      const request: SocialMediaGenerationRequest = {
        platform: "twitter",
        topic: "Test topic",
        tone: "casual",
      };

      await expect(AISocialMediaService.generatePost(request)).rejects.toThrow();
    });
  });

  describe("generateCampaignPosts", () => {
    it("should generate multiple posts for a campaign", async () => {
      const mockPost = {
        caption: "Campaign post",
        hashtags: ["#campaign"],
        mentions: ["@coinkrazy"],
        callToAction: "Join now",
        imagePrompt: "Campaign image",
      };

      vi.mocked(llm.invokeLLM).mockResolvedValue({
        choices: [{ message: { content: JSON.stringify(mockPost) } }],
      } as any);

      const result = await AISocialMediaService.generateCampaignPosts(
        "Summer Promotion",
        ["twitter", "instagram"],
        3,
        "casual"
      );

      expect(result.twitter).toHaveLength(3);
      expect(result.instagram).toHaveLength(3);
      expect(result.twitter[0].caption).toBeDefined();
      expect(result.instagram[0].caption).toBeDefined();
    });

    it("should generate posts for all specified platforms", async () => {
      const mockPost = {
        caption: "Test post",
        hashtags: ["#test"],
        mentions: ["@test"],
        callToAction: "Test",
        imagePrompt: "Test",
      };

      vi.mocked(llm.invokeLLM).mockResolvedValue({
        choices: [{ message: { content: JSON.stringify(mockPost) } }],
      } as any);

      const platforms = ["twitter", "instagram", "tiktok", "facebook"] as const;

      const result = await AISocialMediaService.generateCampaignPosts(
        "Test Campaign",
        platforms,
        2
      );

      for (const platform of platforms) {
        expect(result[platform]).toBeDefined();
        expect(result[platform]).toHaveLength(2);
      }
    });
  });

  describe("generatePostImage", () => {
    it("should generate image for social media post", async () => {
      const mockImageUrl = "https://example.com/image.png";

      vi.mocked(imageGen.generateImage).mockResolvedValueOnce({
        url: mockImageUrl,
      } as any);

      const result = await AISocialMediaService.generatePostImage(
        "A vibrant casino scene",
        "twitter"
      );

      expect(result).toBe(mockImageUrl);
      expect(vi.mocked(imageGen.generateImage)).toHaveBeenCalled();
    });

    it("should enhance prompt for different platforms", async () => {
      const mockImageUrl = "https://example.com/image.png";

      vi.mocked(imageGen.generateImage).mockResolvedValue({
        url: mockImageUrl,
      } as any);

      const platforms = ["twitter", "instagram", "tiktok", "facebook"] as const;

      for (const platform of platforms) {
        vi.mocked(imageGen.generateImage).mockClear();

        await AISocialMediaService.generatePostImage("Test image", platform);

        const callArgs = vi.mocked(imageGen.generateImage).mock.calls[0][0];
        expect(callArgs.prompt).toContain("CoinKrazy");
        expect(callArgs.prompt).toContain("casino");
      }
    });
  });

  describe("Platform guidelines", () => {
    it("should include platform-specific guidelines in system prompt", async () => {
      const mockPost = {
        caption: "Test post",
        hashtags: ["#test"],
        mentions: ["@test"],
        callToAction: "Test",
        imagePrompt: "Test",
      };

      vi.mocked(llm.invokeLLM).mockResolvedValueOnce({
        choices: [{ message: { content: JSON.stringify(mockPost) } }],
      } as any);

      await AISocialMediaService.generatePost({
        platform: "twitter",
        topic: "Test",
        tone: "casual",
      });

      const callArgs = vi.mocked(llm.invokeLLM).mock.calls[0][0];
      const systemMessage = (callArgs.messages as any[])[0];

      expect(systemMessage.content).toContain("twitter");
      expect(systemMessage.content).toContain("280 characters");
    });
  });

  describe("Hashtag and mention generation", () => {
    it("should generate relevant hashtags", async () => {
      const mockPost = {
        caption: "Test post",
        hashtags: ["#CoinKrazy", "#Slots", "#Casino", "#Gaming", "#Sweepstakes"],
        mentions: ["@CoinKrazy"],
        callToAction: "Play now",
        imagePrompt: "Test",
      };

      vi.mocked(llm.invokeLLM).mockResolvedValueOnce({
        choices: [{ message: { content: JSON.stringify(mockPost) } }],
      } as any);

      const result = await AISocialMediaService.generatePost({
        platform: "instagram",
        topic: "New game launch",
        tone: "casual",
        includeHashtags: true,
      });

      expect(result.hashtags.length).toBeGreaterThan(0);
      expect(result.hashtags[0]).toContain("#");
    });

    it("should generate account mentions", async () => {
      const mockPost = {
        caption: "Test post",
        hashtags: ["#test"],
        mentions: ["@CoinKrazy", "@PlayCoinKrazy"],
        callToAction: "Test",
        imagePrompt: "Test",
      };

      vi.mocked(llm.invokeLLM).mockResolvedValueOnce({
        choices: [{ message: { content: JSON.stringify(mockPost) } }],
      } as any);

      const result = await AISocialMediaService.generatePost({
        platform: "twitter",
        topic: "Promotion",
        tone: "casual",
      });

      expect(result.mentions.length).toBeGreaterThan(0);
      expect(result.mentions[0]).toContain("@");
    });
  });

  describe("Call to action", () => {
    it("should include call to action in post", async () => {
      const mockPost = {
        caption: "Join CoinKrazy today!",
        hashtags: ["#test"],
        mentions: ["@test"],
        callToAction: "Join CoinKrazy today!",
        imagePrompt: "Test",
      };

      vi.mocked(llm.invokeLLM).mockResolvedValueOnce({
        choices: [{ message: { content: JSON.stringify(mockPost) } }],
      } as any);

      const result = await AISocialMediaService.generatePost({
        platform: "facebook",
        topic: "Promotion",
        tone: "casual",
        callToAction: "Join CoinKrazy today!",
      });

      expect(result.callToAction).toBeDefined();
      expect(result.callToAction).toBe("Join CoinKrazy today!");
    });
  });

  describe("Responsible gaming compliance", () => {
    it("should include responsible gaming messaging", async () => {
      const mockPost = {
        caption: "Play responsibly. 18+",
        hashtags: ["#ResponsibleGaming"],
        mentions: ["@CoinKrazy"],
        callToAction: "Play now",
        imagePrompt: "Test",
      };

      vi.mocked(llm.invokeLLM).mockResolvedValueOnce({
        choices: [{ message: { content: JSON.stringify(mockPost) } }],
      } as any);

      await AISocialMediaService.generatePost({
        platform: "twitter",
        topic: "Promotion",
        tone: "casual",
      });

      const callArgs = vi.mocked(llm.invokeLLM).mock.calls[0][0];
      const systemMessage = (callArgs.messages as any[])[0];

      expect(systemMessage.content).toContain("responsible gaming");
    });
  });
});
