// SchedulesPage — mirrors the Tasks 3-pane shell: list | detail | history
// Data model derives from ui/src/pages/SchedulesPage.tsx.

const DAYS = ['日', '月', '火', '水', '木', '金', '土'];

function parseCronToDisplay(cron) {
  if (cron === 'once') return '一回のみ';
  const parts = (cron || '').split(' ');
  if (parts.length !== 5) return cron;
  const [min, hour, dom, , dow] = parts;
  const hhmm = `${hour}:${String(min).padStart(2, '0')}`;
  if (dom !== '*' && dow === '*') return `毎月${dom}日 ${hhmm}`;
  if (dow !== '*' && dom === '*') return `毎週${DAYS[Number(dow)] ?? dow}曜 ${hhmm}`;
  if (dom === '*' && dow === '*') return `毎日 ${hhmm}`;
  return cron;
}

function formatDateShort(iso) {
  if (!iso) return '—';
  const d = new Date(iso);
  return d.toLocaleString('ja-JP', { month: '2-digit', day: '2-digit', hour: '2-digit', minute: '2-digit' });
}

function relativeFromNow(iso) {
  if (!iso) return '—';
  const diff = new Date(iso).getTime() - Date.now();
  const abs = Math.abs(diff);
  const mins = Math.round(abs / 60000);
  const hrs = Math.round(mins / 60);
  const days = Math.round(hrs / 24);
  const unit = mins < 60 ? `${mins}分` : hrs < 24 ? `${hrs}時間` : `${days}日`;
  return diff >= 0 ? `${unit}後` : `${unit}前`;
}

