import { describe, expect, it } from "vitest";
import { appRouter } from "./routers";
import type { TrpcContext } from "./_core/context";

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 createPublicContext(): TrpcContext {
  return {
    user: null,
    req: {
      protocol: "https",
      headers: {},
    } as TrpcContext["req"],
    res: {} as TrpcContext["res"],
  };
}

describe("Analytics API - View Tracking", () => {
  it("should allow public users to track article views", async () => {
    const ctx = createPublicContext();
    const caller = appRouter.createCaller(ctx);

    const result = await caller.blog.trackView({
      articleId: 1,
      userAgent: "Mozilla/5.0 Test Browser",
      referrer: "https://google.com",
    });

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

  it("should allow public users to get view count", async () => {
    const ctx = createPublicContext();
    const caller = appRouter.createCaller(ctx);

    const result = await caller.blog.getViewCount({
      articleId: 1,
    });

    expect(typeof result.count).toBe("number");
    expect(result.count).toBeGreaterThanOrEqual(0);
  });
});

describe("Analytics API - Admin Stats", () => {
  it("should allow admin to get blog stats", async () => {
    const ctx = createAdminContext();
    const caller = appRouter.createCaller(ctx);

    const stats = await caller.blog.getStats();

    expect(stats).toBeDefined();
    expect(typeof stats.totalArticles).toBe("number");
    expect(typeof stats.publishedArticles).toBe("number");
    expect(typeof stats.draftArticles).toBe("number");
    expect(typeof stats.totalViews).toBe("number");
    expect(typeof stats.avgViewsPerArticle).toBe("number");
  });

  it("should allow admin to get top articles", async () => {
    const ctx = createAdminContext();
    const caller = appRouter.createCaller(ctx);

    const topArticles = await caller.blog.getTopArticles({ limit: 5 });

    expect(Array.isArray(topArticles)).toBe(true);
    // Each article should have viewCount
    topArticles.forEach((article: any) => {
      expect(typeof article.viewCount).toBe("number");
      expect(article.viewCount).toBeGreaterThan(0);
    });
  });

  it("should allow admin to get views by date", async () => {
    const ctx = createAdminContext();
    const caller = appRouter.createCaller(ctx);

    const viewsByDate = await caller.blog.getViewsByDate({ days: 30 });

    expect(Array.isArray(viewsByDate)).toBe(true);
    viewsByDate.forEach((item: any) => {
      expect(item.date).toBeDefined();
      expect(typeof item.views).toBe("number");
    });
  });

  it("should allow admin to get stats by category", async () => {
    const ctx = createAdminContext();
    const caller = appRouter.createCaller(ctx);

    const statsByCategory = await caller.blog.getStatsByCategory();

    expect(Array.isArray(statsByCategory)).toBe(true);
    statsByCategory.forEach((stat: any) => {
      expect(stat.category).toBeDefined();
      expect(typeof stat.articles).toBe("number");
      expect(typeof stat.views).toBe("number");
    });
  });

  it("should prevent non-admin from accessing admin stats", async () => {
    const ctx = createPublicContext();
    const caller = appRouter.createCaller(ctx);

    await expect(caller.blog.getStats()).rejects.toThrow();
    await expect(caller.blog.getTopArticles()).rejects.toThrow();
    await expect(caller.blog.getViewsByDate()).rejects.toThrow();
    await expect(caller.blog.getStatsByCategory()).rejects.toThrow();
  });
});
