import { COLUMN_LABELS } from './urlState';

export function relativeTime(dateStr: string): string {
  const diff = Date.now() - new Date(dateStr).getTime();
  const mins = Math.floor(diff / 60000);
  if (mins < 1) return 'たった今';
  if (mins < 60) return `${mins}分前`;
  const hrs = Math.floor(mins / 60);
  if (hrs < 24) return `${hrs}時間前`;
  return `${Math.floor(hrs / 24)}日前`;
}

export function formatFileDate(isoStr: string): string {
  const date = new Date(isoStr);
  if (Number.isNaN(date.getTime())) return '';
  const now = new Date();
  const diffMs = now.getTime() - date.getTime();
  const diffMin = Math.floor(diffMs / 60000);
  if (diffMin < 1) return 'たった今';
  if (diffMin < 60) return `${diffMin}分前`;
  const sameDay = date.getFullYear() === now.getFullYear() && date.getMonth() === now.getMonth() && date.getDate() === now.getDate();
  if (sameDay) return date.toLocaleTimeString('ja-JP', { hour: '2-digit', minute: '2-digit' });
  const sameYear = date.getFullYear() === now.getFullYear();
  if (sameYear) return `${date.getMonth() + 1}/${date.getDate()} ${date.toLocaleTimeString('ja-JP', { hour: '2-digit', minute: '2-digit' })}`;
  return `${date.getFullYear()}/${date.getMonth() + 1}/${date.getDate()}`;
}

export function workerPill(workerId: string | null): string {
  if (!workerId) return '-';
  if (workerId.includes('148')) return `${workerId} (quality)`;
  if (workerId.includes('074')) return `${workerId} (fast)`;
  return workerId;
}

export function stateTone(state: string): { bg: string; fg: string } {
  if (state === 'open') return { bg: '#e0efff', fg: '#1d4ed8' };
  if (state === 'closed') return { bg: '#e2e8f0', fg: '#475569' };
  if (state === 'deleted') return { bg: '#fee2e2', fg: '#b91c1c' };
  return { bg: '#dbeafe', fg: '#1e3a8a' };
}

export function statusTone(status: string): { bg: string; fg: string } {
  if (status === 'running') return { bg: '#dcfce7', fg: '#166534' };
  if (status === 'waiting_human') return { bg: '#fef9c3', fg: '#854d0e' };
  if (status === 'waiting_subtasks') return { bg: '#e0e7ff', fg: '#3730a3' };
  if (status === 'failed') return { bg: '#fee2e2', fg: '#b91c1c' };
  if (status === 'succeeded') return { bg: '#dbeafe', fg: '#1e40af' };
  if (status === 'retry') return { bg: '#fef3c7', fg: '#92400e' };
  return { bg: '#e2e8f0', fg: '#475569' };
}

export function formatStatusLabel(status: string): string {
  return COLUMN_LABELS[status] ?? status;
}

export function matchText(value: string | undefined | null, query: string): boolean {
  if (!query.trim()) return true;
  return (value ?? '').toLowerCase().includes(query.trim().toLowerCase());
}

export function isTextPreviewable(name: string): boolean {
  return /\.(md|markdown|csv|txt|log|json|jsonl)$/i.test(name);
}

export function isImagePreviewable(name: string): boolean {
  return /\.(png|jpe?g|gif|webp|bmp)$/i.test(name);
}

export function isPdfPreviewable(name: string): boolean {
  return /\.pdf$/i.test(name);
}

export function isHtmlPreviewable(name: string): boolean {
  return /\.html?$/i.test(name);
}

export function isPreviewable(name: string): boolean {
  return isTextPreviewable(name) || isImagePreviewable(name) || isPdfPreviewable(name) || isHtmlPreviewable(name);
}

export type ActivityEventKind = 'movement_start' | 'movement_complete' | 'tool' | 'preview' | 'final' | 'ask' | 'preflight' | 'other';

export interface ActivityEvent {
  id: string;
  kind: ActivityEventKind;
  label: string;
  note: string;
  state: 'running' | 'done' | 'idle';
  timestamp: string | null;
  workerId: string | null;
  mode: string | null;
}

export function formatActivityMeta(workerId: string | null, mode: string | null): string {
  return [workerId ? `worker: ${workerPill(workerId)}` : '', mode ? `mode: ${mode}` : ''].filter(Boolean).join(' · ');
}

