"use client";

// Client-side container for the /access page: loads eligible/active/
// pending lists in parallel, hosts the request modal, handles revoke.

import { useCallback, useEffect, useState } from "react";
import RequestModal, { type EligibleRow } from "./RequestModal";

type ActiveGrant = {
  id: string;
  roleName: string;
  grantedAt: string;
  expiresAt: string;
  justification: string;
};

type PendingGrant = {
  id: string;
  roleName: string;
  requestedAt: string;
  expiresAt: string;
  justification: string;
};

function fmtRemaining(expiresAt: string): string {
  const diffMs = new Date(expiresAt).getTime() - Date.now();
  if (diffMs <= 0) return "expired";
  const h = Math.floor(diffMs / 3_600_000);
  const m = Math.floor((diffMs % 3_600_000) / 60_000);
  if (h > 0) return `${h}h ${m}m`;
  return `${m}m`;
}

export default function AccessPageClient({ needRole = null }: { needRole?: string | null }) {
  const [eligible, setEligible] = useState<EligibleRow[]>([]);
  const [active, setActive] = useState<ActiveGrant[]>([]);
  const [pending, setPending] = useState<PendingGrant[]>([]);
  const [loading, setLoading] = useState(true);

  const [modalRow, setModalRow] = useState<EligibleRow | null>(null);
  const [modalOpen, setModalOpen] = useState(false);
  const [needAutoOpened, setNeedAutoOpened] = useState(false);

  const refresh = useCallback(async () => {
    setLoading(true);
    try {
      const [e, a] = await Promise.all([
        fetch("/api/pam/eligible", { cache: "no-store" }).then((r) => r.json()),
        fetch("/api/pam/active",   { cache: "no-store" }).then((r) => r.json()),
      ]);
      setEligible(e.eligible ?? []);
      setActive(a.active ?? []);
      // pending grants aren't a dedicated endpoint — pull via audit
      // for now (low-volume). Mirror via /api/pam/active expansion
      // in a future iteration.
    } finally {
      setLoading(false);
    }
  }, []);

  useEffect(() => {
    void refresh();
    const t = setInterval(refresh, 30_000);
    return () => clearInterval(t);
  }, [refresh]);

  // Auto-open the request modal for the role the caller asked for
  // (via /access?need=<role>), but only once and only if the user is
  // actually eligible.
  useEffect(() => {
    if (!needRole || needAutoOpened || eligible.length === 0) return;
    const row = eligible.find((r) => r.role === needRole && r.policy && !r.currentlyActive);
    if (row) {
      setModalRow(row);
      setModalOpen(true);
      setNeedAutoOpened(true);
    }
  }, [needRole, needAutoOpened, eligible]);

  const revoke = async (id: string) => {
    setActive((g) => g.filter((x) => x.id !== id));
    await fetch(`/api/pam/revoke/${encodeURIComponent(id)}`, { method: "POST" });
    void refresh();
  };

  return (
    <div className="container py-4">
      <h2 className="mb-4">
        <i className="ph ph-key me-2" aria-hidden="true"></i>
        Privileged Access
      </h2>
      <p className="text-muted mb-4">
        Request just-in-time access to administrative roles. Grants expire
        automatically and don&apos;t require you to sign in again.
      </p>

      {needRole && (
        <div className="alert alert-info py-2 mb-4 small">
          <i className="ph ph-info me-1" aria-hidden="true"></i>
          The page you tried to open requires <code>{needRole}</code>. Request
          elevation below, then re-navigate.
        </div>
      )}

      {/* ACTIVE */}
      <h5 className="mt-4 mb-2">Active</h5>
      {active.length === 0 ? (
        <div className="text-muted small mb-4">No active grants.</div>
      ) : (
        <div className="table-responsive mb-4">
          <table className="table table-sm align-middle">
            <thead>
              <tr>
                <th>Role</th>
                <th>Granted</th>
                <th>Expires</th>
                <th>Remaining</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {active.map((g) => (
                <tr key={g.id}>
                  <td><code>{g.roleName}</code></td>
                  <td className="small text-muted">{new Date(g.grantedAt).toLocaleString()}</td>
                  <td className="small text-muted">{new Date(g.expiresAt).toLocaleString()}</td>
                  <td><span className="badge bg-success-subtle text-success-emphasis">{fmtRemaining(g.expiresAt)}</span></td>
                  <td className="text-end">
                    <button
                      type="button"
                      className="btn btn-sm btn-outline-danger"
                      onClick={() => revoke(g.id)}
                    >
                      <i className="ph ph-x me-1"></i>Revoke
                    </button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      {/* ELIGIBLE */}
      <h5 className="mt-4 mb-2">Eligible</h5>
      {loading && eligible.length === 0 ? (
        <div className="text-muted small">Loading…</div>
      ) : eligible.length === 0 ? (
        <div className="text-muted small">
          You aren&apos;t a member of any <code>*_eligible</code> group. Ask an administrator
          to add you to one if you need elevated access.
        </div>
      ) : (
        <div className="table-responsive">
          <table className="table table-sm align-middle">
            <thead>
              <tr>
                <th>Role</th>
                <th>Approval</th>
                <th>MFA</th>
                <th>Max duration</th>
                <th></th>
              </tr>
            </thead>
            <tbody>
              {eligible.map((row) => (
                <tr key={row.role}>
                  <td>
                    <code>{row.role}</code>
                    {row.policy?.description && (
                      <div className="small text-muted">{row.policy.description}</div>
                    )}
                  </td>
                  <td>
                    {row.policy ? (
                      <span className={`badge ${row.policy.approvalMode === "audit" ? "bg-success-subtle text-success-emphasis" : "bg-info-subtle text-info-emphasis"}`}>
                        {row.policy.approvalMode}
                      </span>
                    ) : (
                      <span className="badge bg-secondary-subtle text-secondary-emphasis">no policy</span>
                    )}
                  </td>
                  <td>
                    {row.policy?.requiresMfa ? (
                      <i className="ph ph-shield-check text-warning" title="MFA required"></i>
                    ) : (
                      <span className="text-muted small">—</span>
                    )}
                  </td>
                  <td className="small text-muted">
                    {row.policy ? `${row.policy.maxDurationHours}h` : "—"}
                  </td>
                  <td className="text-end">
                    <button
                      type="button"
                      className="btn btn-sm btn-primary"
                      disabled={!row.policy || row.currentlyActive}
                      onClick={() => {
                        setModalRow(row);
                        setModalOpen(true);
                      }}
                    >
                      {row.currentlyActive ? "Already active" : "Request"}
                    </button>
                  </td>
                </tr>
              ))}
            </tbody>
          </table>
        </div>
      )}

      <RequestModal
        row={modalRow}
        open={modalOpen}
        onClose={() => setModalOpen(false)}
        onSuccess={refresh}
      />
    </div>
  );
}
