import React, { useState } from 'react';
import type { Note, Notebook } from '@shared/types';
import { KST_OFFSET_MS } from '@shared/util/kstDate.js';
import { inboxApi } from '../api.js';
import { useInbox } from '../store.js';
import { EditableField } from './EditableField.js';
import { IntentBanner } from './IntentBanner.js';
import { pushTagUndo } from './TagUndoToast.js';
import { MoveStatusModal } from './MoveStatusModal.js';
import { RevisionHistoryModal } from './RevisionHistoryModal.js';

interface Props {
  note: Note;
  onDeleted?: () => void;  // inbox mode 전용 (trash mode 에서 미사용)
  onUpdated: (n: Note) => void;
  mode?: 'inbox' | 'trash';  // default 'inbox'
  onRestore?: () => void;
  onPermanentDelete?: () => void;
}

const aiBadgeStyle: React.CSSProperties = {
  display: 'inline-block', marginLeft: 6, padding: '1px 5px',
  background: '#eee', color: '#666', fontSize: 10, borderRadius: 3, verticalAlign: 'middle'
};

function isPastDue(iso: string, today: string): boolean {
  return iso < today; // string comparison works for ISO YYYY-MM-DD
}

function todayKstIso(): string {
  const k = new Date(Date.now() + KST_OFFSET_MS);
  return k.toISOString().slice(0, 10);
}

function DueDateBadge({
  value,
  isEdited,
  today,
  onSave
}: {
  value: string | null;
  isEdited: boolean;
  today: string;
  onSave: (next: string) => Promise<void>;
}): React.ReactElement {
  const [editing, setEditing] = useState(false);
  const [draft, setDraft] = useState(value ?? '');

  React.useEffect(() => { if (!editing) setDraft(value ?? ''); }, [value, editing]);

  if (!editing) {
    if (value === null) {
      return (
        <span
          onClick={() => setEditing(true)}
          style={{ fontSize: 11, color: '#bbb', cursor: 'pointer' }}
          title="마감일 추가"
        >
          📅 마감일 추가
        </span>
      );
    }
    const past = isPastDue(value, today);
    return (
      <span style={{ fontSize: 11, display: 'inline-flex', alignItems: 'center', gap: 4 }}>
        <span
          onClick={() => setEditing(true)}
          style={{
            color: past ? '#999' : '#666',
            textDecoration: past ? 'line-through' : 'none',
            cursor: 'pointer'
          }}
          title={past ? '지난 마감일 — 클릭으로 편집' : '클릭으로 편집'}
        >
          📅 {value}
        </span>
        {!isEdited && (
          <span
            style={{
              fontSize: 9, padding: '0 4px', background: '#eee',
              color: '#888', borderRadius: 2
            }}
            title="AI 추출"
          >
            AI
          </span>
        )}
      </span>
    );
  }

  return (
    <input
      type="date"
      value={draft}
      onChange={(e) => setDraft(e.target.value)}
      onBlur={async () => {
        try { await onSave(draft); }
        catch { /* keep editing if invalid */ return; }
        setEditing(false);
      }}
      onKeyDown={(e) => {
        if (e.key === 'Enter') (e.target as HTMLInputElement).blur();
        if (e.key === 'Escape') { setDraft(value ?? ''); setEditing(false); }
      }}
      autoFocus
      style={{ fontSize: 11, padding: 1 }}
    />
  );
}

