/**
 * SpaceToolSettings.tsx — ワークスペースごとのツールポリシー設定 UI
 *
 * - 安全カテゴリ（sensitive=false）: デフォルト ON のトグル群
 * - センシティブカテゴリ（sensitive=true）+ Bash: デフォルト OFF のトグル群。
 *   各項目に 1 行のリスク説明を表示。
 * - カテゴリ一覧は API から動的取得（ハードコードなし）。
 * - オーナーのみ編集可（canManage 判定は SpaceMembersPanel と同じシグナル）。
 * - 保存は PUT /api/local/spaces/:id/tool-policy（react-query mutation）。
 */

import { useState } from 'react';
import { Trans, useTranslation } from 'react-i18next';
import { useQuery, useMutation, useQueryClient } from '@tanstack/react-query';
import {
  fetchSpaceToolPolicy,
  fetchSpaceMembers,
  updateSpaceToolPolicy,
  type ToolCategory,
} from '../../api';
import { useAuthState } from '../../App';
import { splitCategories, buildPolicyPatch, countEnabledCategories } from '../../lib/toolPolicy';

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

/** センシティブカテゴリ・ツールに表示する 1 行のリスク説明の翻訳キー。 */
const SENSITIVE_NOTE_KEYS: Record<string, string> = {
  ssh: 'tools.sensitiveNote.ssh',
  browser: 'tools.sensitiveNote.browser',
  Bash: 'tools.sensitiveNote.Bash',
  SpawnSubTask: 'tools.sensitiveNote.SpawnSubTask',
};

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

interface ToggleRowProps {
  name: string;
  enabled: boolean;
  note?: string;
  disabled: boolean;
  disabledReason?: string;
  onChange: (enabled: boolean) => void;
}

function ToggleRow({ name, enabled, note, disabled, disabledReason, onChange }: ToggleRowProps) {
  return (
    <div className="flex items-start gap-3 py-2.5 border-b border-hairline last:border-b-0">
      <div className="min-w-0 flex-1">
        <div className="flex items-center gap-2">
          <span className="text-[13px] font-medium text-slate-900">{name}</span>
          {disabled && disabledReason && (
            <span className="text-2xs text-slate-400">({disabledReason})</span>
          )}
        </div>
        {note && (
          <p className="text-2xs text-slate-500 leading-relaxed mt-0.5">{note}</p>
        )}
      </div>
      <button
        type="button"
        role="switch"
        aria-checked={enabled}
        disabled={disabled}
        onClick={() => onChange(!enabled)}
        className={`relative inline-flex h-5 w-9 shrink-0 items-center rounded-full transition-colors focus:outline-none focus:ring-2 focus:ring-accent-ring focus:ring-offset-1 disabled:opacity-40 disabled:cursor-not-allowed ${
          enabled ? 'bg-accent' : 'bg-slate-300 dark:bg-slate-600'
        }`}
      >
        <span
          className={`inline-block h-3.5 w-3.5 rounded-full bg-white shadow-sm transition-transform ${
            enabled ? 'translate-x-[18px]' : 'translate-x-[3px]'
          }`}
        />
      </button>
    </div>
  );
}

