import { useCallback, useEffect, useRef, useState } from 'preact/hooks';
import { route } from 'preact-router';
import { BottomTabBar } from '../shared/BottomTabBar.jsx';
import { ErrorBoundary } from '../shared/ErrorBoundary.jsx';
import { S12TaskAdd } from './S12TaskAdd.jsx';
import { S13TaskDetail } from './S13TaskDetail.jsx';
import { S15GoalCreate } from './S15GoalCreate.jsx';
import './S10Grow.css';

/*
 * S-10 GROW（メインダッシュボード）
 * design_spec_v1.md §4.4 準拠
 *
 * 本ミッション（M4-C）スコープ:
 * - モックデータで全タスク状態を表示
 * - スクロール連動ヒーロー圧縮（scrollY > 60px で avatar 48→32 / 3 行→1 行）
 * - タスクチェック状態切替（ローカル state のみ / API 連携は後続ミッション）
 * - 遷移先（S-12/S-13/S-14）は未実装のため console.log + route('/') 代替なし
 *
 * Learned Patterns 適用:
 * - LP-001: スクロール圧縮 / チェック spring animation を prefers-reduced-motion で縮退
 * - LP-002: マウント時に <main> へ focus 移動
 * - LP-011: 全寸法・時間をトークン参照（spec §4.4 固定値は spec 由来として許容）
 * - LP-012: 本ファイル自体が lazy import 対象
 */

const SCROLL_COMPRESS_THRESHOLD = 60; // §4.4 固定値
const HERO_PROFILE = {
  avatar: null, // TODO: ADV 別紙でアバター画像決定
  level: 12,
  label: 'EXPLORER',
  expCurrent: 1240,
  expNext: 2000,
};

const OVERDUE_MOCK = [
  {
    id: 'od-1',
    time: '09:00',
    name: '昨日の振り返りメモ',
    meta: '未完了 · 15分',
    category: 'learn',
    categoryLabel: 'Learn',
  },
];

const TODAY_DATE_LABEL = '4月15日';

const TODAY_MOCK = [
  {
    id: 't-1',
    time: '07:30',
    name: '朝のストレッチ',
    category: 'health',
    categoryLabel: 'Health',
    status: 'done',
    meta: '達成 · 15分',
  },
  {
    id: 't-2',
    time: '10:00',
    name: 'プロジェクト提案書レビュー',
    category: 'work',
    categoryLabel: 'Work',
    status: 'active',
    meta: '進行中 · 60分',
  },
  {
    id: 't-3',
    time: '14:00',
    name: 'React の状態管理を読む',
    category: 'learn',
    categoryLabel: 'Learn',
    status: 'scheduled',
    meta: '予定 · 30分',
  },
  {
    id: 't-4',
    time: '19:00',
    name: '夕方の散歩',
    category: 'health',
    categoryLabel: 'Health',
    status: 'scheduled',
    meta: '予定 · 20分',
  },
];

const UPCOMING_MOCK = [
  {
    date: '4/16 (水)',
    tasks: [
      { id: 'u-1', time: '09:00', name: 'チームミーティング', category: 'work', categoryLabel: 'Work' },
      { id: 'u-2', time: '12:00', name: 'ランチ読書', category: 'learn', categoryLabel: 'Learn' },
    ],
  },
  {
    date: '4/17 (木)',
    tasks: [
      { id: 'u-3', time: '08:00', name: 'ジョギング', category: 'health', categoryLabel: 'Health' },
    ],
  },
];

const GOALS_MOCK = [
  { id: 'g-1', name: '毎日 30 分の読書', progress: 60 },
  { id: 'g-2', name: '週 3 回の運動習慣', progress: 40 },
];

function prefersReducedMotion() {
  if (typeof window === 'undefined' || !window.matchMedia) return false;
  return window.matchMedia('(prefers-reduced-motion: reduce)').matches;
}

/*
 * R2 a11y fix:
 * - R-002: 視覚 22×22 は §4.4 固定。ヒット領域は CSS の ::before で 44×44 確保
 * - R-003: role="checkbox" は二値 (or mixed) のため tri-state ローテと不一致。
 *   role="button" + aria-pressed に変更し、tri-state の意味は aria-label で明示
 */