function NotebookChip({ current, notebooks, onMove }: {
  current: Notebook;
  notebooks: Notebook[];
  onMove: (id: string) => Promise<void>;
}): React.ReactElement {
  const [open, setOpen] = useState(false);
  return (
    <span style={{ position: 'relative', display: 'inline-block' }}>
      <button
        onClick={() => setOpen(!open)}
        title="다른 노트북으로 이동"
        style={{
          display: 'inline-flex', alignItems: 'center', gap: 4,
          background: '#f0f0f0', border: 'none', borderRadius: 10,
          padding: '2px 8px', fontSize: 11, cursor: 'pointer'
        }}
      >
        <span style={{ width: 6, height: 6, borderRadius: '50%', background: current.color ?? '#bbb', display: 'inline-block' }} />
        {current.name}
      </button>
      {open && (
        <div
          style={{
            position: 'absolute', top: '100%', left: 0,
            background: '#fff', border: '1px solid #ccc', borderRadius: 4,
            zIndex: 50, minWidth: 120, boxShadow: '0 2px 6px rgba(0,0,0,0.15)'
          }}
        >
          {notebooks.filter((nb) => nb.id !== current.id).map((nb) => (
            <button
              key={nb.id}
              onClick={async () => { await onMove(nb.id); setOpen(false); }}
              style={{
                display: 'flex', alignItems: 'center', gap: 6,
                width: '100%', textAlign: 'left',
                padding: '4px 10px', border: 'none', background: 'transparent',
                cursor: 'pointer', fontSize: 11
              }}
            >
              <span style={{ width: 6, height: 6, borderRadius: '50%', background: nb.color ?? '#bbb', display: 'inline-block' }} />
              {nb.name}
            </button>
          ))}
        </div>
      )}
    </span>
  );
}

