/**
 * `usePlugins` — view-model hook for the `Paramètres > Plugins` admin surface
 * (ticket #43, F2). Consumes {@link PluginGateway} exclusively; never touches
 * `invoke()` (ARCHITECTURE §1.3), so it is fully testable with the mock.
 */

import { useCallback, useEffect, useState } from "react";

import type { GatewayError, PluginAdmin, PluginReview } from "@/domain";
import type { ReviewPluginPackageInput } from "@/ports";
import { useGateways } from "@/app/di";

export interface PluginsViewModel {
  plugins: PluginAdmin[];
  error: string | null;
  busy: boolean;
  refresh: () => Promise<void>;
  reviewArchive: (path: string) => Promise<PluginReview | null>;
  reviewDirectory: (path: string) => Promise<PluginReview | null>;
  installFromArchive: (path: string) => Promise<boolean>;
  installFromDirectory: (path: string) => Promise<boolean>;
  setEnabled: (pluginId: string, enabled: boolean) => Promise<void>;
  uninstall: (pluginId: string) => Promise<void>;
  openPluginsFolder: (pluginId?: string) => Promise<void>;
  pickArchiveFile: () => Promise<string | null>;
  pickDirectory: () => Promise<string | null>;
}

function describe(e: unknown): string {
  if (e && typeof e === "object" && "message" in e) {
    return String((e as GatewayError).message);
  }
  return String(e);
}

export function usePlugins(): PluginsViewModel {
  const { plugin, system } = useGateways();

  const [plugins, setPlugins] = useState<PluginAdmin[]>([]);
  const [error, setError] = useState<string | null>(null);
  const [busy, setBusy] = useState(false);

  const refresh = useCallback(async () => {
    setBusy(true);
    setError(null);
    try {
      setPlugins(await plugin.listPlugins());
    } catch (e) {
      setError(describe(e));
    } finally {
      setBusy(false);
    }
  }, [plugin]);

  useEffect(() => {
    void refresh();
  }, [refresh]);

  const review = useCallback(
    async (input: ReviewPluginPackageInput): Promise<PluginReview | null> => {
      setBusy(true);
      setError(null);
      try {
        return await plugin.reviewPackage(input);
      } catch (e) {
        setError(describe(e));
        return null;
      } finally {
        setBusy(false);
      }
    },
    [plugin],
  );

  const reviewArchive = useCallback(
    (path: string) => review({ sourceKind: "archive", path }),
    [review],
  );
  const reviewDirectory = useCallback(
    (path: string) => review({ sourceKind: "directory", path }),
    [review],
  );

  const installFromArchive = useCallback(
    async (path: string): Promise<boolean> => {
      setBusy(true);
      setError(null);
      try {
        await plugin.installFromArchive(path);
        setPlugins(await plugin.listPlugins());
        return true;
      } catch (e) {
        setError(describe(e));
        return false;
      } finally {
        setBusy(false);
      }
    },
    [plugin],
  );

  const installFromDirectory = useCallback(
    async (path: string): Promise<boolean> => {
      setBusy(true);
      setError(null);
      try {
        await plugin.installFromDirectory(path);
        setPlugins(await plugin.listPlugins());
        return true;
      } catch (e) {
        setError(describe(e));
        return false;
      } finally {
        setBusy(false);
      }
    },
    [plugin],
  );

  const setEnabled = useCallback(
    async (pluginId: string, enabled: boolean) => {
      setBusy(true);
      setError(null);
      try {
        await plugin.setEnabled(pluginId, enabled);
        setPlugins(await plugin.listPlugins());
      } catch (e) {
        setError(describe(e));
      } finally {
        setBusy(false);
      }
    },
    [plugin],
  );

  const uninstall = useCallback(
    async (pluginId: string) => {
      setBusy(true);
      setError(null);
      try {
        await plugin.uninstall(pluginId);
        setPlugins(await plugin.listPlugins());
      } catch (e) {
        setError(describe(e));
      } finally {
        setBusy(false);
      }
    },
    [plugin],
  );

  const openPluginsFolder = useCallback(
    async (pluginId?: string) => {
      try {
        await plugin.openPluginsFolder(pluginId);
      } catch (e) {
        setError(describe(e));
      }
    },
    [plugin],
  );

  const pickArchiveFile = useCallback(() => system.pickArchiveFile(), [system]);
  const pickDirectory = useCallback(() => system.pickFolder(), [system]);

  return {
    plugins,
    error,
    busy,
    refresh,
    reviewArchive,
    reviewDirectory,
    installFromArchive,
    installFromDirectory,
    setEnabled,
    uninstall,
    openPluginsFolder,
    pickArchiveFile,
    pickDirectory,
  };
}
