import { describe, it, expect } from 'vitest';
import {
  composeMarkdown,
  type ExportNote
} from '@main/services/exportFormat.js';
import { parseExportNote } from '@main/services/importFormat.js';

const baseNote: ExportNote = {
  id: '014a3b9c-1234-7890-abcd-000000000001',
  createdAt: '2026-04-25T14:23:11.000Z',
  updatedAt: '2026-04-25T14:24:02.000Z',
  rawText: '회고 메모 본문',
  aiTitle: '주간 회고 PR 리뷰',
  aiSummary: '회고 양식 통일을 위한 메모.',
  titleEditedByUser: false,
  summaryEditedByUser: false,
  aiProvider: 'local-ollama/gemma4:e4b',
  aiGeneratedAt: '2026-04-25T14:23:34.000Z',
  userIntent: null,
  intentPromptedAt: null,
  status: 'active',
  statusChangedAt: null,
  moveReason: null,
  dueDate: null,
  dueDateEditedByUser: false,
  tags: [{ name: 'pr', source: 'ai' }, { name: 'review', source: 'user' }],
  media: []
};

describe('parseExportNote — round-trip with composeMarkdown', () => {
  it('round-trips the base note', () => {
    const md = composeMarkdown(baseNote);
    const parsed = parseExportNote(md);
    expect(parsed.id).toBe(baseNote.id);
    expect(parsed.createdAt).toBe(baseNote.createdAt);
    expect(parsed.updatedAt).toBe(baseNote.updatedAt);
    expect(parsed.rawText).toBe(baseNote.rawText);
    expect(parsed.aiTitle).toBe(baseNote.aiTitle);
    expect(parsed.aiSummary).toBe(baseNote.aiSummary);
    expect(parsed.aiProvider).toBe(baseNote.aiProvider);
    expect(parsed.aiGeneratedAt).toBe(baseNote.aiGeneratedAt);
    expect(parsed.titleEditedByUser).toBe(false);
    expect(parsed.summaryEditedByUser).toBe(false);
    expect(parsed.tags).toEqual([
      { name: 'pr', source: 'ai' },
      { name: 'review', source: 'user' }
    ]);
    expect(parsed.images).toEqual([]);
    expect(parsed.exportVersion).toBe(1);
  });

  it('round-trips a note with media', () => {
    const note: ExportNote = {
      ...baseNote,
      media: [
        { rel: 'media/014a3b9c__1.png', mime: 'image/png', bytes: 1234 },
        { rel: 'media/014a3b9c__2.jpg', mime: 'image/jpeg', bytes: 5678 }
      ]
    };
    const md = composeMarkdown(note);
    const parsed = parseExportNote(md);
    expect(parsed.images).toEqual([
      { rel: 'media/014a3b9c__1.png', mime: 'image/png', bytes: 1234 },
      { rel: 'media/014a3b9c__2.jpg', mime: 'image/jpeg', bytes: 5678 }
    ]);
    expect(parsed.rawText).toBe(note.rawText);
  });
});

describe('parseExportNote — frontmatter scalar variants', () => {
  it('parses plain scalar', () => {
    const md = composeMarkdown({ ...baseNote, aiTitle: '주간 회고' });
    const parsed = parseExportNote(md);
    expect(parsed.aiTitle).toBe('주간 회고');
  });

  it('parses single-quoted with embedded apostrophe (`` `` escape)', () => {
    const note: ExportNote = { ...baseNote, aiTitle: "it's a: title" };
    const md = composeMarkdown(note);
    // Should be emitted as: title: 'it''s a: title'
    expect(md).toContain("title: 'it''s a: title'");
    const parsed = parseExportNote(md);
    expect(parsed.aiTitle).toBe("it's a: title");
  });

  it('parses block scalar `|-` for multiline summary', () => {
    const note: ExportNote = {
      ...baseNote,
      aiSummary: 'line1\nline2\nline3'
    };
    const md = composeMarkdown(note);
    expect(md).toContain('summary: |-');
    const parsed = parseExportNote(md);
    expect(parsed.aiSummary).toBe('line1\nline2\nline3');
  });
});

describe('parseExportNote — list parsing', () => {
  it('parses tags inline flow', () => {
    const md = composeMarkdown({
      ...baseNote,
      tags: [
        { name: 'foo', source: 'ai' },
        { name: 'bar baz', source: 'user' }
      ]
    });
    const parsed = parseExportNote(md);
    expect(parsed.tags).toEqual([
      { name: 'foo', source: 'ai' },
      { name: 'bar baz', source: 'user' }
    ]);
  });

  it('parses images list with mime + bytes', () => {
    const md = composeMarkdown({
      ...baseNote,
      media: [{ rel: 'media/014a3b9c__1.png', mime: 'image/png', bytes: 9876 }]
    });
    const parsed = parseExportNote(md);
    expect(parsed.images).toEqual([
      { rel: 'media/014a3b9c__1.png', mime: 'image/png', bytes: 9876 }
    ]);
  });
});

