import { test, expect, request } from "@playwright/test";

const API_BASE = "https://test111.nxtgauge.com/api";

test.describe("Security - Authentication", () => {
  test("JWT token is not returned for invalid credentials", async () => {
    const ctx = await request.newContext();
    const res = await ctx.post(`${API_BASE}/auth/login`, {
      data: {
        email: "nonexistent@example.com",
        password: "wrongpassword",
      },
    });

    expect(res.status()).toBe(401);
    const body = await res.json();
    expect(body).not.toHaveProperty("access_token");
  });

  test("Login without email returns proper error", async () => {
    const ctx = await request.newContext();
    const res = await ctx.post(`${API_BASE}/auth/login`, {
      data: {
        password: "somepassword",
      },
    });

    expect([400, 422]).toContain(res.status());
  });

  test("Login without password returns proper error", async () => {
    const ctx = await request.newContext();
    const res = await ctx.post(`${API_BASE}/auth/login`, {
      data: {
        email: "test@example.com",
      },
    });

    expect([400, 422]).toContain(res.status());
  });

  test("Protected endpoint rejects request without token", async () => {
    const ctx = await request.newContext();
    const res = await ctx.get(`${API_BASE}/ai/usage`);

    expect([401, 404]).toContain(res.status());
  });

  test("Protected endpoint rejects request with malformed token", async () => {
    const ctx = await request.newContext();
    const res = await ctx.get(`${API_BASE}/ai/usage`, {
      headers: {
        Authorization: "Bearer invalid.malformed.token",
      },
    });

    expect([401, 404]).toContain(res.status());
  });

  test("Protected endpoint rejects request with empty Bearer token", async () => {
    const ctx = await request.newContext();
    const res = await ctx.get(`${API_BASE}/ai/usage`, {
      headers: {
        Authorization: "Bearer ",
      },
    });

    expect([401, 404]).toContain(res.status());
  });
});

test.describe("Security - Rate Limiting", () => {
  test("Login rate limits after multiple failed attempts", async () => {
    const ctx = await request.newContext();
    const uniqueEmail = `securitytest${Date.now()}@example.com`;

    let rateLimited = false;
    for (let i = 0; i < 5; i++) {
      const res = await ctx.post(`${API_BASE}/auth/login`, {
        data: {
          email: uniqueEmail,
          password: "wrongpassword",
        },
      });
      if (res.status() === 429) {
        rateLimited = true;
        break;
      }
    }

    if (!rateLimited) {
      const res = await ctx.post(`${API_BASE}/auth/login`, {
        data: {
          email: uniqueEmail,
          password: "anypassword",
        },
      });
      if (res.status() === 429) {
        rateLimited = true;
      }
    }

    if (!rateLimited) {
      test.skip();
    }
  });

  test("AI endpoints rate limit after daily quota exceeded", async () => {
    const ctx = await request.newContext();
    const loginRes = await ctx.post(`${API_BASE}/auth/login`, {
      data: {
        email: "testcompany@example.com",
        password: "TestPassword123!",
      },
    });

    if (loginRes.status() === 429) {
      test.skip();
      return;
    }

    const data = await loginRes.json();
    const token = data.access_token;
    if (!token) {
      test.skip();
      return;
    }

    let got429 = false;
    for (let i = 0; i < 10; i++) {
      const res = await ctx.post(`${API_BASE}/ai/generate-job-field`, {
        headers: { Authorization: `Bearer ${token}` },
        data: { field: "title", prompt: `Test ${i}` },
      });

      if (res.status() === 429) {
        got429 = true;
        break;
      }
    }

    if (!got429) {
      console.warn("AI rate limit not triggered within 10 requests - may need more requests or limit is higher");
    }
  });
});

test.describe("Security - Input Validation", () => {
  test("SQL injection in login email is handled safely", async () => {
    const ctx = await request.newContext();
    const res = await ctx.post(`${API_BASE}/auth/login`, {
      data: {
        email: "' OR '1'='1",
        password: "anything",
      },
    });

    expect(res.status()).toBe(401);
    const body = await res.json();
    expect(body).not.toHaveProperty("access_token");
  });

  test("XSS attempt in login email is handled safely", async () => {
    const ctx = await request.newContext();
    const res = await ctx.post(`${API_BASE}/auth/login`, {
      data: {
        email: "<script>alert('xss')</script>@example.com",
        password: "password",
      },
    });

    expect(res.status()).toBe(401);
  });

  test("Very long input is handled without crash", async () => {
    const ctx = await request.newContext();
    const longString = "a".repeat(10000);

    const res = await ctx.post(`${API_BASE}/auth/login`, {
      data: {
        email: `${longString}@example.com`,
        password: longString,
      },
    });

    expect([400, 401, 413]).toContain(res.status());
  });
});

test.describe("Security - CORS Headers", () => {
  test("CORS headers are present on API responses", async () => {
    const ctx = await request.newContext();
    const res = await ctx.get(`${API_BASE}/nonexistent-route`);

    expect(res.status()).toBe(404);
  });
});

test.describe("Security - Authorization", () => {
  test("User cannot access admin endpoints with regular user token", async () => {
    const ctx = await request.newContext();
    const loginRes = await ctx.post(`${API_BASE}/auth/login`, {
      data: {
        email: "testtutora2026@example.com",
        password: "Test1234!",
      },
    });

    if (loginRes.status() === 429) {
      test.skip();
      return;
    }

    const data = await loginRes.json();
    const token = data.access_token;
    if (!token) {
      test.skip();
      return;
    }

    const res = await ctx.get(`${API_BASE}/admin/users`, {
      headers: { Authorization: `Bearer ${token}` },
    });

    expect([403, 404]).toContain(res.status());
  });
});

test.describe("Security - Response Headers", () => {
  test("API does not leak sensitive information in error responses", async () => {
    const ctx = await request.newContext();

    const res = await ctx.post(`${API_BASE}/auth/login`, {
      data: {
        email: "test@example.com",
        password: "wrongpassword",
      },
    });

    const body = await res.json();

    expect(body).not.toHaveProperty("stack");
    expect(body).not.toHaveProperty("debug");
    expect(body).not.toHaveProperty("inner_error");
    expect(body).not.toHaveProperty("innerError");
  });

  test("API error responses do not expose server internals", async () => {
    const ctx = await request.newContext();

    const res = await ctx.get(`${API_BASE}/api/nonexistent`);

    const text = await res.text();

    expect(text).not.toContain("at ");
    expect(text).not.toContain("stack:");
    expect(text).not.toContain(".rs:");
  });
});

test.describe("Security - Token Handling", () => {
  test("Expired token is rejected", async () => {
    const ctx = await request.newContext();

    const expiredToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiZXhwIjoxNjAwMDAwMDAwfQ.dummysignature";

    const res = await ctx.get(`${API_BASE}/ai/usage`, {
      headers: { Authorization: `Bearer ${expiredToken}` },
    });

    expect([401, 404]).toContain(res.status());
  });

  test("Token with invalid signature is rejected", async () => {
    const ctx = await request.newContext();

    const badSigToken = "eyJhbGciOiJIUzI1NiIsInR5cCI6IkpXVCJ9.eyJzdWIiOiIxMjM0NTY3ODkwIiwiaWF0IjoxOTk5OTk5OTk5OX0.wronngsignature";

    const res = await ctx.get(`${API_BASE}/ai/usage`, {
      headers: { Authorization: `Bearer ${badSigToken}` },
    });

    expect([401, 404]).toContain(res.status());
  });
});
