import { beforeEach, describe, expect, it, vi } from 'vitest'

async function loadHandlers() {
  vi.resetModules()
  return import('./mock-handlers')
}

describe('mockHandlers coverage', () => {
  beforeEach(() => {
    vi.restoreAllMocks()
  })

  it('renames a note, updates its frontmatter title, and rewrites backlinks', async () => {
    const { mockHandlers } = await loadHandlers()
    const vaultPath = '/Users/mock/Test Vault'
    const oldPath = `${vaultPath}/old-note.md`
    const referencePath = `${vaultPath}/reference.md`

    mockHandlers.save_note_content({
      path: oldPath,
      content: '---\ntitle: Old Note\n---\n\n# Old Note',
    })
    mockHandlers.save_note_content({
      path: referencePath,
      content: 'See [[Old Note]] and [[old-note]].',
    })

    const result = mockHandlers.rename_note({
      vault_path: vaultPath,
      old_path: oldPath,
      new_title: 'New Title',
      old_title: 'Old Note',
    })

    const updatedContent = mockHandlers.get_all_content() as Record<string, string>

    expect(result).toEqual({
      new_path: `${vaultPath}/new-title.md`,
      updated_files: 1,
      failed_updates: 0,
    })
    expect(updatedContent[`${vaultPath}/new-title.md`]).toContain('title: New Title')
    expect(updatedContent[referencePath]).toBe('See [[new-title]] and [[new-title]].')
  })

  it('treats an unchanged title as a no-op rename', async () => {
    const { mockHandlers } = await loadHandlers()
    const vaultPath = '/Users/mock/Test Vault'
    const notePath = `${vaultPath}/same-title.md`

    mockHandlers.save_note_content({
      path: notePath,
      content: '---\ntitle: Same Title\n---\n',
    })

    expect(mockHandlers.rename_note({
      vault_path: vaultPath,
      old_path: notePath,
      new_title: 'Same Title',
      old_title: 'Same Title',
    })).toEqual({
      new_path: notePath,
      updated_files: 0,
      failed_updates: 0,
    })
  })

  it('validates filename-only renames and blocks collisions', async () => {
    const { mockHandlers } = await loadHandlers()
    const vaultPath = '/Users/mock/Test Vault'
    const sourcePath = `${vaultPath}/draft.md`

    mockHandlers.save_note_content({
      path: sourcePath,
      content: '# Draft',
    })
    mockHandlers.save_note_content({
      path: `${vaultPath}/duplicate.md`,
      content: '# Existing',
    })

    expect(() => mockHandlers.rename_note_filename({
      vault_path: vaultPath,
      old_path: sourcePath,
      new_filename_stem: '   ',
    })).toThrow('Invalid filename')

    expect(() => mockHandlers.rename_note_filename({
      vault_path: vaultPath,
      old_path: sourcePath,
      new_filename_stem: 'duplicate',
    })).toThrow('A note with that name already exists')
  })

  it('tracks saved files, deduplicates modified-file listings, and clears them on commit', async () => {
    const { mockHandlers } = await loadHandlers()

    mockHandlers.save_note_content({
      path: '/Users/luca/Laputa/26q1-laputa-app.md',
      content: '# Updated project note',
    })
    mockHandlers.save_note_content({
      path: '/Users/luca/Laputa/new-note.md',
      content: '# New note',
    })

    const modifiedBeforeCommit = mockHandlers.get_modified_files()
    const basePathCount = modifiedBeforeCommit.filter((entry) => entry.path === '/Users/luca/Laputa/26q1-laputa-app.md').length

    expect(basePathCount).toBe(1)
    expect(modifiedBeforeCommit.some((entry) => entry.path === '/Users/luca/Laputa/new-note.md')).toBe(true)

    expect(mockHandlers.git_commit({ message: 'Save everything' })).toContain('6 files changed')
    expect(mockHandlers.get_modified_files()).toEqual([])
  })

  it('searches mock content and slices pulse results to the requested limit', async () => {
    const { mockHandlers } = await loadHandlers()
    const projectPath = '/Users/luca/Laputa/26q1-laputa-app.md'

    mockHandlers.save_note_content({
      path: projectPath,
      content: '# Project Plan\n\nStrategic coverage improvements',
    })

    const search = mockHandlers.search_vault({ query: 'strategic', mode: 'content' })
    const pulse = mockHandlers.get_vault_pulse({ limit: 2 })

    expect(search.query).toBe('strategic')
    expect(search.results).toEqual([
      expect.objectContaining({
        path: projectPath,
        title: 'Build Laputa App',
      }),
    ])
    expect(pulse).toHaveLength(2)
    expect(pulse[0]?.shortHash).toBe('a1b2c3d')
  })

  it('applies setting defaults and keeps saved vault lists isolated from caller mutations', async () => {
    const { mockHandlers } = await loadHandlers()

    mockHandlers.save_settings({
      settings: {
        auto_pull_interval_minutes: undefined,
        autogit_enabled: true,
        autogit_idle_threshold_seconds: undefined,
        autogit_inactive_threshold_seconds: undefined,
        auto_advance_inbox_after_organize: true,
        telemetry_consent: true,
        crash_reporting_enabled: false,
        analytics_enabled: true,
        anonymous_id: 'anon-1',
        release_channel: 'alpha',
        ui_language: 'zh-CN',
        default_ai_agent: 'codex',
      },
    })

    expect(mockHandlers.get_settings()).toEqual({
      auto_pull_interval_minutes: 5,
      git_enabled: null,
      git_path: null,
      git_provider: null,
      git_wsl_distro: null,
      autogit_enabled: true,
      autogit_idle_threshold_seconds: 90,
      autogit_inactive_threshold_seconds: 30,
      auto_advance_inbox_after_organize: true,
      telemetry_consent: true,
      crash_reporting_enabled: false,
      analytics_enabled: true,
      anonymous_id: 'anon-1',
      release_channel: 'alpha',
      automatic_update_checks_enabled: null,
      theme_mode: null,
      date_display_format: null,
      note_width_mode: null,
      sidebar_type_pluralization_enabled: null,
      initial_h1_auto_rename_enabled: null,
      ai_features_enabled: null,
      ui_language: 'zh-CN',
      default_ai_agent: 'codex',
      default_ai_target: null,
      ai_model_providers: null,
      ai_workspace_conversations: null,
      hide_gitignored_files: null,
      all_notes_show_pdfs: null,
      all_notes_show_images: null,
      all_notes_show_unsupported: null,
      multi_workspace_enabled: null,
    })

    const list = {
      vaults: [{ label: 'Work', path: '/work' }],
      active_vault: '/work',
    }
    mockHandlers.save_vault_list({ list })

    const savedList = mockHandlers.load_vault_list()
    savedList.vaults.push({ label: 'Leak', path: '/leak' })

    expect(mockHandlers.load_vault_list()).toEqual({
      vaults: [{ label: 'Work', path: '/work' }],
      active_vault: '/work',
    })
  })

  it('builds attachment paths for saved and copied images', async () => {
    const { mockHandlers } = await loadHandlers()
    vi.spyOn(Date, 'now').mockReturnValue(12345)

    expect(mockHandlers.save_image({
      vault_path: '/vault',
      filename: 'diagram.png',
      data: 'base64',
    })).toBe('/vault/attachments/12345-diagram.png')

    expect(mockHandlers.copy_image_to_vault({
      vault_path: '/vault',
      source_path: '/tmp/screenshot.jpg',
    })).toBe('/vault/attachments/12345-screenshot.jpg')
  })
})