export function SpaceToolSettings({ spaceId, showToast }: { spaceId: string; showToast?: ShowToast }) {
  const { t } = useTranslation('spaces');
  const auth = useAuthState();
  const qc = useQueryClient();

  const noteFor = (name: string): string | undefined => {
    const key = SENSITIVE_NOTE_KEYS[name];
    return key ? t(key) : undefined;
  };

  // メンバー一覧から canManage を判定（SpaceMembersPanel と同じロジック）
  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-tool-policy', spaceId],
    queryFn: () => fetchSpaceToolPolicy(spaceId),
    staleTime: 30_000,
  });

  // UI ローカルのトグル状態（未保存の変更を保持）
  const [toggledSafe, setToggledSafe] = useState<Record<string, boolean>>({});
  const [toggledSens, setToggledSens] = useState<Record<string, boolean>>({});
  const [savedState, setSavedState] = useState<'idle' | 'saved' | 'error'>('idle');

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

  const saveMut = useMutation({
    mutationFn: (patch: { disabledSafe: string[]; enabledSensitive: string[] }) =>
      updateSpaceToolPolicy(spaceId, patch),
    onSuccess: () => {
      setSavedState('saved');
      setToggledSafe({});
      setToggledSens({});
      invalidate();
      setTimeout(() => setSavedState('idle'), 2000);
    },
    onError: (e) => {
      setSavedState('error');
      showToast?.(t('tools.toast.saveFailed', { msg: errMsg(e) }), 'error');
      setTimeout(() => setSavedState('idle'), 3000);
    },
  });

  const handleSave = () => {
    if (!data) return;
    const patch = buildPolicyPatch(data.categories, toggledSafe, toggledSens, data.sensitiveTools ?? []);
    saveMut.mutate(patch);
  };

  const hasPendingChanges = Object.keys(toggledSafe).length > 0 || Object.keys(toggledSens).length > 0;

  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('tools.fetchError', { msg: errMsg(error) })}
          </div>
        </div>
      </div>
    );
  }

  const { safe, sensitive } = splitCategories(data.categories);
  const enabledCount = countEnabledCategories(data.categories, toggledSafe, toggledSens);
  const readonlyReason = t('tools.readonlyReason');

  // センシティブグループ: カテゴリ + Bash（sensitiveTools から取得）
  // sensitiveTools は Bash など個別ツールで sensitive=true なもの
  const sensitiveBash = data.sensitiveTools ?? [];

  const resolveEnabled = (cat: ToolCategory, map: Record<string, boolean>) => {
    return Object.prototype.hasOwnProperty.call(map, cat.name) ? map[cat.name] : cat.enabled;
  };

  const resolveSensToolEnabled = (toolName: string, apiEnabled: boolean) => {
    return Object.prototype.hasOwnProperty.call(toggledSens, toolName)
      ? toggledSens[toolName]
      : apiEnabled;
  };

  return (
    <div className="h-full overflow-y-auto" data-testid="space-tool-settings">
      <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('tools.heading')}</h2>
          <p className="text-[13px] text-slate-500 leading-relaxed">
            {t('tools.intro')}
          </p>
          <p className="text-[13px] text-slate-500 mt-1">
            <Trans
              t={t}
              i18nKey="tools.enabledCount"
              values={{ count: enabledCount }}
              components={{ strong: <span className="font-semibold text-slate-700" /> }}
            />
          </p>
        </div>

        {/* 安全カテゴリ（デフォルト ON） */}
        <section>
          <h3 className="text-[11px] font-semibold uppercase tracking-wide text-slate-500 mb-2">
            {t('tools.standardCategories')}
          </h3>
          {safe.length === 0 ? (
            <p className="text-[13px] text-slate-400">{t('tools.noStandardCategories')}</p>
          ) : (
            <div className="rounded-md border border-hairline bg-surface/40 divide-y divide-hairline overflow-hidden px-3">
              {safe.map(cat => (
                <ToggleRow
                  key={cat.name}
                  name={cat.name}
                  enabled={resolveEnabled(cat, toggledSafe)}
                  disabled={!canManage || saveMut.isPending}
                  disabledReason={!canManage ? readonlyReason : undefined}
                  onChange={v => setToggledSafe(prev => ({ ...prev, [cat.name]: v }))}
                />
              ))}
            </div>
          )}
        </section>

        {/* センシティブカテゴリ（デフォルト OFF） */}
        <section>
          <h3 className="text-[11px] font-semibold uppercase tracking-wide text-slate-500 mb-1">
            {t('tools.sensitiveTools')}
          </h3>
          <p className="text-2xs text-slate-500 leading-relaxed mb-2">
            {t('tools.sensitiveWarning')}
          </p>
          {sensitive.length === 0 && sensitiveBash.length === 0 ? (
            <p className="text-[13px] text-slate-400">{t('tools.noSensitiveCategories')}</p>
          ) : (
            <div className="rounded-md border border-hairline bg-amber-50/40 dark:bg-amber-900/10 divide-y divide-hairline overflow-hidden px-3">
              {/* センシティブカテゴリ（ssh / browser 等） */}
              {sensitive.map(cat => (
                <ToggleRow
                  key={cat.name}
                  name={cat.name}
                  enabled={resolveEnabled(cat, toggledSens)}
                  note={noteFor(cat.name)}
                  disabled={!canManage || saveMut.isPending}
                  disabledReason={!canManage ? readonlyReason : undefined}
                  onChange={v => setToggledSens(prev => ({ ...prev, [cat.name]: v }))}
                />
              ))}
              {/* 個別センシティブツール（Bash 等） */}
              {sensitiveBash.map(tool => (
                <ToggleRow
                  key={tool.name}
                  name={tool.name}
                  enabled={resolveSensToolEnabled(tool.name, tool.enabled)}
                  note={noteFor(tool.name)}
                  disabled={!canManage || saveMut.isPending}
                  disabledReason={!canManage ? readonlyReason : undefined}
                  onChange={v => setToggledSens(prev => ({ ...prev, [tool.name]: v }))}
                />
              ))}
            </div>
          )}
        </section>

        {/* 保存ボタン */}
        <div className="flex items-center gap-3">
          <button
            type="button"
            onClick={handleSave}
            disabled={!canManage || saveMut.isPending || !hasPendingChanges}
            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"
          >
            {saveMut.isPending ? t('tools.saving') : t('common:save')}
          </button>
          {savedState === 'saved' && (
            <span className="text-[13px] text-green-600">{t('tools.saved')}</span>
          )}
          {savedState === 'error' && (
            <span className="text-[13px] text-red-600">{t('tools.saveFailedInline')}</span>
          )}
          {!canManage && (
            <span className="text-[13px] text-slate-400">{readonlyReason}</span>
          )}
        </div>
      </div>
    </div>
  );
}
