import { useMemo, useState } from 'react';
import { useTranslation } from 'react-i18next';
import { useAuthState } from '../../App';
import { useSpaces } from '../../hooks/useSpaces';
import { useLocalTaskList } from '../../hooks/useTaskList';
import { sortSpacesForRail } from '../../lib/spaceSort';
import { countRunningTasksForSpace } from '../../lib/spaceTasks';
import { statusTone } from '../../lib/utils';
import type { Space } from '../../api';
import { SpaceFormDialog } from './SpaceFormDialog';

interface SpaceRailProps {
  selectedId?: string;
  onSelect: (id: string) => void;
}

// 可視性ラベルは private を出さない（既定値でノイズになるため）。org/public のみ
// 意味があるので表示する。
const VIS_LABEL: Partial<Record<Space['visibility'], string>> = {
  org: 'org',
  public: 'public',
};

// グループの色帯。統合スペース（個人＝作業が集まる中心）はブランド色、個別スペース
// （案件＝プロジェクトごとに分かれる）は中立色で、左端の帯で一目で区別する。
const GROUP_BAND_INTEGRATED = 'var(--brand-primary)';
const GROUP_BAND_INDIVIDUAL = '#94a3b8'; // slate-400

interface SpaceGroupDef {
  /** Stable key used for data-group (test selector); decoupled from the display label. */
  key: string;
  label: string;
  band: string;
  spaces: Space[];
}

export function SpaceRail({ selectedId, onSelect }: SpaceRailProps) {
  const { t } = useTranslation('spaces');
  const { data: spaces, isLoading, isError } = useSpaces();
  // 実行中件数の算出元。リスト API はスペースで絞らないので全件を保持しており、
  // FAST ポーリングで自動更新される。スペースごとにクライアント側で数える。
  const { data: tasks } = useLocalTaskList();
  const [showCreate, setShowCreate] = useState(false);

  const auth = useAuthState();
  const myUserId = auth.mode === 'authenticated' ? auth.user.id : null;
  // 認証無効 (no-auth 単独利用) は admin 同等に扱う（App.tsx の isAdmin と同じ規約）。
  const isAdmin = auth.mode === 'authenticated' ? auth.user.role === 'admin' : true;
  // case スペースの id 集合。個人スペースバッジの「個人バケツ」判定に使う。
  const caseSpaceIds = useMemo(
    () => new Set((spaces ?? []).filter(s => s.kind === 'case').map(s => s.id)),
    [spaces],
  );

  const sorted = useMemo(() => sortSpacesForRail(spaces ?? []), [spaces]);
  // 他ユーザー所有のスペースが一覧に混在するとき（＝admin が全ユーザーのスペースを
  // 見ている場合）だけ「自分」バッジを出す。単一ユーザーの一覧では全部自分なので
  // ノイズにしかならず、出さない（issue #003）。
  const hasOthersSpaces = useMemo(
    () => myUserId != null && sorted.some(s => s.ownerId != null && s.ownerId !== myUserId),
    [sorted, myUserId],
  );
  const groups = useMemo<SpaceGroupDef[]>(() => {
    const personal = sorted.filter(s => s.kind === 'personal');
    const cases = sorted.filter(s => s.kind !== 'personal');
    const out: SpaceGroupDef[] = [];
    if (personal.length > 0) out.push({ key: '統合スペース', label: t('rail.group.integrated'), band: GROUP_BAND_INTEGRATED, spaces: personal });
    if (cases.length > 0) out.push({ key: '個別スペース', label: t('rail.group.individual'), band: GROUP_BAND_INDIVIDUAL, spaces: cases });
    return out;
  }, [sorted, t]);

  return (
    <div className="flex h-full flex-col overflow-hidden" data-testid="space-rail">
      <div className="flex items-center justify-between border-b border-hairline px-3 py-2.5">
        <span className="text-[11px] font-bold uppercase tracking-wider text-slate-500">{t('rail.heading')}</span>
        <button
          type="button"
          data-testid="create-space-btn"
          onClick={() => setShowCreate(true)}
          className="rounded-md border border-hairline px-2 py-1 text-xs font-semibold text-slate-700 transition-colors hover:bg-surface-2"
        >
          {t('rail.new')}
        </button>
      </div>

      <div className="flex-1 overflow-y-auto px-2 py-2">
        {isLoading && <p className="px-1 py-2 text-xs text-slate-500">{t('common:loading')}</p>}
        {isError && <p className="px-1 py-2 text-xs text-red-600">{t('rail.fetchError')}</p>}

        {groups.map((g, i) => (
          <section
            key={g.key}
            data-testid="space-group"
            data-group={g.key}
            className={`border-l-2 pl-2 ${i > 0 ? 'mt-2 border-t border-hairline pt-2' : ''}`}
            style={{ borderLeftColor: g.band }}
          >
            <div className="mb-1 px-1 text-[10px] font-bold uppercase tracking-wider text-slate-400">{g.label}</div>
            {g.spaces.map(s => (
              <SpaceRow
                key={s.id}
                space={s}
                active={s.id === selectedId}
                onSelect={onSelect}
                runningCount={countRunningTasksForSpace(tasks ?? [], s, { viewerId: myUserId, isAdmin, caseSpaceIds })}
                mine={hasOthersSpaces && myUserId != null && s.ownerId === myUserId}
              />
            ))}
          </section>
        ))}

        {!isLoading && !isError && sorted.length === 0 && (
          <p className="px-1 py-2 text-xs text-slate-500">{t('rail.empty')}</p>
        )}
      </div>

      {showCreate && (
        <SpaceFormDialog
          onClose={() => setShowCreate(false)}
          onSaved={(id) => {
            setShowCreate(false);
            onSelect(id);
          }}
        />
      )}
    </div>
  );
}

