import { describe, it, expect, beforeAll } from 'vitest';
import fs from 'fs';
import path from 'path';

const SKILL_DIR = path.resolve(__dirname, '..');

describe('add-compact skill package', () => {
  describe('manifest', () => {
    let content: string;

    beforeAll(() => {
      content = fs.readFileSync(path.join(SKILL_DIR, 'manifest.yaml'), 'utf-8');
    });

    it('has a valid manifest.yaml', () => {
      expect(fs.existsSync(path.join(SKILL_DIR, 'manifest.yaml'))).toBe(true);
      expect(content).toContain('skill: add-compact');
      expect(content).toContain('version: 1.0.0');
    });

    it('has no npm dependencies', () => {
      expect(content).toContain('npm_dependencies: {}');
    });

    it('has no env_additions', () => {
      expect(content).toContain('env_additions: []');
    });

    it('lists all add files', () => {
      expect(content).toContain('src/session-commands.ts');
      expect(content).toContain('src/session-commands.test.ts');
    });

    it('lists all modify files', () => {
      expect(content).toContain('src/index.ts');
      expect(content).toContain('container/agent-runner/src/index.ts');
    });

    it('has no dependencies', () => {
      expect(content).toContain('depends: []');
    });
  });

  describe('add/ files', () => {
    it('includes src/session-commands.ts with required exports', () => {
      const filePath = path.join(SKILL_DIR, 'add', 'src', 'session-commands.ts');
      expect(fs.existsSync(filePath)).toBe(true);

      const content = fs.readFileSync(filePath, 'utf-8');
      expect(content).toContain('export function extractSessionCommand');
      expect(content).toContain('export function isSessionCommandAllowed');
      expect(content).toContain('export async function handleSessionCommand');
      expect(content).toContain("'/compact'");
    });

    it('includes src/session-commands.test.ts with test cases', () => {
      const filePath = path.join(SKILL_DIR, 'add', 'src', 'session-commands.test.ts');
      expect(fs.existsSync(filePath)).toBe(true);

      const content = fs.readFileSync(filePath, 'utf-8');
      expect(content).toContain('extractSessionCommand');
      expect(content).toContain('isSessionCommandAllowed');
      expect(content).toContain('detects bare /compact');
      expect(content).toContain('denies untrusted sender');
    });
  });

  describe('modify/ files exist', () => {
    const modifyFiles = [
      'src/index.ts',
      'container/agent-runner/src/index.ts',
    ];

    for (const file of modifyFiles) {
      it(`includes modify/${file}`, () => {
        const filePath = path.join(SKILL_DIR, 'modify', file);
        expect(fs.existsSync(filePath)).toBe(true);
      });
    }
  });

  describe('intent files exist', () => {
    const intentFiles = [
      'src/index.ts.intent.md',
      'container/agent-runner/src/index.ts.intent.md',
    ];

    for (const file of intentFiles) {
      it(`includes modify/${file}`, () => {
        const filePath = path.join(SKILL_DIR, 'modify', file);
        expect(fs.existsSync(filePath)).toBe(true);
      });
    }
  });

  describe('modify/src/index.ts', () => {
    let content: string;

    beforeAll(() => {
      content = fs.readFileSync(
        path.join(SKILL_DIR, 'modify', 'src', 'index.ts'),
        'utf-8',
      );
    });

    it('imports session command helpers', () => {
      expect(content).toContain("import { extractSessionCommand, handleSessionCommand, isSessionCommandAllowed } from './session-commands.js'");
    });

    it('uses const for missedMessages', () => {
      expect(content).toMatch(/const missedMessages = getMessagesSince/);
    });

    it('delegates to handleSessionCommand in processGroupMessages', () => {
      expect(content).toContain('Session command interception (before trigger check)');
      expect(content).toContain('handleSessionCommand(');
      expect(content).toContain('cmdResult.handled');
      expect(content).toContain('cmdResult.success');
    });

    it('passes deps to handleSessionCommand', () => {
      expect(content).toContain('sendMessage:');
      expect(content).toContain('setTyping:');
      expect(content).toContain('runAgent:');
      expect(content).toContain('closeStdin:');
      expect(content).toContain('advanceCursor:');
      expect(content).toContain('formatMessages');
      expect(content).toContain('canSenderInteract:');
    });

    it('has session command interception in startMessageLoop', () => {
      expect(content).toContain('Session command interception (message loop)');
      expect(content).toContain('queue.enqueueMessageCheck(chatJid)');
    });

    it('preserves core index.ts structure', () => {
      expect(content).toContain('processGroupMessages');
      expect(content).toContain('startMessageLoop');
      expect(content).toContain('async function main()');
      expect(content).toContain('recoverPendingMessages');
      expect(content).toContain('ensureContainerSystemRunning');
    });
  });

  describe('modify/container/agent-runner/src/index.ts', () => {
    let content: string;

    beforeAll(() => {
      content = fs.readFileSync(
        path.join(SKILL_DIR, 'modify', 'container', 'agent-runner', 'src', 'index.ts'),
        'utf-8',
      );
    });

    it('defines KNOWN_SESSION_COMMANDS whitelist', () => {
      expect(content).toContain("KNOWN_SESSION_COMMANDS");
      expect(content).toContain("'/compact'");
    });

    it('uses query() with string prompt for slash commands', () => {
      expect(content).toContain('prompt: trimmedPrompt');
      expect(content).toContain('allowedTools: []');
    });

    it('observes compact_boundary system event', () => {
      expect(content).toContain('compactBoundarySeen');
      expect(content).toContain("'compact_boundary'");
      expect(content).toContain('Compact boundary observed');
    });

    it('handles error subtypes', () => {
      expect(content).toContain("resultSubtype?.startsWith('error')");
    });

    it('registers PreCompact hook for slash commands', () => {
      expect(content).toContain('createPreCompactHook(containerInput.assistantName)');
    });

    it('preserves core agent-runner structure', () => {
      expect(content).toContain('async function runQuery');
      expect(content).toContain('class MessageStream');
      expect(content).toContain('function writeOutput');
      expect(content).toContain('function createPreCompactHook');
      expect(content).toContain('function createSanitizeBashHook');
      expect(content).toContain('async function main');
    });
  });
});