function Check({ status, onToggle, tapping }) {
  const ariaLabel =
    status === 'done'
      ? '完了済み。タップすると予定に戻す'
      : status === 'active'
      ? '進行中。タップすると完了にする'
      : '予定。タップすると進行中にする';
  return (
    <button
      type="button"
      class={
        `s10-check s10-check-${status}` +
        (tapping ? ' s10-check-tap' : '')
      }
      aria-pressed={status === 'done'}
      aria-label={ariaLabel}
      onClick={onToggle}
    >
      {status === 'done' && (
        <svg
          viewBox="0 0 11 11"
          width="11"
          height="11"
          aria-hidden="true"
          focusable="false"
        >
          <path
            d="M 2 5.5 L 4.5 8 L 9 3"
            fill="none"
            stroke="currentColor"
            stroke-width="1.8"
            stroke-linecap="round"
            stroke-linejoin="round"
          />
        </svg>
      )}
    </button>
  );
}

function TodayRow({ task, onToggle, onOpen, tappingId }) {
  return (
    <li class={`s10-task s10-task-${task.status}`}>
      <span class="s10-task-time">{task.time}</span>
      <Check
        status={task.status}
        onToggle={() => onToggle(task.id)}
        tapping={tappingId === task.id}
      />
      <button
        type="button"
        class="s10-task-card"
        onClick={(e) => onOpen(task.id, e.currentTarget)}
        aria-label={`${task.name} — ${task.meta}`}
      >
        <div class="s10-task-card-body">
          <p class={`s10-task-name s10-task-name-${task.status}`}>{task.name}</p>
          <p class={`s10-task-meta s10-task-meta-${task.status}`}>
            {task.status === 'active' && (
              <span class="s10-task-meta-dash" aria-hidden="true" />
            )}
            {task.meta}
          </p>
        </div>
        <span class="s10-task-category" aria-hidden="true">
          <span class={`s10-task-dot s10-task-dot-${task.category}`} />
          <span class="s10-task-category-label">{task.categoryLabel}</span>
        </span>
      </button>
    </li>
  );
}

/*
 * R2 a11y fix R-004:
 * Overdue 行では Check コンポーネントを流用しない（実動作が「完了」ではなく
 * 「延期」のため、aria-label と action が一致しない = WCAG 4.1.2 違反）。
 * 視覚的なマーカー（装飾のみの <span>）に置き換え、唯一のインタラクションは
 * 「明日に延期」ボタン1つに統一する。
 */
function OverdueRow({ task, onDefer }) {
  return (
    <li class="s10-task s10-task-overdue">
      <span class="s10-task-time">{task.time}</span>
      <span class="s10-check s10-check-overdue" aria-hidden="true" />
      <div class="s10-task-card s10-task-card-overdue">
        <div class="s10-task-card-body">
          <p class="s10-task-name s10-task-name-scheduled">{task.name}</p>
          <p class="s10-task-meta s10-task-meta-scheduled">{task.meta}</p>
        </div>
        <button
          type="button"
          class="s10-task-defer"
          onClick={() => onDefer(task.id)}
          aria-label={`${task.name} を明日に延期する`}
        >
          明日に延期
        </button>
      </div>
    </li>
  );
}