function SpaceRow({
  space,
  active,
  onSelect,
  runningCount,
  mine,
}: {
  space: Space;
  active: boolean;
  onSelect: (id: string) => void;
  runningCount: number;
  /** 他ユーザーのスペースが混在する一覧で、これが閲覧者自身の所有なら true。 */
  mine?: boolean;
}) {
  const { t } = useTranslation('spaces');
  const dot = space.brandColor ?? 'var(--brand-primary)';
  const runningStyle = statusTone('running');
  return (
    <button
      type="button"
      data-testid="space-row"
      data-space-kind={space.kind}
      data-space-id={space.id}
      data-space-mine={mine ? '1' : undefined}
      onClick={() => onSelect(space.id)}
      className={`mb-0.5 flex w-full items-center gap-2 rounded-md border px-2 py-1.5 text-left transition-colors ${
        active
          ? 'border-hairline bg-[var(--brand-primary-soft)]'
          : 'border-transparent hover:bg-surface-2'
      }`}
    >
      <span
        className="h-2 w-2 shrink-0 rounded-full"
        style={{ background: dot }}
        aria-hidden
      />
      <span className="flex-1 truncate text-[12.5px] font-semibold text-slate-800">{space.title}</span>
      {mine && (
        <span
          data-testid="space-mine-badge"
          className="shrink-0 rounded-full bg-[var(--brand-primary-soft)] px-1.5 py-0.5 text-[9px] font-bold tracking-wide text-[var(--brand-primary)]"
          title={t('rail.mineTitle')}
        >
          {t('rail.mine')}
        </span>
      )}
      {VIS_LABEL[space.visibility] && (
        <span className="shrink-0 font-mono text-[9px] font-bold uppercase tracking-wide text-slate-400">
          {VIS_LABEL[space.visibility]}
        </span>
      )}
      {runningCount > 0 && (
        <span
          data-testid="space-running-count"
          className="shrink-0 inline-flex items-center gap-1 rounded-full px-1.5 py-0.5 text-[9px] font-bold tabular-nums"
          style={{ background: runningStyle.bg, color: runningStyle.fg }}
          title={t('rail.runningTitle', { count: runningCount })}
          aria-label={t('rail.runningAria', { count: runningCount })}
        >
          ● {t('rail.running', { count: runningCount })}
        </span>
      )}
    </button>
  );
}
