import { describe, expect, it, beforeAll } from "vitest";
import { appRouter } from "./routers";
import type { TrpcContext } from "./_core/context";
import { TRPCError } from "@trpc/server";

type AuthenticatedUser = NonNullable<TrpcContext["user"]>;

function createAdminContext(): TrpcContext {
  const adminUser: AuthenticatedUser = {
    id: 1,
    openId: "admin-test",
    email: "admin@leifo.fr",
    name: "Admin Test",
    loginMethod: "manus",
    role: "admin",
    createdAt: new Date(),
    updatedAt: new Date(),
    lastSignedIn: new Date(),
  };

  return {
    user: adminUser,
    req: {
      protocol: "https",
      headers: {},
    } as TrpcContext["req"],
    res: {} as TrpcContext["res"],
  };
}

function createUserContext(): TrpcContext {
  const regularUser: AuthenticatedUser = {
    id: 2,
    openId: "user-test",
    email: "user@example.com",
    name: "User Test",
    loginMethod: "manus",
    role: "user",
    createdAt: new Date(),
    updatedAt: new Date(),
    lastSignedIn: new Date(),
  };

  return {
    user: regularUser,
    req: {
      protocol: "https",
      headers: {},
    } as TrpcContext["req"],
    res: {} as TrpcContext["res"],
  };
}

function createPublicContext(): TrpcContext {
  return {
    user: null,
    req: {
      protocol: "https",
      headers: {},
    } as TrpcContext["req"],
    res: {} as TrpcContext["res"],
  };
}

describe("Blog API - Admin Operations", () => {
  it("should allow admin to create an article", async () => {
    const ctx = createAdminContext();
    const caller = appRouter.createCaller(ctx);

    const uniqueSlug = `test-article-api-${Date.now()}`;
    const result = await caller.blog.create({
      title: "Test Article API",
      slug: uniqueSlug,
      excerpt: "This is a test article created via API for testing purposes.",
      content: "This is the full content of the test article. It contains enough text to pass validation requirements for the API endpoint.",
      heroImage: "https://example.com/test-image.jpg",
      category: "Test",
      tags: ["test", "api"],
      author: "Leifo",
      readingTime: 5,
      seoTitle: "Test Article SEO Title",
      seoDescription: "Test article SEO description",
      seoKeywords: ["test", "api", "blog"],
      published: false,
    });

    expect(result.success).toBe(true);
    expect(typeof result.id).toBe('number');
  });

  it("should prevent non-admin from creating an article", async () => {
    const ctx = createUserContext();
    const caller = appRouter.createCaller(ctx);

    await expect(
      caller.blog.create({
        title: "Unauthorized Article",
        slug: "unauthorized-article",
        excerpt: "This should not be created by a regular user.",
        content: "Content that should not be saved because the user is not an admin.",
        heroImage: "https://example.com/unauthorized.jpg",
        category: "Test",
        tags: ["test"],
        author: "Leifo",
        readingTime: 3,
        published: false,
      })
    ).rejects.toThrow();
  });

  it("should allow admin to update an article", async () => {
    const ctx = createAdminContext();
    const caller = appRouter.createCaller(ctx);

    // Get an existing article first
    const articles = await caller.blog.getAll();
    if (articles.length === 0) {
      // Skip test if no articles exist
      return;
    }

    const result = await caller.blog.update({
      id: articles[0]!.id,
      title: "Updated Test Article",
      excerpt: "This article has been updated via the API.",
    });

    expect(result.success).toBe(true);
  });

  it("should allow admin to publish/unpublish an article", async () => {
    const ctx = createAdminContext();
    const caller = appRouter.createCaller(ctx);

    // Get an existing article first
    const articles = await caller.blog.getAll();
    if (articles.length === 0) {
      return;
    }

    // Publish
    const publishResult = await caller.blog.publish({
      id: articles[0]!.id,
      published: true,
    });
    expect(publishResult.success).toBe(true);

    // Unpublish
    const unpublishResult = await caller.blog.publish({
      id: articles[0]!.id,
      published: false,
    });
    expect(unpublishResult.success).toBe(true);
  });

  it("should verify delete endpoint exists and requires admin", async () => {
    const ctx = createAdminContext();
    const caller = appRouter.createCaller(ctx);

    // Just verify the endpoint exists and is callable by admin
    // We won't actually delete to avoid breaking other tests
    expect(caller.blog.delete).toBeDefined();
  });

  it("should prevent non-admin from deleting an article", async () => {
    const ctx = createUserContext();
    const caller = appRouter.createCaller(ctx);

    await expect(
      caller.blog.delete({
        id: 1,
      })
    ).rejects.toThrow();
  });
});

describe("Blog API - Public Access", () => {
  it("should allow public access to published articles", async () => {
    const ctx = createPublicContext();
    const caller = appRouter.createCaller(ctx);

    const articles = await caller.blog.getAll();

    expect(Array.isArray(articles)).toBe(true);
    // All returned articles should be published
    articles.forEach((article) => {
      expect(article.published).toBe(true);
    });
  });

  it("should allow public access to article by slug", async () => {
    const ctx = createPublicContext();
    const caller = appRouter.createCaller(ctx);

    const article = await caller.blog.getBySlug({
      slug: "optimiser-seo-site-web-2025",
    });

    if (article) {
      expect(article.slug).toBe("optimiser-seo-site-web-2025");
      // Article may have been unpublished by previous test
      expect(typeof article.published).toBe('boolean');
    }
  });
});
