import { useState, useEffect } from 'react';
import { useTranslation } from 'react-i18next';
import * as Dialog from '@radix-ui/react-dialog';
import { useQuery } from '@tanstack/react-query';
import { CreateLocalTaskInput, fetchMyOrgs, Visibility, listBrowserSessionProfiles, fetchLlmWorkers } from '../../api';
import { CreateTaskDialogAdvancedSection } from './CreateTaskDialogAdvancedSection';
import { CreateTaskDialogCoreSection } from './CreateTaskDialogCoreSection';
import { usePieceList } from '../../hooks/usePieces';
import { useSpaces } from '../../hooks/useSpaces';
import { sortSpacesForRail } from '../../lib/spaceSort';
import { resolvePieceOptions } from '../../lib/splitPieces';
import { useAuthState } from '../../App';
import { useDraft } from '../../hooks/useDraft';
import { toBase64, uniqueAttachmentName } from '../../lib/fileAttachments';

interface CreateTaskDialogProps {
  onClose: () => void;
  onSubmit: (input: CreateLocalTaskInput, attachments: Array<{ name: string; contentBase64: string }>) => Promise<void>;
  /**
   * Optional preselected piece. When set, the piece is locked (not overridden
   * by the auto-classifier) and a placeholder hint explains the assistant.
   * Used by the Help Center "AI に聞く" button to land users in the help piece.
   */
  initialPiece?: string;
  initialBody?: string;
  placeholder?: string;
  /**
   * Spaces foundation: スペース詳細から開いた場合に紐付けるスペース。
   * 指定時はそのスペースに固定（ピッカー非表示・名称のみ表示）。
   * 未指定（グローバルのタスク一覧から開いた）時は個人スペースが既定。
   */
  initialSpaceId?: string;
  /** Optional in-page portal target. When set, the form is non-modal. */
  inlineContainer?: HTMLElement | null;
}
export function CreateTaskDialog({ onClose, onSubmit, initialPiece, initialBody, placeholder, initialSpaceId, inlineContainer }: CreateTaskDialogProps) {
  const { t } = useTranslation('create');
  const { data: pieces } = usePieceList();
  const { data: spacesData } = useSpaces();
  const { data: orgs = [] } = useQuery({ queryKey: ['my-orgs'], queryFn: fetchMyOrgs, staleTime: 5 * 60 * 1000 });
  const { data: sessionProfiles = [] } = useQuery({
    queryKey: ['browser-session-profiles'],
    // ラップ必須: react-query は queryFn に QueryFunctionContext を渡すため、直接渡すと
    // spaceId 引数にオブジェクトが入り ?spaceId=[object Object] になる(WS2 回帰)。
    queryFn: () => listBrowserSessionProfiles(),
    staleTime: 60 * 1000,
  });
  const activeSessionProfiles = sessionProfiles.filter(p => p.status === 'active');
  const { data: llmWorkers = [] } = useQuery({ queryKey: ['llm-workers'], queryFn: fetchLlmWorkers });
  const enabledLlmWorkers = llmWorkers.filter(w => w.enabled !== false);
  interface ConnectionRow { serverId: string; serverName: string; connected: boolean }
  const { data: connections } = useQuery({
    queryKey: ['mcp-connections'],
    queryFn: async (): Promise<ConnectionRow[]> => {
      const res = await fetch('/api/mcp/connections', { credentials: 'include' });
      if (!res.ok) return [];
      const data = await res.json();
      return (data.connections ?? []) as ConnectionRow[];
    },
    staleTime: 30_000,
  });
  const authState = useAuthState();
  const defaultVis = (authState.mode === 'authenticated' ? authState.user?.defaultVisibility : undefined) ?? 'private';
  const savedOrgId = (authState.mode === 'authenticated' ? authState.user?.defaultVisibilityOrgId : undefined) ?? null;
  const [visibility, setVisibility] = useState<Visibility>(defaultVis);
  const [visibilityScopeOrgId, setVisibilityScopeOrgId] = useState<string | null>(savedOrgId);

  // Backfill the scope when orgs finish loading: useQuery starts with orgs=[]
  // so without this the initial render freezes scopeId=null for users without
  // a saved default, and picking 'Organization' would submit an unscoped task.
  useEffect(() => {
    if (visibilityScopeOrgId !== null) return;
    if (orgs.length === 0) return;
    setVisibilityScopeOrgId(orgs[0].orgId);
  }, [orgs, visibilityScopeOrgId]);
  // 下書き保存: ヘルプ/継続フロー等で initialBody が来たときは明示指定を優先し、
  // 下書きの復元も上書きもしない（key=null で opt-out）。
  const draftKey = initialBody
    ? null
    : `create-task:${initialPiece ?? 'default'}:${initialSpaceId ?? 'global'}`;
  const { draft, saveDraft, clearDraft } = useDraft(draftKey);
  const [form, setForm] = useState<CreateLocalTaskInput>({
    body: initialBody ?? draft ?? '',
    piece: initialPiece ?? 'auto',
    profile: 'auto',
    outputFormat: 'markdown',
    askPolicy: 'low',
    priority: 'medium',
    workspaceMode: 'persistent',
    llmWorkerId: null,
    llmEffort: null,
  });
  // スペース起点で開いた場合は固定。それ以外はユーザーが任意で選択（既定=個人）。
  const [selectedSpaceId, setSelectedSpaceId] = useState<string | undefined>(initialSpaceId);
  const sortedSpaces = sortSpacesForRail(spacesData ?? []).filter(s => s.status === 'open');
  const fixedSpace = initialSpaceId ? sortedSpaces.find(s => s.id === initialSpaceId) : undefined;
  const [attachments, setAttachments] = useState<Array<{ name: string; contentBase64: string }>>([]);
  const [browserSessionProfileId, setBrowserSessionProfileId] = useState<number | null>(null);
  const [error, setError] = useState('');
  const [submitting, setSubmitting] = useState(false);
  const [showAdvanced, setShowAdvanced] = useState(false);
  const [isScheduled, setIsScheduled] = useState(false);
  const [schedule, setSchedule] = useState({
    scheduleType: 'daily',
    hour: 9,
    minute: 0,
    dayOfWeek: 1,
    dayOfMonth: 1,
    cronExpression: '',
    scheduledAt: '',
  });

  const resolvedPieces = resolvePieceOptions(pieces ?? []);
  const selectedPiece = resolvedPieces.find(p => p.name === form.piece);
  const missingMcp = selectedPiece?.requiredMcp
    ? selectedPiece.requiredMcp.filter(
        (id) => !(connections ?? []).find((c) => c.serverId === id && c.connected),
      )
    : [];

  // ダイアログ全体でファイル貼り付けを受ける（textarea 外でも効く）。
  // テキストだけの貼り付けには一切介入しない。
  const handlePaste = async (e: React.ClipboardEvent) => {
    const files = Array.from(e.clipboardData?.files ?? []);
    if (files.length === 0) return;
    e.preventDefault();
    const taken = new Set(attachments.map(a => a.name));
    const converted: Array<{ name: string; contentBase64: string }> = [];
    let failed = 0;
    for (const f of files) {
      const name = uniqueAttachmentName(f.name, taken);
      taken.add(name);
      try {
        converted.push({ name, contentBase64: await toBase64(f) });
      } catch {
        failed += 1;
      }
    }
    if (converted.length > 0) {
      setAttachments(prev => [...prev, ...converted]);
    }
    if (failed > 0) {
      setError(t('errors.pasteAttachFailed'));
    }
  };

  const handleSubmit = async () => {
    if (!form.body.trim()) {
      setError(t('errors.bodyRequired'));
      return;
    }
    try {
      setSubmitting(true);
      setError('');
      if (isScheduled) {
        const res = await fetch('/api/scheduled-tasks', {
          method: 'POST',
          headers: { 'Content-Type': 'application/json' },
          body: JSON.stringify({
            title: form.body.trim().slice(0, 40),
            body: form.body.trim(),
            piece: form.piece,
            visibility,
            visibilityScopeOrgId: visibility === 'org' ? visibilityScopeOrgId : null,
            browserSessionProfileId: browserSessionProfileId ?? undefined,
            ...schedule,
          }),
        });
        if (!res.ok) throw new Error(t('errors.scheduleFailed'));
        clearDraft();
        onClose();
        return;
      }
      const submitForm = {
        ...form,
        // initialPiece が指定されているヘルプアシスタント等は piece を固定。
        // それ以外は form.piece (詳細設定で選択した値、無指定なら 'auto') を尊重する。
        piece: initialPiece ?? form.piece,
        title: undefined,
        body: form.body.trim(),
        visibility,
        visibilityScopeOrgId: visibility === 'org' ? visibilityScopeOrgId : null,
        browserSessionProfileId: browserSessionProfileId ?? undefined,
        // 固定スペースを最優先、無ければ選択値。未指定なら個人スペースに解決される。
        spaceId: initialSpaceId ?? selectedSpaceId ?? undefined,
      };
      await onSubmit(submitForm, attachments);
      clearDraft();
    } catch (e) {
      setError(e instanceof Error ? e.message : String(e));
    } finally {
      setSubmitting(false);
    }
  };

  // 入力があるときだけ外側クリックのクローズを止める（Esc/×/キャンセルは常に有効）
  const dirty = form.body.trim().length > 0 || attachments.length > 0;

  return (
    <Dialog.Root open modal={!inlineContainer} onOpenChange={(open) => { if (!open) onClose(); }}>
      <Dialog.Portal container={inlineContainer ?? undefined}>
        {!inlineContainer && <Dialog.Overlay className="fixed inset-0 bg-slate-900/50 z-30" />}
        <Dialog.Content
          className={inlineContainer
            ? 'h-full w-full overflow-auto bg-surface focus:outline-none'
            : 'fixed top-1/2 left-1/2 -translate-x-1/2 -translate-y-1/2 bg-surface rounded-2xl shadow-2xl w-full overflow-auto z-40 focus:outline-none'}
          style={inlineContainer ? undefined : { maxWidth: 'min(860px, 92vw)', maxHeight: '88dvh' }}
          onOpenAutoFocus={e => {
            e.preventDefault();
          }}
          onPointerDownOutside={e => { if (dirty) e.preventDefault(); }}
          onInteractOutside={e => { if (dirty) e.preventDefault(); }}
          onPaste={e => void handlePaste(e)}
        >
        <div className="p-5">
          <div className="flex items-start justify-between gap-3 mb-5">
            <div>
              <Dialog.Title className="text-xl font-extrabold text-slate-900 m-0">
                {initialPiece === 'help' ? t('title.help') : t('title.new')}
              </Dialog.Title>
              <Dialog.Description className="mt-1 text-[13px] text-slate-500">
                {initialPiece === 'help' ? t('subtitle.help') : t('subtitle.new')}
              </Dialog.Description>
            </div>
            <Dialog.Close asChild>
              <button
                aria-label={t('close')}
                className="p-1.5 rounded-lg text-slate-400 hover:text-slate-600 hover:bg-slate-100 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-ring"
              >
                <svg className="w-4 h-4" viewBox="0 0 16 16" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round">
                  <path d="M4 4l8 8M12 4l-8 8"/>
                </svg>
              </button>
            </Dialog.Close>
          </div>

          <CreateTaskDialogCoreSection
            initialPiece={initialPiece}
            placeholder={placeholder}
            initialSpaceId={initialSpaceId}
            fixedSpace={fixedSpace}
            selectedSpaceId={selectedSpaceId}
            setSelectedSpaceId={setSelectedSpaceId}
            form={form}
            setForm={setForm}
            attachments={attachments}
            setAttachments={setAttachments}
            resolvedPieces={resolvedPieces}
            missingMcp={missingMcp}
            onSubmit={handleSubmit}
            saveDraft={saveDraft}
            sortedSpaces={sortedSpaces}
            orgs={orgs}
            visibility={visibility}
          />
          <CreateTaskDialogAdvancedSection
            form={form}
            setForm={setForm}
            resolvedPieces={resolvedPieces}
            activeSessionProfiles={activeSessionProfiles}
            enabledLlmWorkers={enabledLlmWorkers}
            isScheduled={isScheduled}
            setIsScheduled={setIsScheduled}
            schedule={schedule}
            setSchedule={setSchedule}
            browserSessionProfileId={browserSessionProfileId}
            setBrowserSessionProfileId={setBrowserSessionProfileId}
            visibility={visibility}
            setVisibility={setVisibility}
            visibilityScopeOrgId={visibilityScopeOrgId}
            setVisibilityScopeOrgId={setVisibilityScopeOrgId}
            orgs={orgs}
            showAdvanced={showAdvanced}
            setShowAdvanced={setShowAdvanced}
          />
          {error && <div className="mt-4 text-[13px] text-red-600">{error}</div>}
          <div className="mt-4 flex justify-end items-center gap-2 pt-1">
            <Dialog.Close asChild>
              <button className="px-4 py-2 border border-slate-200 rounded-xl text-[13px] text-slate-600 hover:bg-slate-50 focus-visible:outline-none focus-visible:ring-2 focus-visible:ring-accent-ring">
                {t('cancel')}
              </button>
            </Dialog.Close>
            <button
              disabled={submitting}
              data-testid="create-task-submit"
              onClick={() => void handleSubmit()}
              className="px-4 py-2 bg-accent text-accent-fg rounded-xl text-[13px] font-bold disabled:opacity-50 hover:bg-accent-deep"
            >
              {submitting ? t('submitting') : isScheduled ? t('submitSchedule') : t('submit')}
            </button>
          </div>
        </div>
        </Dialog.Content>
      </Dialog.Portal>
    </Dialog.Root>
  );
}