export function S10Grow() {
  const mainRef = useRef(null);
  const tickingRef = useRef(false);
  const tapTimerRef = useRef(null);
  const mountedRef = useRef(true);
  const addTaskButtonRef = useRef(null);
  const createGoalButtonRef = useRef(null);
  const taskDetailReturnFocusRef = useRef(null);
  const [heroCompressed, setHeroCompressed] = useState(false);
  const [tasks, setTasks] = useState(TODAY_MOCK);
  const [upcomingOpen, setUpcomingOpen] = useState(false);
  const [taskAddOpen, setTaskAddOpen] = useState(false);
  const [taskDetailOpenId, setTaskDetailOpenId] = useState(null);
  const [goalCreateOpen, setGoalCreateOpen] = useState(false);
  // R2 spec-compliance fix R-003: spring アニメーション対象 task id を 400ms 保持
  const [tappingId, setTappingId] = useState(null);

  // LP-002: マウント直後に <main> へ focus 移動
  useEffect(() => {
    if (mainRef.current) {
      mainRef.current.focus({ preventScroll: true });
    }
  }, []);

  // §4.4 ヒーロー圧縮: scrollY > 60px で切替。rAF でスロットル。
  useEffect(() => {
    const handleScroll = () => {
      if (tickingRef.current) return;
      tickingRef.current = true;
      window.requestAnimationFrame(() => {
        setHeroCompressed(window.scrollY > SCROLL_COMPRESS_THRESHOLD);
        tickingRef.current = false;
      });
    };
    window.addEventListener('scroll', handleScroll, { passive: true });
    // 初期同期（リロード時に既にスクロール位置がある場合）
    handleScroll();
    return () => window.removeEventListener('scroll', handleScroll);
  }, []);

  const completedCount = tasks.filter((t) => t.status === 'done').length;

  const cycleStatus = (current) => {
    // 予定 → 進行中 → 完了 → 予定 のシンプルローテ（UI 確認用）
    if (current === 'scheduled') return 'active';
    if (current === 'active') return 'done';
    return 'scheduled';
  };

  const handleToggle = useCallback((id) => {
    setTasks((prev) =>
      prev.map((t) =>
        t.id === id
          ? {
              ...t,
              status: cycleStatus(t.status),
              meta:
                cycleStatus(t.status) === 'done'
                  ? '達成 · 15分'
                  : cycleStatus(t.status) === 'active'
                  ? '進行中 · 15分'
                  : '予定 · 15分',
            }
          : t
      )
    );
    // R2 spec-compliance R-003 fix: spring scale(0.9→1.1→1) アニメーション発火
    // LP-001 で prefers-reduced-motion 時は CSS 側で animation: none に縮退するため
    // JS 側はタイマーのみ管理。
    setTappingId(id);
    if (tapTimerRef.current) clearTimeout(tapTimerRef.current);
    tapTimerRef.current = setTimeout(() => {
      if (mountedRef.current) setTappingId(null);
    }, 400); // --duration-fast 200ms + 余裕
    // §4.4: Undo スナックバー 30s は後続ミッション（スコープ外）
  }, []);

  const handleOpenTask = useCallback((id, triggerEl) => {
    if (triggerEl) {
      taskDetailReturnFocusRef.current = triggerEl;
    }
    setTaskDetailOpenId(id);
  }, []);

  const handleTaskDetailClose = useCallback(() => {
    setTaskDetailOpenId(null);
  }, []);

  const handleTaskDetailSave = useCallback((updated) => {
    setTasks((prev) =>
      prev.map((t) =>
        t.id === updated.id
          ? {
              ...t,
              name: updated.name,
              time: updated.time,
              duration: updated.duration,
              memo: updated.memo,
            }
          : t
      )
    );
  }, []);

  const handleTaskDetailDelete = useCallback((target) => {
    if (!target) return;
    setTasks((prev) => prev.filter((t) => t.id !== target.id));
  }, []);

  const handleDeferOverdue = useCallback((id) => {
    // eslint-disable-next-line no-console
    console.log('[S10Grow] deferOverdue:', id);
  }, []);

  const handleAddTask = useCallback(() => {
    setTaskAddOpen(true);
  }, []);

  const handleTaskAddClose = useCallback(() => {
    setTaskAddOpen(false);
  }, []);

  const handleTaskCreate = useCallback((_payload) => {
    // M4-D スコープ外: API 連携は後続ミッション。ここでは S12 側の console.log のみ
  }, []);

  const handleCreateGoal = useCallback(() => {
    setGoalCreateOpen(true);
  }, []);

  const handleGoalCreateClose = useCallback(() => {
    setGoalCreateOpen(false);
  }, []);

  const handleGoalCreate = useCallback((_payload) => {
    // M4-G スコープ外: Supabase + Goals セクションへのリアルタイム追加は後続
  }, []);

  const handleOpenGoal = useCallback((id) => {
    route('/goal/' + id);
  }, []);

  const handleTabSelect = useCallback((tabId) => {
    if (tabId === 'grow') return; // 現在地
    if (tabId === 'me') {
      route('/me');
      return;
    }
    if (tabId === 'talk') {
      route('/talk');
      return;
    }
  }, []);

  return (
    <main
      ref={mainRef}
      tabIndex={-1}
      class="s10-grow"
      aria-labelledby="s10-today-label"
    >
      {/* S10-1 ヒーロー */}
      <section
        class={'s10-hero ' + (heroCompressed ? 's10-hero-compressed' : '')}
        aria-label="プロフィールサマリー"
      >
        <div class="s10-hero-avatar" aria-hidden="true">
          {/* アバター仮表示（ADV 別紙待ち） */}
        </div>
        <div class="s10-hero-body">
          <p class="s10-hero-lv-row">
            <span class="s10-hero-lv">Lv.{HERO_PROFILE.level}</span>
            <span class="s10-hero-label">{HERO_PROFILE.label}</span>
          </p>
          {!heroCompressed && (
            <>
              <div
                class="s10-hero-bar"
                role="progressbar"
                aria-valuenow={HERO_PROFILE.expCurrent}
                aria-valuemin={0}
                aria-valuemax={HERO_PROFILE.expNext}
                aria-valuetext={`${HERO_PROFILE.expCurrent} / ${HERO_PROFILE.expNext} EXP`}
                aria-label="経験値"
              >
                <span
                  class="s10-hero-bar-fill"
                  style={{
                    width: `${Math.round(
                      (HERO_PROFILE.expCurrent / HERO_PROFILE.expNext) * 100
                    )}%`,
                  }}
                />
              </div>
              <p class="s10-hero-exp" aria-hidden="true">
                {HERO_PROFILE.expCurrent.toLocaleString()} /{' '}
                {HERO_PROFILE.expNext.toLocaleString()} EXP
              </p>
            </>
          )}
        </div>
      </section>

      {/* S10-2 Overdue */}
      {OVERDUE_MOCK.length > 0 && (
        <section class="s10-section s10-overdue">
          <h2 class="s10-overdue-label">OVERDUE</h2>
          <ul class="s10-task-list">
            {OVERDUE_MOCK.map((t) => (
              <OverdueRow key={t.id} task={t} onDefer={handleDeferOverdue} />
            ))}
          </ul>
        </section>
      )}

      {/* S10-3 Today ヘッダ */}
      <section class="s10-section s10-today">
        <header class="s10-today-header">
          <h2 id="s10-today-label" class="s10-today-label">
            TODAY
          </h2>
          <span class="s10-today-date">{TODAY_DATE_LABEL}</span>
        </header>
        <p class="s10-today-counter">
          {completedCount} / {tasks.length} completed
        </p>

        {/* S10-4 Today タスク */}
        <ul class="s10-task-list">
          {tasks.map((task) => (
            <TodayRow
              key={task.id}
              task={task}
              onToggle={handleToggle}
              onOpen={handleOpenTask}
              tappingId={tappingId}
            />
          ))}
        </ul>

        {/* S10-5 + タスクを追加 */}
        <button
          ref={addTaskButtonRef}
          type="button"
          class="s10-add-task"
          onClick={handleAddTask}
          aria-haspopup="dialog"
          aria-expanded={taskAddOpen}
        >
          + タスクを追加
        </button>
      </section>

      {/* S10-6 Upcoming 折りたたみ */}
      <section class="s10-section s10-upcoming">
        <button
          type="button"
          class="s10-upcoming-header"
          aria-expanded={upcomingOpen}
          aria-controls="s10-upcoming-panel"
          onClick={() => setUpcomingOpen((v) => !v)}
        >
          <span class="s10-upcoming-label">UPCOMING</span>
          <span class="s10-upcoming-chevron" aria-hidden="true">
            {upcomingOpen ? '▲' : '▼'}
          </span>
        </button>
        {upcomingOpen && (
          <div id="s10-upcoming-panel" class="s10-upcoming-panel">
            {UPCOMING_MOCK.map((group) => (
              <div key={group.date} class="s10-upcoming-group">
                <p class="s10-upcoming-date">{group.date}</p>
                <ul class="s10-task-list">
                  {group.tasks.map((task) => (
                    <li key={task.id} class="s10-task s10-task-upcoming">
                      <span class="s10-task-time">{task.time}</span>
                      <span class="s10-check s10-check-scheduled" aria-hidden="true" />
                      <div class="s10-task-card">
                        <div class="s10-task-card-body">
                          <p class="s10-task-name s10-task-name-scheduled">
                            {task.name}
                          </p>
                        </div>
                        <span class="s10-task-category" aria-hidden="true">
                          <span class={`s10-task-dot s10-task-dot-${task.category}`} />
                          <span class="s10-task-category-label">
                            {task.categoryLabel}
                          </span>
                        </span>
                      </div>
                    </li>
                  ))}
                </ul>
              </div>
            ))}
          </div>
        )}
      </section>

      {/* S10-7 Goals ヘッダ + S10-8 Goals 行 */}
      <section class="s10-section s10-goals">
        <h2 class="s10-goals-label">GOALS</h2>
        <ul class="s10-goals-list">
          {GOALS_MOCK.map((g) => (
            <li key={g.id}>
              <button
                type="button"
                class="s10-goal"
                onClick={() => handleOpenGoal(g.id)}
              >
                <div class="s10-goal-top">
                  <span class="s10-goal-name">{g.name}</span>
                  <span class="s10-goal-pct">{g.progress}%</span>
                </div>
                <div
                  class="s10-goal-bar"
                  role="progressbar"
                  aria-valuenow={g.progress}
                  aria-valuemin={0}
                  aria-valuemax={100}
                  aria-label={`${g.name} の進捗`}
                >
                  <span
                    class="s10-goal-bar-fill"
                    style={{ width: `${g.progress}%` }}
                  />
                </div>
              </button>
            </li>
          ))}
        </ul>

        {/* S10-9 + ゴールを作成 */}
        <button
          ref={createGoalButtonRef}
          type="button"
          class="s10-add-goal"
          onClick={handleCreateGoal}
          aria-haspopup="dialog"
          aria-expanded={goalCreateOpen}
        >
          + ゴールを作成
        </button>
      </section>

      {/* S10-10 BottomTabBar */}
      <BottomTabBar active="grow" onSelect={handleTabSelect} />

      {/* S-12 Task Add ハーフモーダル（M4-D） */}
      {/* PATCH-PB4-ERROR-BOUNDARY: モーダル失敗が S-10 全体を巻き込まないよう個別ラップ */}
      <ErrorBoundary label="タスク追加モーダルでエラーが発生しました">
        <S12TaskAdd
          open={taskAddOpen}
          onClose={handleTaskAddClose}
          onCreate={handleTaskCreate}
          returnFocusRef={addTaskButtonRef}
        />
      </ErrorBoundary>

      {/* S-13 Task Detail ハーフモーダル（M4-E） */}
      <ErrorBoundary label="タスク詳細モーダルでエラーが発生しました">
        <S13TaskDetail
          open={taskDetailOpenId !== null}
          task={tasks.find((t) => t.id === taskDetailOpenId) || null}
          onClose={handleTaskDetailClose}
          onSave={handleTaskDetailSave}
          onDelete={handleTaskDetailDelete}
          returnFocusRef={taskDetailReturnFocusRef}
        />
      </ErrorBoundary>

      {/* S-15 Goal Create ハーフモーダル（M4-G） */}
      <ErrorBoundary label="ゴール作成モーダルでエラーが発生しました">
        <S15GoalCreate
          open={goalCreateOpen}
          onClose={handleGoalCreateClose}
          onCreate={handleGoalCreate}
          returnFocusRef={createGoalButtonRef}
        />
      </ErrorBoundary>
    </main>
  );
}

export default S10Grow;
