/**
 * Browser/React Native-safe org, workspace, membership, and license client
 * for platform-service.
 *
 * All org routes require admin-only access (super_admin or admin JWT role).
 * No Node.js dependencies — uses globalThis.fetch.
 */

import type {
  LicenseDoc,
  MembershipDoc,
  OrgClient,
  OrgClientConfig,
  OrganizationDoc,
  WorkspaceDoc,
} from './types.js';

function generateRequestId(): string {
  return typeof globalThis.crypto?.randomUUID === 'function'
    ? globalThis.crypto.randomUUID()
    : `${Date.now()}-${Math.random().toString(36).slice(2, 10)}`;
}

export function createOrgClient(config: OrgClientConfig): OrgClient {
  const { baseUrl, productId, getAccessToken } = config;

  function headers(): Record<string, string> {
    const h: Record<string, string> = {
      'Content-Type': 'application/json',
      'x-product-id': productId,
      'x-request-id': generateRequestId(),
    };
    const token = getAccessToken();
    if (token) h['Authorization'] = `Bearer ${token}`;
    return h;
  }

  // ── Organizations ─────────────────────────────────

  async function listOrgs(query?: { status?: string; limit?: number }): Promise<OrganizationDoc[]> {
    const params = new URLSearchParams();
    if (query?.status) params.set('status', query.status);
    if (query?.limit) params.set('limit', String(query.limit));
    const qs = params.toString();
    const url = qs ? `${baseUrl}/orgs?${qs}` : `${baseUrl}/orgs`;
    const res = await globalThis.fetch(url, { headers: headers() });
    if (!res.ok) throw new Error(`listOrgs failed: ${res.status}`);
    return (await res.json()) as OrganizationDoc[];
  }

  async function createOrg(input: {
    name: string;
    slug: string;
    ownerUserId?: string;
  }): Promise<OrganizationDoc> {
    const res = await globalThis.fetch(`${baseUrl}/orgs`, {
      method: 'POST',
      headers: headers(),
      body: JSON.stringify({ ...input, productId }),
    });
    if (!res.ok) throw new Error(`createOrg failed: ${res.status}`);
    return (await res.json()) as OrganizationDoc;
  }

  async function getOrg(id: string): Promise<OrganizationDoc> {
    const res = await globalThis.fetch(`${baseUrl}/orgs/${encodeURIComponent(id)}`, {
      headers: headers(),
    });
    if (!res.ok) throw new Error(`getOrg failed: ${res.status}`);
    return (await res.json()) as OrganizationDoc;
  }

  async function updateOrg(
    id: string,
    updates: Partial<OrganizationDoc>
  ): Promise<OrganizationDoc> {
    const res = await globalThis.fetch(`${baseUrl}/orgs/${encodeURIComponent(id)}`, {
      method: 'PATCH',
      headers: headers(),
      body: JSON.stringify(updates),
    });
    if (!res.ok) throw new Error(`updateOrg failed: ${res.status}`);
    return (await res.json()) as OrganizationDoc;
  }

  // ── Workspaces ────────────────────────────────────

  async function listWorkspaces(orgId: string): Promise<WorkspaceDoc[]> {
    const res = await globalThis.fetch(`${baseUrl}/orgs/${encodeURIComponent(orgId)}/workspaces`, {
      headers: headers(),
    });
    if (!res.ok) throw new Error(`listWorkspaces failed: ${res.status}`);
    return (await res.json()) as WorkspaceDoc[];
  }

  async function createWorkspace(
    orgId: string,
    input: { name: string; slug: string; description?: string }
  ): Promise<WorkspaceDoc> {
    const res = await globalThis.fetch(`${baseUrl}/orgs/${encodeURIComponent(orgId)}/workspaces`, {
      method: 'POST',
      headers: headers(),
      body: JSON.stringify(input),
    });
    if (!res.ok) throw new Error(`createWorkspace failed: ${res.status}`);
    return (await res.json()) as WorkspaceDoc;
  }

  async function updateWorkspace(
    orgId: string,
    workspaceId: string,
    updates: Partial<WorkspaceDoc>
  ): Promise<WorkspaceDoc> {
    const res = await globalThis.fetch(
      `${baseUrl}/orgs/${encodeURIComponent(orgId)}/workspaces/${encodeURIComponent(workspaceId)}`,
      {
        method: 'PATCH',
        headers: headers(),
        body: JSON.stringify(updates),
      }
    );
    if (!res.ok) throw new Error(`updateWorkspace failed: ${res.status}`);
    return (await res.json()) as WorkspaceDoc;
  }

  // ── Memberships ───────────────────────────────────

  async function listMemberships(
    orgId: string,
    query?: { scope?: string; limit?: number }
  ): Promise<MembershipDoc[]> {
    const params = new URLSearchParams();
    if (query?.scope) params.set('scope', query.scope);
    if (query?.limit) params.set('limit', String(query.limit));
    const qs = params.toString();
    const url = qs
      ? `${baseUrl}/orgs/${encodeURIComponent(orgId)}/memberships?${qs}`
      : `${baseUrl}/orgs/${encodeURIComponent(orgId)}/memberships`;
    const res = await globalThis.fetch(url, { headers: headers() });
    if (!res.ok) throw new Error(`listMemberships failed: ${res.status}`);
    return (await res.json()) as MembershipDoc[];
  }

  async function addMember(
    orgId: string,
    input: { userId: string; role?: string; scope?: string; workspaceId?: string }
  ): Promise<MembershipDoc> {
    const res = await globalThis.fetch(`${baseUrl}/orgs/${encodeURIComponent(orgId)}/memberships`, {
      method: 'POST',
      headers: headers(),
      body: JSON.stringify(input),
    });
    if (!res.ok) throw new Error(`addMember failed: ${res.status}`);
    return (await res.json()) as MembershipDoc;
  }

  async function updateMember(
    orgId: string,
    membershipId: string,
    updates: { role?: string; status?: string }
  ): Promise<MembershipDoc> {
    const res = await globalThis.fetch(
      `${baseUrl}/orgs/${encodeURIComponent(orgId)}/memberships/${encodeURIComponent(membershipId)}`,
      {
        method: 'PATCH',
        headers: headers(),
        body: JSON.stringify(updates),
      }
    );
    if (!res.ok) throw new Error(`updateMember failed: ${res.status}`);
    return (await res.json()) as MembershipDoc;
  }

  // ── Licenses ──────────────────────────────────────

  async function generateLicense(input: {
    userId: string;
    plan: string;
    maxDevices?: number;
  }): Promise<LicenseDoc> {
    const res = await globalThis.fetch(`${baseUrl}/licenses`, {
      method: 'POST',
      headers: headers(),
      body: JSON.stringify({ ...input, productId }),
    });
    if (!res.ok) throw new Error(`generateLicense failed: ${res.status}`);
    return (await res.json()) as LicenseDoc;
  }

  async function activateLicense(input: { key: string; deviceId: string }): Promise<LicenseDoc> {
    const res = await globalThis.fetch(`${baseUrl}/licenses/activate`, {
      method: 'POST',
      headers: headers(),
      body: JSON.stringify(input),
    });
    if (!res.ok) throw new Error(`activateLicense failed: ${res.status}`);
    return (await res.json()) as LicenseDoc;
  }

  async function deactivateLicense(input: { key: string; deviceId: string }): Promise<void> {
    const res = await globalThis.fetch(`${baseUrl}/licenses/deactivate`, {
      method: 'POST',
      headers: headers(),
      body: JSON.stringify(input),
    });
    if (!res.ok) throw new Error(`deactivateLicense failed: ${res.status}`);
  }

  return {
    listOrgs,
    createOrg,
    getOrg,
    updateOrg,
    listWorkspaces,
    createWorkspace,
    updateWorkspace,
    listMemberships,
    addMember,
    updateMember,
    generateLicense,
    activateLicense,
    deactivateLicense,
  };
}