export function parseActivityLog(logText: string): ActivityEvent[] {
  const lines = logText.split('\n').map(line => line.trim()).filter(Boolean);
  const events: ActivityEvent[] = [];

  for (const [index, rawLine] of lines.entries()) {
    const timestampMatch = /^\[([^\]]+)\]\s+/.exec(rawLine);
    const timestamp = timestampMatch?.[1] ?? null;
    const workerId = /\[worker:([^\]]+)\]/.exec(rawLine)?.[1] ?? null;
    const mode = /\[mode:([^\]]+)\]/.exec(rawLine)?.[1] ?? null;
    const line = rawLine
      .replace(/^\[[^\]]+\]\s+/, '')
      .replace(/\[worker:[^\]]+\]\s*/g, '')
      .replace(/\[mode:[^\]]+\]\s*/g, '')
      .trim();

    const base = { id: `${timestamp ?? 'line'}-${index}`, timestamp, workerId, mode };

    const movementStart = /^\[([^\]]+)\] (?:start|ステップ開始)$/.exec(line);
    if (movementStart) {
      events.push({ ...base, kind: 'movement_start', label: movementStart[1]!, note: 'started', state: 'running' });
      continue;
    }

    const movementComplete = /^\[([^\]]+)\] (?:complete ->|完了 →) (.+)$/.exec(line);
    if (movementComplete) {
      events.push({ ...base, kind: 'movement_complete', label: movementComplete[1]!, note: `next: ${movementComplete[2]}`, state: 'done' });
      continue;
    }

    const movementPreview = /^\[([^\]]+)\] preview: (.+)$/.exec(line);
    if (movementPreview) {
      events.push({ ...base, kind: 'preview', label: movementPreview[1]!, note: movementPreview[2]!, state: 'running' });
      continue;
    }

    const preview = /^preview:\s*(.+)$/i.exec(line);
    if (preview) {
      events.push({ ...base, kind: 'preview', label: 'assistant', note: preview[1]!, state: 'running' });
      continue;
    }

    const final = /^(?:final:|最終結果:)\s*([a-z_]+)/i.exec(line);
    if (final) {
      const normalized = final[1]!.toLowerCase();
      events.push({ ...base, kind: 'final', label: 'final', note: normalized, state: normalized === 'completed' ? 'done' : 'running' });
      continue;
    }

    const ask = /^(?:ask:|\[ASK\])\s*(.+)$/i.exec(line);
    if (ask) {
      events.push({ ...base, kind: 'ask', label: 'ask', note: ask[1]!, state: 'idle' });
      continue;
    }

    // tool 正規表現より前に preflight をマッチさせる。
    // ok 行は短縮版 ("preflight: 12,400/128,000 tokens") として書かれる。
    // blocked 行はフル ("[llm-preflight:blocked] ...") のまま出る。
    const preflightShort = /^preflight:\s*(.+)$/.exec(line);
    if (preflightShort) {
      events.push({ ...base, kind: 'preflight', label: 'preflight', note: preflightShort[1]!, state: 'idle' });
      continue;
    }
    const preflightBlocked = /^\[llm-preflight:blocked\]\s*(.+)$/.exec(line);
    if (preflightBlocked) {
      events.push({ ...base, kind: 'preflight', label: 'preflight (blocked)', note: preflightBlocked[1]!, state: 'idle' });
      continue;
    }

    const tool = /^([A-Za-z][A-Za-z0-9_]+):\s*(.+)$/.exec(line);
    if (tool) {
      events.push({ ...base, kind: 'tool', label: tool[1]!, note: tool[2]!, state: 'idle' });
      continue;
    }

    events.push({ ...base, kind: 'other', label: 'log', note: line, state: 'idle' });
  }

  return events;
}

export function buildActivitySteps(events: ActivityEvent[]): Array<{ label: string; state: 'running' | 'done' | 'idle'; note: string }> {
  const steps = new Map<string, { state: 'running' | 'done' | 'idle'; note: string }>();
  let currentMovement: string | null = null;

  for (const event of events) {
    const meta = formatActivityMeta(event.workerId, event.mode);
    const suffix = meta ? ` · ${meta}` : '';

    if (event.kind === 'movement_start') {
      currentMovement = event.label;
      steps.set(event.label, { state: 'running', note: `started${suffix}` });
      continue;
    }

    if (event.kind === 'tool' && currentMovement && steps.has(currentMovement)) {
      steps.set(currentMovement, { state: 'running', note: `tool: ${event.label} · ${event.note}${suffix}` });
      continue;
    }

    if (event.kind === 'preview' && steps.has(event.label)) {
      steps.set(event.label, { state: 'running', note: `preview: ${event.note}${suffix}` });
      continue;
    }

    if (event.kind === 'movement_complete') {
      currentMovement = null;
      steps.set(event.label, { state: 'done', note: `${event.note}${suffix}` });
      continue;
    }

    if (event.kind === 'final') {
      steps.set('final', { state: event.state, note: `${event.note}${suffix}` });
    }
  }

  return Array.from(steps.entries()).map(([label, value]) => ({ label, ...value }));
}

export function formatActivityTimestamp(timestamp: string | null): string {
  if (!timestamp) return '';
  const date = new Date(timestamp);
  if (Number.isNaN(date.getTime())) return '';
  return date.toLocaleTimeString([], { hour: '2-digit', minute: '2-digit', second: '2-digit' });
}

export function activityKindLabel(kind: ActivityEventKind): string {
  switch (kind) {
    case 'movement_start':
    case 'movement_complete': return 'STEP';
    case 'tool': return 'TOOL';
    case 'preview': return 'PREVIEW';
    case 'final': return 'FINAL';
    case 'ask': return 'ASK';
    case 'preflight': return 'LLM';
    default: return 'LOG';
  }
}

export function activityEventTitle(event: ActivityEvent): string {
  switch (event.kind) {
    case 'preview': return `${event.label} response`;
    case 'final': return 'Run finished';
    case 'ask': return 'Need user input';
    default: return event.label;
  }
}

export function renderCsvRows(csv: string): string[][] {
  const rows = csv.trim().split(/\r?\n/).map(r => r.split(','));
  return rows.slice(0, 120).map(r => r.slice(0, 20));
}