export function NoteCard({ note, onDeleted, onUpdated, mode = 'inbox', onRestore, onPermanentDelete }: Props): React.ReactElement {
  const isTrash = mode === 'trash';
  // v0.2.9 Cut B Task 13 — ai_status='disabled' 노트는 raw_text 가 1차 정보. 원문 펼침 default 켬.
  const [rawOpen, setRawOpen] = useState(note.aiStatus !== 'done');
  const [local, setLocal] = useState(note);
  const isAiDisabled = local.aiStatus === 'disabled';
  const fallbackTitle = local.rawText.split('\n')[0]?.slice(0, 60) || '(빈 메모)';
  // 이동 modal 열림 여부. 클릭 시 MoveStatusModal 에서 사유 + AI 분류 + 수동 분류 선택.
  const [moveOpen, setMoveOpen] = useState(false);
  const [editingRaw, setEditingRaw] = useState(false);
  const [draftRaw, setDraftRaw] = useState('');
  const [showRevisions, setShowRevisions] = useState(false);

  const notebooks = useInbox((s) => s.notebooks);
  const moveNoteToNotebook = useInbox((s) => s.moveNoteToNotebook);
  const currentNb = notebooks.find((nb) => nb.id === local.notebookId);

  React.useEffect(() => { setLocal(note); }, [note]);

  const formatted = new Date(note.createdAt).toLocaleString('ko-KR');

  async function saveTitle(next: string) {
    await inboxApi.updateAiFields(note.id, { title: next });
    const updated = { ...local, aiTitle: next, titleEditedByUser: true };
    setLocal(updated); onUpdated(updated);
  }

  async function saveSummary(next: string) {
    await inboxApi.updateAiFields(note.id, { summary: next });
    const updated = { ...local, aiSummary: next, summaryEditedByUser: true };
    setLocal(updated); onUpdated(updated);
  }

  async function saveDueDate(next: string) {
    const value = next.trim() === '' ? null : next.trim();
    // Light validation: empty or YYYY-MM-DD
    if (value !== null && !/^\d{4}-\d{2}-\d{2}$/.test(value)) {
      throw new Error('Invalid date');
    }
    await inboxApi.setDueDate(note.id, value);
    const updated = { ...local, dueDate: value, dueDateEditedByUser: true };
    setLocal(updated); onUpdated(updated);
  }

  async function saveRaw() {
    const next = draftRaw;
    if (next.trim().length === 0) return;
    const r = await inboxApi.updateRawText(note.id, next);
    if (!r.ok) return;
    // disabled 노트는 AI 재처리 안 됨 (서버에서 skip) — aiStatus 유지.
    // 그 외는 optimistic 으로 pending 표시 → AiWorker 완료 시 push 로 자동 sync.
    const willReprocess = local.aiStatus !== 'disabled';
    const updated = {
      ...local,
      rawText: next,
      updatedAt: new Date().toISOString(),
      ...(willReprocess ? { aiStatus: 'pending' as const, aiError: null } : {})
    };
    setLocal(updated);
    onUpdated(updated);
    setEditingRaw(false);
  }

  async function removeTag(tagName: string) {
    const removed = local.tags.find((t) => t.name === tagName);
    const nextTagNames = local.tags.filter((t) => t.name !== tagName).map((t) => t.name);
    await inboxApi.updateAiFields(note.id, { tags: nextTagNames });
    const updated = { ...local, tags: local.tags.filter((t) => t.name !== tagName) };
    setLocal(updated); onUpdated(updated);

    if (removed !== undefined) {
      pushTagUndo({
        noteId: note.id,
        tag: removed,
        onUndo: async () => {
          // Restore by re-adding the removed tag.
          // Note: source flag is reset to 'user' on the backend by `updateAiFields` (it
          // only takes names), which mirrors current behaviour for any user-driven
          // tag mutation. Visual restoration matches latest local state.
          const restoredNames = [...updated.tags.map((t) => t.name), removed.name];
          await inboxApi.updateAiFields(note.id, { tags: restoredNames });
          const u2 = { ...updated, tags: [...updated.tags, removed] };
          setLocal(u2); onUpdated(u2);
        }
      });
    }
  }

  function filterByTag(tagName: string): void {
    useInbox.getState().setTagFilter(tagName);
  }

  async function saveIntent(next: string) {
    await inboxApi.setIntent(note.id, next);
    const now = new Date().toISOString();
    const updated = { ...local, userIntent: next, intentPromptedAt: local.intentPromptedAt ?? now };
    setLocal(updated); onUpdated(updated);
  }

  const showIntentBanner = local.aiStatus === 'done' && local.intentPromptedAt === null;

  return (
    // id load-bearing — RecallBanner 의 scrollIntoView target (#6 v0.2.3)
    <div id={`note-${note.id}`} style={{ background: 'white', padding: 16, marginBottom: 12, borderRadius: 10, boxShadow: '0 1px 2px rgba(0,0,0,0.04)' }}>
      <div style={{ fontSize: 11, color: '#888' }}>{formatted}</div>

      {!isTrash && showIntentBanner && (
        <IntentBanner
          noteId={note.id}
          onResolved={(intentText) => {
            const now = new Date().toISOString();
            const updated = { ...local, userIntent: intentText ?? null, intentPromptedAt: now };
            setLocal(updated); onUpdated(updated);
          }}
        />
      )}

      {local.aiStatus === 'pending' && (
        <div style={{ marginTop: 4, display: 'flex', alignItems: 'center', gap: 8 }}>
          <div style={{ fontSize: 16, fontWeight: 600, color: '#666' }}>
            Inkling이 정리하는 중…
          </div>
          {/* v0.3.9 — pending cancel UI. Ollama 끊김 / 무한 pending 시 사용자 unblock path. */}
          <button
            onClick={async () => {
              await inboxApi.cancelPending(local.id);
              // push 기반 — onNoteUpdated 가 store 자동 갱신.
            }}
            style={{
              background: 'none', border: '1px solid #ccc', color: '#666',
              cursor: 'pointer', fontSize: 11, padding: '2px 8px', borderRadius: 4
            }}
            title="AI 자동 처리를 건너뛰고 원문만 보관"
          >
            건너뛰기
          </button>
        </div>
      )}
      {local.aiStatus === 'failed' && (
        <div style={{ marginTop: 4 }}>
          <div style={{ display: 'flex', alignItems: 'center', gap: 8 }}>
            <div style={{ fontSize: 16, fontWeight: 600, color: '#a55' }}>
              정리 보류 — 원문은 안전합니다
            </div>
            {/* v0.3.9 — per-note 재시도 UI. FailedBanner 의 일괄 재시도와 별개. */}
            <button
              onClick={async () => {
                await inboxApi.retryOneFailed(local.id);
              }}
              style={{
                background: 'none', border: '1px solid #a55', color: '#a55',
                cursor: 'pointer', fontSize: 11, padding: '2px 8px', borderRadius: 4
              }}
              title="이 노트만 AI 처리 재시도"
            >
              재시도
            </button>
          </div>
          {/* v0.3.14 — fail 원인 inline 표시. ai_error 의 raw message 가 그대로 사용자에게
              보여서 디버깅 + 모델/네트워크 이슈 진단 가능. 너무 길면 <details> 로 접힘. */}
          {local.aiError !== null && local.aiError.length > 0 && (
            <details style={{ marginTop: 4 }}>
              <summary style={{ fontSize: 12, color: '#a55', cursor: 'pointer' }}>
                원인 보기
              </summary>
              <pre style={{
                fontSize: 11, color: '#666', background: '#fff0f0', padding: 6,
                borderRadius: 4, marginTop: 4, whiteSpace: 'pre-wrap', wordBreak: 'break-word'
              }}>
                {local.aiError}
              </pre>
            </details>
          )}
        </div>
      )}
      {/* v0.2.9 Cut B Task 13 — ai_status='disabled': raw_text 첫 줄 fallback title.
          summary/tags 는 hide. 원문은 아래 "원문 보기" 영역에서 항상 표시. */}
      {isAiDisabled && (
        <div style={{ marginTop: 4 }}>
          <h3 style={{ margin: 0, fontSize: 16, fontWeight: 600 }}>{fallbackTitle}</h3>
        </div>
      )}
      {local.aiStatus === 'done' && (
        <>
          {isTrash ? (
            <>
              <div style={{ marginTop: 4 }}>
                <h3 style={{ margin: 0, fontSize: 16, fontWeight: 600 }}>{local.aiTitle ?? '(제목 없음)'}</h3>
              </div>
              <div style={{ marginTop: 6, fontSize: 13, color: '#333', whiteSpace: 'pre-wrap' }}>
                {local.aiSummary ?? '(요약 없음)'}
              </div>
              {local.dueDate !== null && (
                <div style={{ marginTop: 6 }}>
                  <span style={{ fontSize: 11, color: '#666' }}>📅 {local.dueDate}</span>
                </div>
              )}
              {local.tags.length > 0 && (
                <div style={{ marginTop: 8, display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                  {local.tags.map((t) => (
                    <span
                      key={t.name}
                      style={{
                        background: t.source === 'ai' ? '#eaf3ff' : '#e9f9e4',
                        color: t.source === 'ai' ? '#0a4b80' : '#236b1a',
                        padding: '2px 8px',
                        borderRadius: 12,
                        fontSize: 12
                      }}
                    >
                      {t.name}{t.source === 'ai' && <sub style={{ marginLeft: 3, fontSize: 9 }}>AI</sub>}
                    </span>
                  ))}
                </div>
              )}
            </>
          ) : (
            <>
              <div style={{ marginTop: 4 }}>
                <EditableField
                  value={local.aiTitle ?? ''}
                  onSave={saveTitle}
                  style={{ display: 'inline-block', fontSize: 16, fontWeight: 600 }}
                  singleLine
                />
                {!local.titleEditedByUser && <span style={aiBadgeStyle} title="AI 제안">AI</span>}
              </div>
              <div style={{ marginTop: 6 }}>
                <EditableField
                  value={local.aiSummary ?? ''}
                  onSave={saveSummary}
                  style={{ fontSize: 13, color: '#333', whiteSpace: 'pre-wrap' }}
                  singleLine={false}
                />
                {!local.summaryEditedByUser && <span style={aiBadgeStyle} title="AI 제안">AI</span>}
              </div>
              <div style={{ marginTop: 6 }}>
                <DueDateBadge
                  value={local.dueDate}
                  isEdited={local.dueDateEditedByUser}
                  today={todayKstIso()}
                  onSave={saveDueDate}
                />
              </div>
              {local.tags.length > 0 && (
                <div style={{ marginTop: 8, display: 'flex', gap: 6, flexWrap: 'wrap' }}>
                  {local.tags.map((t) => (
                    <span
                      key={t.name}
                      style={{
                        background: t.source === 'ai' ? '#eaf3ff' : '#e9f9e4',
                        color: t.source === 'ai' ? '#0a4b80' : '#236b1a',
                        padding: '2px 4px 2px 8px',
                        borderRadius: 12,
                        fontSize: 12,
                        display: 'inline-flex',
                        alignItems: 'center',
                        gap: 4
                      }}
                    >
                      <span
                        onClick={() => filterByTag(t.name)}
                        style={{ cursor: 'pointer' }}
                        title={`#${t.name} 노트만 보기`}
                      >
                        {t.name}{t.source === 'ai' && <sub style={{ marginLeft: 3, fontSize: 9 }}>AI</sub>}
                      </span>
                      <button
                        onClick={(e) => { e.stopPropagation(); void removeTag(t.name); }}
                        style={{
                          background: 'none',
                          border: 'none',
                          cursor: 'pointer',
                          color: 'inherit',
                          fontSize: 14,
                          padding: '0 2px',
                          lineHeight: 1,
                          opacity: 0.6
                        }}
                        title="태그 제거"
                        aria-label={`${t.name} 태그 제거`}
                      >
                        ×
                      </button>
                    </span>
                  ))}
                </div>
              )}
              {currentNb && (
                <div style={{ marginTop: 8 }}>
                  <NotebookChip
                    current={currentNb}
                    notebooks={notebooks}
                    onMove={async (newId) => {
                      await moveNoteToNotebook(local.id, newId);
                      setLocal({ ...local, notebookId: newId });
                    }}
                  />
                </div>
              )}
              {local.userIntent !== null && (
                <div style={{ marginTop: 10, padding: 8, background: '#fffbe9', borderRadius: 6 }}>
                  <span style={{ fontSize: 12, color: '#7a5a00', marginRight: 6 }}>💡</span>
                  <EditableField
                    value={local.userIntent}
                    onSave={saveIntent}
                    style={{ display: 'inline-block', fontSize: 13, color: '#444' }}
                    singleLine
                  />
                </div>
              )}
            </>
          )}
        </>
      )}

      {local.media.length > 0 && (
        <div style={{ marginTop: 10, display: 'flex', flexWrap: 'wrap', gap: 6 }}>
          {local.media.map((m) => (
            // alt="" — decorative (relPath 는 사용자 의미 X). title 이 hover tooltip.
            <img
              key={m.id}
              src={`inkling-media://${m.relPath}`}
              alt=""
              title={m.relPath}
              onClick={() => { void inboxApi.openMedia(m.relPath); }}
              style={{
                width: 48,
                height: 48,
                objectFit: 'cover',
                borderRadius: 4,
                cursor: 'pointer',
                border: '1px solid #e0e0e0'
              }}
            />
          ))}
        </div>
      )}

      <div style={{ marginTop: 10 }}>
        <button onClick={() => setRawOpen((o) => !o)} style={{ background: 'none', border: 'none', color: '#555', fontSize: 12, cursor: 'pointer', padding: 0 }}>
          {rawOpen ? '▾ 원문 접기' : '▸ 원문 보기'}
        </button>
        {rawOpen && (
          <div style={{ marginTop: 6 }}>
            {editingRaw ? (
              <div>
                <textarea
                  aria-label="원문 편집"
                  value={draftRaw}
                  onChange={(e) => setDraftRaw(e.target.value)}
                  style={{ width: '100%', minHeight: 80, fontSize: 12, fontFamily: 'inherit', padding: 8, border: '1px solid #ddd', borderRadius: 4, boxSizing: 'border-box' }}
                />
                <div style={{ marginTop: 4, display: 'flex', gap: 6, justifyContent: 'flex-end' }}>
                  <button onClick={() => setEditingRaw(false)} style={{ background: 'none', border: '1px solid #ccc', color: '#444', cursor: 'pointer', fontSize: 12, padding: '3px 10px', borderRadius: 4 }}>취소</button>
                  <button onClick={() => { void saveRaw(); }} style={{ background: '#0a4b80', border: 'none', color: '#fff', cursor: 'pointer', fontSize: 12, padding: '3px 10px', borderRadius: 4 }}>저장</button>
                </div>
              </div>
            ) : (
              <>
                <pre style={{ margin: 0, whiteSpace: 'pre-wrap', fontSize: 12, color: '#555', background: '#fafafa', padding: 8, borderRadius: 4 }}>
                  {local.rawText}
                </pre>
                <div style={{ marginTop: 4, display: 'flex', gap: 6, justifyContent: 'flex-end' }}>
                  <button onClick={() => setShowRevisions(true)} style={{ background: 'none', border: 'none', color: '#0a4b80', cursor: 'pointer', fontSize: 12, padding: 0 }}>이력</button>
                  <button onClick={() => { setDraftRaw(local.rawText); setEditingRaw(true); }} style={{ background: 'none', border: '1px solid #ccc', color: '#444', cursor: 'pointer', fontSize: 12, padding: '3px 10px', borderRadius: 4 }}>편집</button>
                </div>
              </>
            )}
          </div>
        )}
      </div>

      <div style={{ marginTop: 10, textAlign: 'right' }}>
        <div
          style={{
            display: 'flex',
            gap: 8,
            justifyContent: 'flex-end',
            alignItems: 'center'
          }}
        >
          {/* 이동 버튼 — 클릭 시 MoveStatusModal 진입.
              사유 입력 + AI 자동 분류 + 수동 status 선택 한 곳에서 처리. */}
          <button
            onClick={() => setMoveOpen(true)}
            aria-label="이동"
            style={{
              background: 'none',
              border: '1px solid #ccc',
              color: '#444',
              cursor: 'pointer',
              fontSize: 12,
              padding: '4px 10px',
              borderRadius: 4
            }}
          >
            이동
          </button>

          {/* trash mode 만 영구 삭제 + 복구 보존 (휴지통 단독 액션). */}
          {isTrash && (
            <>
              <button
                onClick={onRestore}
                style={{
                  background: 'none', border: '1px solid #0a4b80', color: '#0a4b80',
                  cursor: 'pointer', fontSize: 12, padding: '4px 10px', borderRadius: 4
                }}
              >
                🔄 복구
              </button>
              <button
                onClick={onPermanentDelete}
                style={{
                  background: 'none', border: '1px solid #c93030', color: '#c93030',
                  cursor: 'pointer', fontSize: 12, padding: '4px 10px', borderRadius: 4
                }}
              >
                🗑 영구 삭제
              </button>
            </>
          )}
        </div>
      </div>

      {moveOpen && (
        <MoveStatusModal
          noteId={local.id}
          rawText={local.rawText}
          summary={local.aiSummary ?? ''}
          currentStatus={local.status}
          onClose={() => setMoveOpen(false)}
          onMoved={(newStatus, reason) => {
            const updated = { ...local, status: newStatus, moveReason: reason };
            setLocal(updated);
            onUpdated(updated);
            // inbox/완료/보관/휴지통 view 의 list 가 status 별로 필터되므로 status 변경 시 onDeleted 호출.
            if (newStatus !== local.status) onDeleted?.();
            // setStatus IPC 는 pushNoteUpdated emit 안 함 → 헤더 탭 counts 가 stale.
            // refreshMeta 로 server-authoritative counts 재로드.
            void useInbox.getState().refreshMeta();
            setMoveOpen(false);
          }}
        />
      )}
      {showRevisions && (
        <RevisionHistoryModal
          noteId={local.id}
          onClose={() => setShowRevisions(false)}
          onRestored={(newRawText) => {
            const updated = { ...local, rawText: newRawText, updatedAt: new Date().toISOString() };
            setLocal(updated);
            onUpdated(updated);
          }}
        />
      )}
    </div>
  );
}
