/**
 * PythonPackagesPanel.tsx — ワークスペースごとの Python パッケージ管理 UI
 *
 * admin/オーナーが wheel パッケージ名を直接入力して、そのワークスペース専用の
 * オーバーレイに追加する。追加したパッケージは、そのワークスペースのエージェント
 * だけが `import` できる（他ワークスペースには波及しない）。
 *
 * - GET/POST/DELETE /api/local/spaces/:id/python-packages（canManageSpace が編集）
 * - インストールはサーバー側で out-of-band に実行（ネットワークは分離 bwrap のみ）。
 *   wheels のみ許可（sdist の任意コード実行を回避）。
 */

import { useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import {
  fetchSpacePythonPackages,
  fetchSpaceMembers,
  addSpacePythonPackage,
  removeSpacePythonPackage,
} from '../../api';
import { useAuthState } from '../../App';

type ShowToast = (message: string, variant?: 'success' | 'error') => void;

function errMsg(e: unknown): string {
  return e instanceof Error ? e.message : String(e);
}

export function PythonPackagesPanel({ spaceId, showToast }: { spaceId: string; showToast?: ShowToast }) {
  const { t } = useTranslation('spaces');
  const auth = useAuthState();
  const qc = useQueryClient();
  const [input, setInput] = useState('');

  const { data: members } = useQuery({
    queryKey: ['space-members', spaceId],
    queryFn: () => fetchSpaceMembers(spaceId),
    staleTime: 30_000,
  });
  const ownerRow = (members ?? []).find(m => m.isOwner);
  const canManage =
    auth.mode === 'disabled' ||
    (auth.mode === 'authenticated' &&
      (auth.user.role === 'admin' || (!!ownerRow && ownerRow.userId === auth.user.id)));

  const { data, isLoading, isError, error } = useQuery({
    queryKey: ['space-python-packages', spaceId],
    queryFn: () => fetchSpacePythonPackages(spaceId),
    staleTime: 15_000,
  });

  const invalidate = () => qc.invalidateQueries({ queryKey: ['space-python-packages', spaceId] });

  const addMut = useMutation({
    mutationFn: (spec: string) => addSpacePythonPackage(spaceId, spec),
    onSuccess: () => {
      setInput('');
      showToast?.(t('python.added'), 'success');
      void invalidate();
    },
    onError: (e) => showToast?.(t('python.addFailed', { msg: errMsg(e) }), 'error'),
  });

  const removeMut = useMutation({
    mutationFn: (name: string) => removeSpacePythonPackage(spaceId, name),
    onSuccess: () => { showToast?.(t('python.removed'), 'success'); void invalidate(); },
    onError: (e) => showToast?.(t('python.removeFailed', { msg: errMsg(e) }), 'error'),
  });

  const busy = addMut.isPending || removeMut.isPending;

  const submit = () => {
    const spec = input.trim();
    if (!spec || busy) return;
    addMut.mutate(spec);
  };

  if (isLoading) {
    return (
      <div className="h-full overflow-y-auto"><div className="max-w-2xl mx-auto px-6 py-8">
        <div className="text-[13px] text-slate-400">{t('common:loading')}</div>
      </div></div>
    );
  }
  if (isError || !data) {
    return (
      <div className="h-full overflow-y-auto"><div className="max-w-2xl mx-auto px-6 py-8">
        <div className="text-[13px] text-red-600">{t('python.fetchError', { msg: errMsg(error) })}</div>
      </div></div>
    );
  }

  const disabledFeature = !data.enabled;
  const preflightBad = data.enabled && !data.preflight.ok;

  return (
    <div className="h-full overflow-y-auto" data-testid="space-python-packages">
      <div className="max-w-2xl mx-auto px-6 py-8 space-y-6">
        <div>
          <h2 className="text-base font-semibold text-slate-900 mb-1">{t('python.heading')}</h2>
          <p className="text-[13px] text-slate-500 leading-relaxed">{t('python.intro')}</p>
        </div>

        {disabledFeature && (
          <div className="rounded-md border border-hairline bg-surface/40 px-4 py-3 text-[13px] text-slate-500">
            {t('python.disabled')}
          </div>
        )}

        {preflightBad && (
          <div className="rounded-md border border-amber-300 bg-amber-50/60 dark:bg-amber-900/10 px-4 py-3 text-[13px] text-amber-800 dark:text-amber-300">
            {data.preflight.reason ?? t('python.preflightBad')}
          </div>
        )}

        {/* 追加フォーム */}
        <section>
          <label className="block text-[11px] font-semibold uppercase tracking-wide text-slate-500 mb-2">
            {t('python.addLabel')}
          </label>
          <div className="flex gap-2">
            <input
              value={input}
              onChange={e => setInput(e.target.value)}
              onKeyDown={e => { if (e.key === 'Enter') submit(); }}
              disabled={!canManage || disabledFeature || busy}
              placeholder="requests==2.32.3"
              data-testid="python-add-input"
              className="h-9 flex-1 rounded-md border border-hairline px-3 text-sm focus:border-accent focus:outline-none focus:ring-2 focus:ring-accent-ring disabled:opacity-50"
            />
            <button
              type="button"
              onClick={submit}
              disabled={!canManage || disabledFeature || busy || !input.trim()}
              className="px-4 py-1.5 rounded-md text-sm font-semibold bg-accent text-white hover:bg-accent/90 transition-colors disabled:opacity-40 disabled:cursor-not-allowed"
            >
              {addMut.isPending ? t('python.installing') : t('python.add')}
            </button>
          </div>
          <p className="text-2xs text-slate-500 leading-relaxed mt-1.5">{t('python.addHint')}</p>
        </section>

        {/* 一覧 */}
        <section>
          <h3 className="text-[11px] font-semibold uppercase tracking-wide text-slate-500 mb-2">
            {t('python.installedHeading')}
          </h3>
          {data.packages.length === 0 ? (
            <p className="text-[13px] text-slate-400">{t('python.none')}</p>
          ) : (
            <div className="rounded-md border border-hairline bg-surface/40 divide-y divide-hairline overflow-hidden">
              {data.packages.map(pkg => (
                <div key={pkg.name} className="flex items-center gap-3 px-3 py-2.5">
                  <code className="min-w-0 flex-1 truncate text-[13px] text-slate-900">{pkg.spec}</code>
                  <button
                    type="button"
                    onClick={() => removeMut.mutate(pkg.name)}
                    disabled={!canManage || busy}
                    className="text-xs text-red-600 hover:text-red-700 disabled:opacity-40 disabled:cursor-not-allowed"
                  >
                    {t('python.remove')}
                  </button>
                </div>
              ))}
            </div>
          )}
        </section>

        {!canManage && (
          <p className="text-[13px] text-slate-400">{t('python.readonly')}</p>
        )}
      </div>
    </div>
  );
}
