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

vi.mock('node:fs/promises');

import { readFile } from 'node:fs/promises';
import { detectMarker } from '../detect-marker.js';

const mockReadFile = vi.mocked(readFile);

beforeEach(() => {
  vi.resetAllMocks();
});

describe('hooks/detectMarker', () => {
  // HTML marker with source and target
  it('detects HTML marker and extracts source and target', async () => {
    mockReadFile.mockResolvedValueOnce(
      '<!-- PromptScript generated | source: .promptscript/instructions.prs | target: .github/copilot-instructions.md -->\n'
    );

    const result = await detectMarker('/workspace/.github/copilot-instructions.md');

    expect(result).toEqual({
      isGenerated: true,
      source: '.promptscript/instructions.prs',
      target: '.github/copilot-instructions.md',
    });
  });

  // YAML marker with source and target
  it('detects YAML marker and extracts source and target', async () => {
    mockReadFile.mockResolvedValueOnce(
      '# promptscript-generated: true | source: agent.prs | target: CLAUDE.md\n'
    );

    const result = await detectMarker('/workspace/CLAUDE.md');

    expect(result).toEqual({
      isGenerated: true,
      source: 'agent.prs',
      target: 'CLAUDE.md',
    });
  });

  // Legacy HTML marker (no source/target)
  it('detects legacy HTML marker without source and target', async () => {
    mockReadFile.mockResolvedValueOnce(
      '<!-- PromptScript auto-generated file. Do not edit manually. -->\n'
    );

    const result = await detectMarker('/workspace/output.md');

    expect(result).toEqual({
      isGenerated: true,
      source: null,
      target: null,
    });
  });

  // Legacy YAML marker (no source/target)
  it('detects legacy YAML marker without source and target', async () => {
    mockReadFile.mockResolvedValueOnce('# promptscript-generated: true\n');

    const result = await detectMarker('/workspace/CLAUDE.md');

    expect(result).toEqual({
      isGenerated: true,
      source: null,
      target: null,
    });
  });

  // Legacy auto-generated marker
  it('detects legacy auto-generated marker without source and target', async () => {
    mockReadFile.mockResolvedValueOnce('> Auto-generated by PromptScript — do not edit\n');

    const result = await detectMarker('/workspace/instructions.md');

    expect(result).toEqual({
      isGenerated: true,
      source: null,
      target: null,
    });
  });

  // Hand-written file (no marker)
  it('returns isGenerated false for a hand-written file', async () => {
    mockReadFile.mockResolvedValueOnce(
      '# My custom instructions\n\nThis file was written by hand.\n'
    );

    const result = await detectMarker('/workspace/manual.md');

    expect(result).toEqual({
      isGenerated: false,
      source: null,
      target: null,
    });
  });

  // Non-existent file (ENOENT)
  it('returns isGenerated false when file does not exist', async () => {
    const error = Object.assign(new Error('ENOENT: no such file'), { code: 'ENOENT' });
    mockReadFile.mockRejectedValueOnce(error);

    const result = await detectMarker('/workspace/nonexistent.md');

    expect(result).toEqual({
      isGenerated: false,
      source: null,
      target: null,
    });
  });

  // Marker on line 55 (beyond 50-line limit)
  it('returns isGenerated false when marker appears after line 50', async () => {
    const lines = Array.from({ length: 54 }, (_, i) => `line ${i + 1}`);
    lines[54] = '<!-- PromptScript generated | source: foo.prs | target: bar.md -->';
    mockReadFile.mockResolvedValueOnce(lines.join('\n'));

    const result = await detectMarker('/workspace/late-marker.md');

    expect(result).toEqual({
      isGenerated: false,
      source: null,
      target: null,
    });
  });
});