// ── Left: list of schedules ──────────────────────────────────────────────
function ScheduleListItem({ sch, active, onClick }) {
  return (
    <button onClick={onClick} style={{
      width: '100%', textAlign: 'left', padding: '10px 12px', borderRadius: 12,
      border: '1px solid ' + (active ? '#3b82f6' : '#e2e8f0'),
      background: active ? '#eff6ff' : '#fff',
      cursor: 'pointer', transition: 'background .15s', fontFamily: 'inherit',
    }}>
      <div style={{ display: 'flex', alignItems: 'center', gap: 8, minWidth: 0 }}>
        <span style={{
          width: 8, height: 8, borderRadius: 9999, flexShrink: 0,
          background: sch.isActive ? '#22c55e' : '#cbd5e1',
        }} />
        <div style={{
          flex: 1, minWidth: 0,
          fontSize: 13, fontWeight: 700, color: sch.isActive ? '#0f172a' : '#64748b',
          overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap',
        }}>{sch.title || 'タイトルなし'}</div>
        {sch.triggerKind === 'event' && (
          <span style={{
            fontSize: 10, fontWeight: 700, color: '#5b21b6', background: '#ede9fe',
            padding: '2px 6px', borderRadius: 4, flexShrink: 0,
          }}>event</span>
        )}
      </div>
      <div style={{ marginTop: 4, fontSize: 11, color: '#64748b', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
        {sch.triggerKind === 'event' ? sch.eventSource : parseCronToDisplay(sch.cronExpression)}
      </div>
      <div style={{ marginTop: 2, fontSize: 10, color: '#94a3b8' }}>
        {sch.isActive
          ? (sch.nextRunAt ? `次回 ${formatDateShort(sch.nextRunAt)} (${relativeFromNow(sch.nextRunAt)})` : '次回未定')
          : '停止中'}
      </div>
    </button>
  );
}

function ScheduleListPane({ items, activeId, onSelect, filter, setFilter, search, setSearch, onOpenCreate }) {
  const filtered = items.filter(s => {
    if (filter === 'active' && !s.isActive) return false;
    if (filter === 'paused' && s.isActive) return false;
    if (filter === 'event' && s.triggerKind !== 'event') return false;
    if (search && !(s.title + s.body).toLowerCase().includes(search.toLowerCase())) return false;
    return true;
  });
  const counts = {
    all: items.length,
    active: items.filter(s => s.isActive).length,
    paused: items.filter(s => !s.isActive).length,
    event: items.filter(s => s.triggerKind === 'event').length,
  };
  const chipStyle = (on) => ({
    flexShrink: 0, padding: '6px 10px', borderRadius: 9999,
    fontSize: 11, fontWeight: 700, whiteSpace: 'nowrap', cursor: 'pointer',
    border: '1px solid ' + (on ? '#2563eb' : '#e2e8f0'),
    background: on ? '#eff6ff' : '#fff',
    color: on ? '#1d4ed8' : '#64748b', fontFamily: 'inherit',
  });
  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
      <button onClick={onOpenCreate} style={{
        width: '100%', padding: '10px 14px', marginBottom: 10, background: '#2563eb',
        color: '#fff', borderRadius: 12, fontSize: 13, fontWeight: 700, border: 'none',
        cursor: 'pointer', fontFamily: 'inherit', display: 'inline-flex', alignItems: 'center',
        justifyContent: 'center', gap: 6, boxShadow: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
      }}>
        <svg width="14" height="14" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2.5" strokeLinecap="round"><path d="M12 5v14M5 12h14"/></svg>
        新しいスケジュール
      </button>
      <div style={{
        display: 'flex', alignItems: 'center', gap: 10, fontSize: 11,
        color: '#64748b', padding: '0 2px 10px',
      }}>
        <span><b style={{ color: '#334155', fontWeight: 700 }}>{counts.all}</b> 件</span>
        <span style={{ color: '#cbd5e1' }}>·</span>
        <span><b style={{ color: '#16a34a', fontWeight: 700 }}>{counts.active}</b> 有効</span>
        {counts.paused > 0 && <span><b style={{ color: '#64748b', fontWeight: 700 }}>{counts.paused}</b> 停止</span>}
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 8, paddingBottom: 12, borderBottom: '1px solid #e2e8f0' }}>
        <div style={{
          display: 'flex', alignItems: 'center', gap: 8, background: '#fff', border: '1px solid #e2e8f0',
          borderRadius: 12, padding: '6px 12px', boxShadow: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
        }}>
          <IconSearch width={14} height={14} style={{ color: '#94a3b8', flexShrink: 0 }} />
          <input value={search} onChange={(e) => setSearch(e.target.value)} placeholder="検索..."
            style={{ flex: 1, border: 'none', outline: 'none', background: 'transparent', fontSize: 13, fontFamily: 'inherit', color: '#0f172a', minWidth: 0 }} />
        </div>
        <div style={{ display: 'flex', gap: 6, overflowX: 'auto', paddingBottom: 4 }}>
          <button style={chipStyle(filter === 'all')} onClick={() => setFilter('all')}>All <span style={{ color: '#94a3b8', marginLeft: 2 }}>{counts.all}</span></button>
          <button style={chipStyle(filter === 'active')} onClick={() => setFilter('active')}>有効 <span style={{ color: '#94a3b8', marginLeft: 2 }}>{counts.active}</span></button>
          <button style={chipStyle(filter === 'paused')} onClick={() => setFilter('paused')}>停止 <span style={{ color: '#94a3b8', marginLeft: 2 }}>{counts.paused}</span></button>
          <button style={chipStyle(filter === 'event')} onClick={() => setFilter('event')}>Event <span style={{ color: '#94a3b8', marginLeft: 2 }}>{counts.event}</span></button>
        </div>
      </div>
      <div style={{ display: 'flex', flexDirection: 'column', gap: 6, marginTop: 8, overflowY: 'auto', flex: 1, minHeight: 0 }}>
        {filtered.map(s => <ScheduleListItem key={s.id} sch={s} active={activeId === s.id} onClick={() => onSelect(s.id)} />)}
        {filtered.length === 0 && (
          (search || filter !== 'all') ? (
            <EmptyState
              compact
              icon={<IconSearch width={18} height={18} />}
              title="該当するスケジュールはありません"
              hint="検索やフィルタを変えてみてください。"
              action={
                <button onClick={() => { setSearch(''); setFilter('all'); }} style={{
                  padding: '6px 12px', borderRadius: 8, fontSize: 12, fontWeight: 700,
                  background: '#fff', border: '1px solid #e2e8f0', color: '#334155',
                  cursor: 'pointer', fontFamily: 'inherit',
                }}>フィルタをクリア</button>
              }
            />
          ) : (
            <EmptyState
              compact
              icon={<svg width="18" height="18" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>}
              title="スケジュールがありません"
              hint="定期実行やイベントトリガーを登録するとここに表示されます。"
            />
          )
        )}
      </div>
    </div>
  );
}

// ── Center: schedule detail editor ───────────────────────────────────────
function FormRow({ label, help, children }) {
  return (
    <label style={{ display: 'block', marginBottom: 14 }}>
      <div style={{ fontSize: 11, fontWeight: 600, color: '#475569', marginBottom: 4 }}>{label}</div>
      {children}
      {help && <div style={{ fontSize: 10, color: '#94a3b8', marginTop: 4 }}>{help}</div>}
    </label>
  );
}

