import { registered, supports } from "./registry.ts";
import type { NativeTarget } from "./types.ts";
export type NativePermission =
  "camera" | "geolocation" | "microphone" | "notifications" | "photos" | "storage" | (string & {});
export interface NativeCapabilityManifestEntry {
  name: string;
  description?: string;
  permissions?: NativePermission[];
  targets?: NativeTarget[];
  optional?: boolean;
}
export interface NativeCapabilityManifest {
  name: string;
  version?: string;
  capabilities: NativeCapabilityManifestEntry[];
}
export function defineNativeManifest<T extends NativeCapabilityManifest>(manifest: T): T {
  const names = new Set<string>();
  for (const capability of manifest.capabilities) {
    if (!/^[A-Za-z][A-Za-z0-9.-]*$/.test(capability.name))
      throw new TypeError(`Invalid native capability: ${capability.name}`);
    if (names.has(capability.name))
      throw new Error(`Duplicate native capability: ${capability.name}`);
    names.add(capability.name);
  }
  return manifest;
}
export function inspectNativeCapabilities(
  target?: NativeTarget,
): Array<{ name: string; supported: boolean }> {
  return registered().map((name) => ({ name, supported: supports(name, target) }));
}
export function missingNativeCapabilities(
  manifest: NativeCapabilityManifest,
  target?: NativeTarget,
): NativeCapabilityManifestEntry[] {
  return manifest.capabilities.filter(
    (capability) =>
      !capability.optional &&
      (!capability.targets || !target || capability.targets.includes(target)) &&
      !supports(capability.name, target),
  );
}
export interface PermissionAdapter {
  query(name: NativePermission): Promise<"granted" | "denied" | "prompt" | "unavailable">;
  request?(name: NativePermission): Promise<"granted" | "denied">;
}
export class PermissionManager {
  constructor(private readonly adapter: PermissionAdapter) {}
  query(name: NativePermission) {
    return this.adapter.query(name);
  }
  async ensure(name: NativePermission): Promise<boolean> {
    const state = await this.adapter.query(name);
    if (state === "granted") return true;
    if (state === "prompt" && this.adapter.request)
      return (await this.adapter.request(name)) === "granted";
    return false;
  }
}