describe('parseExportNote — body extraction', () => {
  it('extracts rawText with summary present', () => {
    const md = composeMarkdown({ ...baseNote, rawText: '본문\n두 번째 줄' });
    const parsed = parseExportNote(md);
    expect(parsed.rawText).toBe('본문\n두 번째 줄');
  });

  it('extracts rawText with summary absent', () => {
    const md = composeMarkdown({
      ...baseNote,
      aiSummary: null,
      rawText: '요약 없는 본문'
    });
    const parsed = parseExportNote(md);
    expect(parsed.rawText).toBe('요약 없는 본문');
  });

  it('extracts rawText with no images', () => {
    const md = composeMarkdown({ ...baseNote, rawText: '이미지 없음', media: [] });
    const parsed = parseExportNote(md);
    expect(parsed.rawText).toBe('이미지 없음');
  });

  it('preserves `>` mid-line in rawText (not parsed as blockquote)', () => {
    const md = composeMarkdown({
      ...baseNote,
      rawText: '값 a > b 라는 부등호'
    });
    const parsed = parseExportNote(md);
    expect(parsed.rawText).toBe('값 a > b 라는 부등호');
  });

  it('preserves `# ` mid-line in rawText (not parsed as heading)', () => {
    const md = composeMarkdown({
      ...baseNote,
      rawText: '예시: see issue #1 어쩌고 # 가운데 해시'
    });
    const parsed = parseExportNote(md);
    expect(parsed.rawText).toBe('예시: see issue #1 어쩌고 # 가운데 해시');
  });
});

describe('parseExportNote — provenance', () => {
  it('recovers titleEditedByUser from title_source: user', () => {
    const md = composeMarkdown({ ...baseNote, titleEditedByUser: true });
    const parsed = parseExportNote(md);
    expect(parsed.titleEditedByUser).toBe(true);
  });

  it('recovers summaryEditedByUser from summary_source: user', () => {
    const md = composeMarkdown({ ...baseNote, summaryEditedByUser: true });
    const parsed = parseExportNote(md);
    expect(parsed.summaryEditedByUser).toBe(true);
  });

  it('exposes exportVersion = 1', () => {
    const md = composeMarkdown(baseNote);
    const parsed = parseExportNote(md);
    expect(parsed.exportVersion).toBe(1);
  });
});

describe('parseExportNote — status/dueDate/moveReason round-trip (v0.3.0 Cut E)', () => {
  it('round-trips status=active (default)', () => {
    const md = composeMarkdown(baseNote);
    const parsed = parseExportNote(md);
    expect(parsed.status).toBe('active');
    expect(parsed.statusChangedAt).toBeNull();
    expect(parsed.moveReason).toBeNull();
    expect(parsed.dueDate).toBeNull();
    expect(parsed.dueDateEditedByUser).toBe(false);
  });

  it('round-trips status=archived with statusChangedAt and moveReason', () => {
    const note: ExportNote = {
      ...baseNote,
      status: 'archived',
      statusChangedAt: '2026-05-01T10:00:00Z',
      moveReason: 'project done'
    };
    const md = composeMarkdown(note);
    const parsed = parseExportNote(md);
    expect(parsed.status).toBe('archived');
    expect(parsed.statusChangedAt).toBe('2026-05-01T10:00:00Z');
    expect(parsed.moveReason).toBe('project done');
  });

  it('round-trips dueDate with dueDateEditedByUser=true', () => {
    const note: ExportNote = {
      ...baseNote,
      dueDate: '2026-06-15',
      dueDateEditedByUser: true
    };
    const md = composeMarkdown(note);
    const parsed = parseExportNote(md);
    expect(parsed.dueDate).toBe('2026-06-15');
    expect(parsed.dueDateEditedByUser).toBe(true);
  });

  it('round-trips dueDate with dueDateEditedByUser=false (ai source)', () => {
    const note: ExportNote = {
      ...baseNote,
      dueDate: '2026-07-01',
      dueDateEditedByUser: false
    };
    const md = composeMarkdown(note);
    const parsed = parseExportNote(md);
    expect(parsed.dueDate).toBe('2026-07-01');
    expect(parsed.dueDateEditedByUser).toBe(false);
  });

  it('defaults to status=active for older exports without status field', () => {
    // Simulate a pre-Cut E export that has no status line
    const md = `---\nid: 014a3b9c-1234-7890-abcd-000000000001\ncreated_at: 2026-04-25T14:23:11.000Z\nupdated_at: 2026-04-25T14:24:02.000Z\ntitle: t\ntitle_source: ai\nsummary: s\nsummary_source: ai\ninkling_export_version: 1\n---\n\n# t\n\n> s\n\nbody\n`;
    const parsed = parseExportNote(md);
    expect(parsed.status).toBe('active');
    expect(parsed.dueDate).toBeNull();
    expect(parsed.moveReason).toBeNull();
    expect(parsed.dueDateEditedByUser).toBe(false);
  });
});

describe('parseExportNote — edge cases', () => {
  it('preserves user_intent when present', () => {
    const md = composeMarkdown({
      ...baseNote,
      userIntent: '팀에서 회고 양식 통일',
      intentPromptedAt: '2026-04-25T14:24:02.000Z'
    });
    const parsed = parseExportNote(md);
    expect(parsed.userIntent).toBe('팀에서 회고 양식 통일');
    expect(parsed.intentPromptedAt).toBe('2026-04-25T14:24:02.000Z');
  });

  it('returns null aiTitle / aiSummary when omitted', () => {
    const md = composeMarkdown({
      ...baseNote,
      aiTitle: null,
      aiSummary: null
    });
    const parsed = parseExportNote(md);
    expect(parsed.aiTitle).toBeNull();
    expect(parsed.aiSummary).toBeNull();
  });

  it('throws when input lacks frontmatter delimiter', () => {
    expect(() => parseExportNote('hello world')).toThrow();
  });
});
