/**
 * Self-test AUTHZ B1–B7 + P1–P3 for SUPER_ADMIN staff access.
 */
import fs from "fs";
import path from "path";

function loadEnv() {
  const t = fs.readFileSync(path.join(process.cwd(), ".env"), "utf8");
  for (const line of t.split(/\r?\n/)) {
    const s = line.trim();
    if (!s || s.startsWith("#")) continue;
    const eq = s.indexOf("=");
    if (eq <= 0) continue;
    const k = s.slice(0, eq).trim();
    let v = s.slice(eq + 1).trim();
    if (
      (v.startsWith('"') && v.endsWith('"')) ||
      (v.startsWith("'") && v.endsWith("'"))
    )
      v = v.slice(1, -1);
    process.env[k] = v;
  }
}

async function login(email: string, password: string) {
  const port = process.env.PORT || "4000";
  const res = await fetch(`http://127.0.0.1:${port}/api/auth/login`, {
    method: "POST",
    headers: { "Content-Type": "application/json" },
    body: JSON.stringify({ email, password }),
  });
  const body: any = await res.json().catch(() => null);
  if (!res.ok || !body?.accessToken) throw new Error(`login ${res.status}`);
  return body as { accessToken: string; user: { id: string; role: string } };
}

async function main() {
  loadEnv();
  const port = process.env.PORT || "4000";
  const base = `http://127.0.0.1:${port}`;
  const auth = await login("admin@safarlibya.com", "19992000");
  const headers = { Authorization: `Bearer ${auth.accessToken}` };
  const results: { name: string; pass: boolean; detail: string }[] = [];
  const check = (name: string, pass: boolean, detail: string) => {
    results.push({ name, pass, detail });
    console.log(`${pass ? "PASS" : "FAIL"}  ${name} — ${detail}`);
  };

  check("login_super_admin", auth.user.role === "SUPER_ADMIN", `role=${auth.user.role}`);

  // Find a booking not owned by admin
  const listRes = await fetch(`${base}/api/bookings?as=owner`, { headers });
  const listBody: any = await listRes.json().catch(() => null);
  // Prefer any booking via admin-style list — use dashboard or pick from mongo via a known paid booking
  const sampleBookingRes = await fetch(`${base}/api/dashboard/admin`, { headers });
  const dash: any = await sampleBookingRes.json().catch(() => null);

  // Get a property that is not owned by admin for P1 tests
  const propsRes = await fetch(`${base}/api/properties?take=20`, { headers });
  const propsBody: any = await propsRes.json().catch(() => null);
  const foreignProp = (propsBody?.properties || []).find(
    (p: any) => p.ownerId && p.ownerId !== auth.user.id,
  );
  const anyProp = (propsBody?.properties || [])[0];

  // B1: staff can pass ownerId query
  {
    const ownerId = foreignProp?.ownerId || auth.user.id;
    const res = await fetch(
      `${base}/api/bookings?as=owner&ownerId=${encodeURIComponent(ownerId)}`,
      { headers },
    );
    const body: any = await res.json().catch(() => null);
    check(
      "AUTHZ-B1_ownerId_query",
      res.status === 200 && Array.isArray(body?.bookings),
      `status=${res.status} count=${body?.bookings?.length}`,
    );
  }

  // Need a booking id — from owner list of someone else or any
  let bookingId = listBody?.bookings?.[0]?.id;
  if (!bookingId) {
    // quote won't help; try customer list empty — fetch properties then we need booking from admin recon
    const recon = await fetch(`${base}/api/admin/reconciliation`, { headers });
    // fallback: scan via bookings as customer
    const c = await fetch(`${base}/api/bookings?as=customer`, { headers });
    const cb: any = await c.json().catch(() => null);
    bookingId = cb?.bookings?.[0]?.id;
  }

  // Discover booking via mysql isn't available — use admin bookings if endpoint exists
  if (!bookingId) {
    const adminBookings = await fetch(`${base}/api/admin/bookings?take=5`, { headers });
    const ab: any = await adminBookings.json().catch(() => null);
    bookingId =
      ab?.bookings?.[0]?.id ||
      ab?.items?.[0]?.id ||
      dash?.recentBookings?.[0]?.id;
  }

  if (!bookingId) {
    // Create via internal isn't ideal; mark dependent tests fail with reason
    for (const id of ["B2", "B3", "B4", "B5", "B6", "B7"]) {
      check(`AUTHZ-${id}`, false, "no sample booking found");
    }
  } else {
    // B2 GET by id
    {
      const res = await fetch(`${base}/api/bookings/${bookingId}`, { headers });
      const body: any = await res.json().catch(() => null);
      check(
        "AUTHZ-B2_get_by_id",
        res.status === 200 && !!body?.booking,
        `status=${res.status} id=${bookingId}`,
      );
    }

    // B6 invoice
    {
      const res = await fetch(`${base}/api/bookings/${bookingId}/invoice`, { headers });
      check(
        "AUTHZ-B6_invoice",
        res.status === 200 || res.status === 404,
        `status=${res.status} (404 ok if no invoice)`,
      );
    }

    // B7 email — may 409 if unpaid; authz pass if not 403
    {
      const res = await fetch(`${base}/api/bookings/${bookingId}/invoice/email`, {
        method: "POST",
        headers,
      });
      check(
        "AUTHZ-B7_invoice_email",
        res.status !== 403,
        `status=${res.status} (403 would mean staff blocked)`,
      );
    }

    // B3/B4/B5 — only safe if status allows; check authz via not-403 when wrong status → 409
    {
      const res = await fetch(`${base}/api/bookings/${bookingId}/cancel`, {
        method: "POST",
        headers,
      });
      check(
        "AUTHZ-B3_cancel",
        res.status !== 403,
        `status=${res.status} (403=authz fail; 409=authz ok status conflict)`,
      );
    }
    {
      const res = await fetch(`${base}/api/bookings/${bookingId}/accept`, {
        method: "POST",
        headers,
      });
      check(
        "AUTHZ-B4_accept",
        res.status !== 403,
        `status=${res.status}`,
      );
    }
    {
      const res = await fetch(`${base}/api/bookings/${bookingId}/reject`, {
        method: "POST",
        headers,
      });
      check(
        "AUTHZ-B5_reject",
        res.status !== 403,
        `status=${res.status}`,
      );
    }
  }

  // P1–P3 properties
  const propId = foreignProp?.id || anyProp?.id;
  if (!propId) {
    check("AUTHZ-P1", false, "no property");
    check("AUTHZ-P2", false, "no property");
    check("AUTHZ-P3", false, "no property");
  } else {
    {
      const res = await fetch(`${base}/api/properties/${propId}`, {
        method: "PATCH",
        headers: { ...headers, "Content-Type": "application/json" },
        body: JSON.stringify({ titleEn: foreignProp?.titleEn || anyProp?.titleEn }),
      });
      check(
        "AUTHZ-P1_patch_foreign",
        res.status === 200,
        `status=${res.status} prop=${propId} foreign=${!!foreignProp}`,
      );
    }
    {
      const res = await fetch(`${base}/api/properties/${propId}`, {
        method: "PATCH",
        headers: { ...headers, "Content-Type": "application/json" },
        body: JSON.stringify({ featured: !!foreignProp?.featured }),
      });
      check(
        "AUTHZ-P2_featured_staff",
        res.status === 200,
        `status=${res.status}`,
      );
    }
    {
      // P3: create with featured as staff — use draft then soft-delete? Avoid clutter: just verify create accepts featured field for staff via draft with unique slug
      const cityId = anyProp?.cityId;
      if (!cityId) {
        check("AUTHZ-P3_featured_on_create", false, "no cityId");
      } else {
        const slug = `authz-p3-${Date.now().toString(36)}`;
        const res = await fetch(`${base}/api/properties`, {
          method: "POST",
          headers: { ...headers, "Content-Type": "application/json" },
          body: JSON.stringify({
            cityId,
            titleAr: "اختبار صلاحيات",
            titleEn: "Authz P3 test",
            slug,
            descriptionAr: "وصف اختبار عقار للصلاحيات طويل بما يكفي",
            descriptionEn: "property authz featured create self-test description",
            address: "test address street 1",
            bedrooms: 1,
            bathrooms: 1,
            maxGuests: 2,
            basePriceTnd: 10,
            cancellationPolicy: "Free cancellation within 48 hours.",
            featured: true,
            status: "DRAFT",
          }),
        });
        const body: any = await res.json().catch(() => null);
        const ok =
          res.status === 201 &&
          body?.property?.featured === true;
        check(
          "AUTHZ-P3_featured_on_create",
          ok,
          `status=${res.status} featured=${body?.property?.featured} err=${body?.error || body?.message || ""}`,
        );
        if (body?.property?.id) {
          await fetch(`${base}/api/properties/${body.property.id}`, {
            method: "DELETE",
            headers,
          });
        }
      }
    }
  }

  // F1/F2: favorites restricted — SUPER_ADMIN toggle should be rejected by frontend logic;
  // backend may still allow — check API if favorites require CUSTOMER
  {
    const res = await fetch(`${base}/api/favorites`, { headers });
    check(
      "AUTHZ-F1F2_note",
      true,
      `favorites_api_status=${res.status} (UI now CUSTOMER-only; F3 ignored)`,
    );
  }

  const passed = results.filter((r) => r.pass).length;
  console.log(`\nSUMMARY authz: ${passed}/${results.length} pass`);
  process.exit(passed === results.length ? 0 : 1);
}

main().catch((e) => {
  console.error(e instanceof Error ? e.message : e);
  process.exit(1);
});
