'use client';

import { useCallback, useRef, useState } from 'react';

function normalizeAuditRows(payload) {
  return Array.isArray(payload)
    ? payload
    : (Array.isArray(payload?.rows) ? payload.rows : (Array.isArray(payload?.data) ? payload.data : []));
}

export function useShareData() {
  const cacheRef = useRef(new Map());
  const [version, setVersion] = useState(0);

  const readArtifactShareData = useCallback(async (artifactId, { force = false } = {}) => {
    if (!artifactId) return null;
    if (!force && cacheRef.current.has(artifactId)) return cacheRef.current.get(artifactId);

    const [aclRes, linksRes, auditRes] = await Promise.all([
      fetch(`/api/artifacts/${artifactId}/acl`),
      fetch(`/api/artifacts/${artifactId}/share-link`),
      fetch(`/api/audit/search?action_target_type=artifact&action_target_id=${artifactId}&limit=5`),
    ]);

    const next = { acl: null, links: [], auditRows: [] };
    if (aclRes.ok) {
      const { data } = await aclRes.json();
      next.acl = data;
    }
    if (linksRes.ok) {
      const { data } = await linksRes.json();
      next.links = Array.isArray(data) ? data : [];
    }
    if (auditRes.ok) {
      next.auditRows = normalizeAuditRows(await auditRes.json()).slice(0, 5);
    }
    cacheRef.current.set(artifactId, next);
    setVersion((v) => v + 1);
    return next;
  }, []);

  const invalidateArtifactShareData = useCallback((artifactId) => {
    if (artifactId) cacheRef.current.delete(artifactId);
    else cacheRef.current.clear();
    setVersion((v) => v + 1);
  }, []);

  // Project-level share data: the cloud publish status (visibility / shared),
  // the per-principal ACL grants (only when published), and the org member list
  // that feeds the "add member" picker. Cached under a `project:` key namespace
  // so it never collides with artifact ids.
  const readProjectShareData = useCallback(async (projectId, { force = false } = {}) => {
    if (!projectId) return null;
    const cacheKey = `project:${projectId}`;
    if (!force && cacheRef.current.has(cacheKey)) return cacheRef.current.get(cacheKey);

    const next = { status: null, cloudReady: false, grants: [], members: [], orgId: null, error: null };

    const [statusRes, orgsRes] = await Promise.all([
      fetch(`/api/shared/spaces/status?local_space_id=${encodeURIComponent(projectId)}&space_type=project`),
      fetch('/api/orgs'),
    ]);

    if (statusRes.ok) {
      const d = await statusRes.json();
      next.status = d.status || null;
      next.cloudReady = !!d.cloud_ready;
    }
    if (orgsRes.ok) {
      const { orgs } = await orgsRes.json();
      next.orgId = Array.isArray(orgs) && orgs.length ? (orgs[0].org_id || orgs[0].id || null) : null;
    }

    // Grants only exist once the project is published to the shared cloud.
    if (next.status?.shared) {
      const aclRes = await fetch(`/api/shared/spaces/${encodeURIComponent(projectId)}/acl?space_type=project`);
      if (aclRes.ok) {
        const { data } = await aclRes.json();
        next.grants = Array.isArray(data) ? data : [];
      }
    }
    if (next.orgId) {
      const memRes = await fetch(`/api/orgs/${encodeURIComponent(next.orgId)}/members`);
      if (memRes.ok) {
        const { members } = await memRes.json();
        next.members = Array.isArray(members) ? members : [];
      }
    }

    cacheRef.current.set(cacheKey, next);
    setVersion((v) => v + 1);
    return next;
  }, []);

  const invalidateProjectShareData = useCallback((projectId) => {
    if (projectId) cacheRef.current.delete(`project:${projectId}`);
    else cacheRef.current.clear();
    setVersion((v) => v + 1);
  }, []);

  return {
    readArtifactShareData,
    invalidateArtifactShareData,
    readProjectShareData,
    invalidateProjectShareData,
    shareDataVersion: version,
  };
}