function TextInput(props) {
  return <input {...props} style={{
    width: '100%', padding: '8px 12px', fontSize: 13, fontFamily: 'inherit',
    background: '#fff', border: '1px solid #e2e8f0', borderRadius: 10,
    outline: 'none', color: '#0f172a',
    ...(props.style || {}),
  }} />;
}

function SelectInput({ children, ...props }) {
  return <select {...props} style={{
    width: '100%', padding: '8px 12px', fontSize: 13, fontFamily: 'inherit',
    background: '#fff', border: '1px solid #e2e8f0', borderRadius: 10,
    outline: 'none', color: '#0f172a',
  }}>{children}</select>;
}

function ScheduleDetail({ sch, onPatch, onTrigger, onDelete }) {
  if (!sch) {
    return (
      <div style={{ padding: 40, display: 'flex', alignItems: 'center', justifyContent: 'center', height: '100%' }}>
        <EmptyState
          icon={<svg width="22" height="22" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>}
          title="スケジュールを選択してください"
          hint="左のリストから編集したいスケジュールを開きます。"
        />
      </div>
    );
  }

  const isEvent = sch.triggerKind === 'event';

  return (
    <div style={{ display: 'flex', flexDirection: 'column', height: '100%', overflow: 'hidden' }}>
      {/* Header */}
      <div style={{
        flexShrink: 0, padding: '14px 20px', borderBottom: '1px solid #e2e8f0', background: '#fff',
        display: 'flex', alignItems: 'center', justifyContent: 'space-between', gap: 12,
      }}>
        <div style={{ display: 'flex', alignItems: 'center', gap: 10, minWidth: 0 }}>
          <span style={{
            width: 10, height: 10, borderRadius: 9999,
            background: sch.isActive ? '#22c55e' : '#cbd5e1',
          }} />
          <div style={{ fontSize: 10, fontWeight: 700, color: '#64748b', letterSpacing: '.08em', textTransform: 'uppercase' }}>SCHEDULE #{sch.id}</div>
          <div style={{ fontSize: 15, fontWeight: 700, color: '#0f172a', overflow: 'hidden', textOverflow: 'ellipsis', whiteSpace: 'nowrap' }}>
            {sch.title || 'タイトルなし'}
          </div>
        </div>
        <div style={{ display: 'flex', gap: 8, flexShrink: 0 }}>
          <button onClick={() => onTrigger(sch.id)} style={{
            padding: '6px 12px', background: '#fff', border: '1px solid #bfdbfe', color: '#1d4ed8',
            borderRadius: 8, fontSize: 12, fontWeight: 700, cursor: 'pointer', fontFamily: 'inherit',
            display: 'inline-flex', alignItems: 'center', gap: 4,
          }}>
            <svg width="12" height="12" viewBox="0 0 24 24" fill="currentColor"><path d="M8 5v14l11-7z"/></svg>
            今すぐ実行
          </button>
          <button onClick={() => onPatch(sch.id, { isActive: !sch.isActive })} style={{
            padding: '6px 12px', background: '#fff', border: '1px solid #e2e8f0', color: '#475569',
            borderRadius: 8, fontSize: 12, fontWeight: 700, cursor: 'pointer', fontFamily: 'inherit',
          }}>{sch.isActive ? '停止' : '再開'}</button>
          <button onClick={() => onDelete(sch.id)} style={{
            padding: '6px 12px', background: '#fff', border: '1px solid #fecaca', color: '#dc2626',
            borderRadius: 8, fontSize: 12, fontWeight: 700, cursor: 'pointer', fontFamily: 'inherit',
          }}>削除</button>
        </div>
      </div>

      {/* Body */}
      <div style={{ flex: 1, overflowY: 'auto', padding: '20px 24px', background: '#f8fafc' }}>
        <div style={{ maxWidth: 640, margin: '0 auto' }}>
          {/* Summary strip */}
          <div style={{
            display: 'flex', gap: 10, marginBottom: 20, flexWrap: 'wrap',
          }}>
            <StatChip label="トリガー" value={isEvent ? 'Event' : 'Cron'} />
            <StatChip label={isEvent ? 'ソース' : 'スケジュール'} value={isEvent ? sch.eventSource : parseCronToDisplay(sch.cronExpression)} />
            <StatChip label="ピース" value={sch.pieceName} color="#2563eb" />
            {sch.isActive
              ? <StatChip label="次回実行" value={sch.nextRunAt ? relativeFromNow(sch.nextRunAt) : '—'} />
              : <StatChip label="ステータス" value="停止中" color="#64748b" />}
          </div>

          {/* Form card */}
          <div style={{
            background: '#fff', border: '1px solid #e2e8f0', borderRadius: 16, padding: 20,
            boxShadow: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
          }}>
            <div style={{ fontSize: 11, fontWeight: 700, color: '#64748b', letterSpacing: '.08em', textTransform: 'uppercase', marginBottom: 14 }}>
              基本情報
            </div>

            <FormRow label="タイトル">
              <TextInput value={sch.title || ''} onChange={e => onPatch(sch.id, { title: e.target.value })} placeholder="週次ニュースまとめ" />
            </FormRow>

            <FormRow label="プロンプト" help="エージェントに送るメッセージ">
              <textarea value={sch.body} onChange={e => onPatch(sch.id, { body: e.target.value })} rows={4} style={{
                width: '100%', padding: '8px 12px', fontSize: 13, fontFamily: 'inherit',
                background: '#fff', border: '1px solid #e2e8f0', borderRadius: 10,
                outline: 'none', color: '#0f172a', resize: 'vertical', lineHeight: 1.55,
              }} />
            </FormRow>

            <div style={{ display: 'grid', gridTemplateColumns: '1fr 1fr', gap: 12 }}>
              <FormRow label="ピース">
                <SelectInput value={sch.pieceName} onChange={e => onPatch(sch.id, { pieceName: e.target.value })}>
                  <option value="auto">auto</option>
                  <option value="chat">chat</option>
                  <option value="research">research</option>
                  <option value="general">general</option>
                  <option value="x-ai-digest">x-ai-digest</option>
                </SelectInput>
              </FormRow>
              <FormRow label="出力フォーマット">
                <SelectInput value={sch.outputFormat || 'markdown'} onChange={e => onPatch(sch.id, { outputFormat: e.target.value })}>
                  <option value="markdown">markdown</option>
                  <option value="plain">plain</option>
                  <option value="json">json</option>
                </SelectInput>
              </FormRow>
            </div>
          </div>

          {/* Trigger card */}
          <div style={{
            background: '#fff', border: '1px solid #e2e8f0', borderRadius: 16, padding: 20,
            marginTop: 16, boxShadow: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
          }}>
            <div style={{ fontSize: 11, fontWeight: 700, color: '#64748b', letterSpacing: '.08em', textTransform: 'uppercase', marginBottom: 14 }}>
              トリガー
            </div>

            <div style={{ display: 'flex', gap: 8, marginBottom: 14 }}>
              {['cron', 'event'].map(k => (
                <button key={k} onClick={() => onPatch(sch.id, { triggerKind: k })} style={{
                  flex: 1, padding: '10px 12px', borderRadius: 10,
                  border: '1px solid ' + (sch.triggerKind === k ? '#2563eb' : '#e2e8f0'),
                  background: sch.triggerKind === k ? '#eff6ff' : '#fff',
                  color: sch.triggerKind === k ? '#1d4ed8' : '#64748b',
                  fontWeight: 700, fontSize: 12, cursor: 'pointer', fontFamily: 'inherit',
                  textAlign: 'left', display: 'flex', flexDirection: 'column', gap: 2,
                }}>
                  <span>{k === 'cron' ? '定期実行 (Cron)' : 'イベントトリガー'}</span>
                  <span style={{ fontSize: 10, color: sch.triggerKind === k ? '#3b82f6' : '#94a3b8', fontWeight: 500 }}>
                    {k === 'cron' ? '毎日 / 毎週 / カスタム' : 'GitHub / Mail / Webhook'}
                  </span>
                </button>
              ))}
            </div>

            {!isEvent && (
              <>
                <FormRow label="Cron 式" help="分 時 日 月 曜日  ·  例: 0 7 * * * = 毎日 07:00 (UTC)">
                  <TextInput value={sch.cronExpression} onChange={e => onPatch(sch.id, { cronExpression: e.target.value })}
                    style={{ fontFamily: 'IBM Plex Mono, monospace' }} placeholder="0 7 * * *" />
                </FormRow>
                <div style={{ padding: '10px 12px', background: '#f8fafc', border: '1px solid #e2e8f0', borderRadius: 10, fontSize: 12, color: '#475569' }}>
                  <b style={{ color: '#0f172a' }}>{parseCronToDisplay(sch.cronExpression)}</b>
                  {sch.nextRunAt && <span> · 次回 {formatDateShort(sch.nextRunAt)} ({relativeFromNow(sch.nextRunAt)})</span>}
                </div>
              </>
            )}

            {isEvent && (
              <>
                <FormRow label="イベントソース">
                  <SelectInput value={sch.eventSource || ''} onChange={e => onPatch(sch.id, { eventSource: e.target.value })}>
                    <option value="github.issue.opened">github.issue.opened</option>
                    <option value="github.pr.opened">github.pr.opened</option>
                    <option value="gitea.push">gitea.push</option>
                    <option value="mail.received">mail.received</option>
                    <option value="webhook.custom">webhook.custom</option>
                  </SelectInput>
                </FormRow>
                <FormRow label="フィルタ条件" help="該当イベントが発火した時のみ実行">
                  <TextInput value={sch.eventFilter || ''} onChange={e => onPatch(sch.id, { eventFilter: e.target.value })}
                    style={{ fontFamily: 'IBM Plex Mono, monospace' }} placeholder='repo == "agent-orchestrator" && label == "bug"' />
                </FormRow>
              </>
            )}
          </div>

          {/* History */}
          <div style={{
            background: '#fff', border: '1px solid #e2e8f0', borderRadius: 16, padding: 20,
            marginTop: 16, boxShadow: '0 1px 2px 0 rgb(0 0 0 / 0.05)',
          }}>
            <div style={{
              display: 'flex', alignItems: 'center', justifyContent: 'space-between', marginBottom: 14,
            }}>
              <div style={{ fontSize: 11, fontWeight: 700, color: '#64748b', letterSpacing: '.08em', textTransform: 'uppercase' }}>
                実行履歴
              </div>
              <span style={{ fontSize: 11, color: '#94a3b8' }}>直近 {sch.history?.length || 0} 件</span>
            </div>

            {(sch.history || []).length === 0 && (
              <EmptyState
                compact
                icon={<svg width="16" height="16" viewBox="0 0 24 24" fill="none" stroke="currentColor" strokeWidth="2" strokeLinecap="round" strokeLinejoin="round"><circle cx="12" cy="12" r="9"/><path d="M12 7v5l3 2"/></svg>}
                title="まだ実行されていません"
                hint={sch.isActive ? '次回の実行後にここに履歴が追加されます。' : 'スケジュールは停止中です。「再開」で有効化できます。'}
              />
            )}

            <div style={{ display: 'flex', flexDirection: 'column' }}>
              {(sch.history || []).map((h, i) => (
                <div key={i} style={{
                  display: 'flex', alignItems: 'center', gap: 12, padding: '10px 0',
                  borderTop: i === 0 ? 'none' : '1px solid #f1f5f9',
                }}>
                  <StatusBadge status={h.status} small />
                  <div style={{ flex: 1, fontSize: 12, color: '#334155' }}>
                    <a href="#" style={{ color: '#2563eb', fontWeight: 700, textDecoration: 'none' }}>#{h.taskId}</a>
                    {' · '}{h.summary || '—'}
                  </div>
                  <div style={{ fontSize: 11, color: '#94a3b8', whiteSpace: 'nowrap' }}>{formatDateShort(h.at)}</div>
                </div>
              ))}
            </div>
          </div>

          <div style={{ height: 40 }} />
        </div>
      </div>
    </div>
  );
}

function SchedulesPage({ schedules, activeId, setActiveId, onPatch, onTrigger, onDelete, onOpenCreate }) {
  const [filter, setFilter] = React.useState('all');
  const [search, setSearch] = React.useState('');
  const active = schedules.find(s => s.id === activeId) || schedules[0];
  return (
    <div style={{
      flex: 1, minHeight: 0, display: 'grid',
      gridTemplateColumns: '320px 1fr',
      background: '#f1f5f9', gap: 1,
    }}>
      <div style={{ background: '#fff', padding: 12, minWidth: 0, display: 'flex', flexDirection: 'column' }}>
        <ScheduleListPane
          items={schedules} activeId={active?.id} onSelect={setActiveId}
          filter={filter} setFilter={setFilter} search={search} setSearch={setSearch}
          onOpenCreate={onOpenCreate}
        />
      </div>
      <div style={{ background: '#fff', minWidth: 0 }}>
        <ScheduleDetail sch={active} onPatch={onPatch} onTrigger={onTrigger} onDelete={onDelete} />
      </div>
    </div>
  );
}

window.SchedulesPage = SchedulesPage;
