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

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

describe('add-image-vision 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-image-vision');
      expect(content).toContain('version: 1.1.0');
    });

    it('declares sharp as npm dependency', () => {
      expect(content).toContain('sharp:');
      expect(content).toMatch(/sharp:\s*"\^0\.34/);
    });

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

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

    it('lists all modify files', () => {
      expect(content).toContain('src/channels/whatsapp.ts');
      expect(content).toContain('src/channels/whatsapp.test.ts');
      expect(content).toContain('src/container-runner.ts');
      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/image.ts with required exports', () => {
      const filePath = path.join(SKILL_DIR, 'add', 'src', 'image.ts');
      expect(fs.existsSync(filePath)).toBe(true);

      const content = fs.readFileSync(filePath, 'utf-8');
      expect(content).toContain('export function isImageMessage');
      expect(content).toContain('export async function processImage');
      expect(content).toContain('export function parseImageReferences');
      expect(content).toContain('export interface ProcessedImage');
      expect(content).toContain('export interface ImageAttachment');
      expect(content).toContain("import sharp from 'sharp'");
    });

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

      const content = fs.readFileSync(filePath, 'utf-8');
      expect(content).toContain('isImageMessage');
      expect(content).toContain('processImage');
      expect(content).toContain('parseImageReferences');
    });
  });

  describe('modify/ files exist', () => {
    const modifyFiles = [
      'src/channels/whatsapp.ts',
      'src/channels/whatsapp.test.ts',
      'src/container-runner.ts',
      '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/channels/whatsapp.ts.intent.md',
      'src/channels/whatsapp.test.ts.intent.md',
      'src/container-runner.ts.intent.md',
      '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/channels/whatsapp.ts', () => {
    let content: string;

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

    it('imports image utilities', () => {
      expect(content).toContain("from '../image.js'");
      expect(content).toContain('processImage');
    });

    it('imports downloadMediaMessage', () => {
      expect(content).toContain('downloadMediaMessage');
      expect(content).toContain("from '@whiskeysockets/baileys'");
    });

    it('imports GROUPS_DIR from config', () => {
      expect(content).toContain('GROUPS_DIR');
    });

    it('uses let content for mutable assignment', () => {
      expect(content).toMatch(/let content\s*=/);
    });

    it('includes image processing block', () => {
      expect(content).toContain('processImage(buffer');
      expect(content).toContain('Image - download failed');
    });

    it('preserves core WhatsAppChannel structure', () => {
      expect(content).toContain('export class WhatsAppChannel implements Channel');
      expect(content).toContain('async connect()');
      expect(content).toContain('async sendMessage(');
      expect(content).toContain('async syncGroupMetadata(');
      expect(content).toContain('private async translateJid(');
      expect(content).toContain('private async flushOutgoingQueue(');
    });
  });

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

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

    it('mocks image.js module', () => {
      expect(content).toContain("vi.mock('../image.js'");
      expect(content).toContain('isImageMessage');
      expect(content).toContain('processImage');
    });

    it('mocks downloadMediaMessage', () => {
      expect(content).toContain('downloadMediaMessage');
    });

    it('includes image test cases', () => {
      expect(content).toContain('downloads and processes image attachments');
      expect(content).toContain('handles image without caption');
      expect(content).toContain('handles image download failure gracefully');
      expect(content).toContain('falls back to caption when processImage returns null');
    });

    it('preserves all existing test sections', () => {
      expect(content).toContain('connection lifecycle');
      expect(content).toContain('authentication');
      expect(content).toContain('reconnection');
      expect(content).toContain('message handling');
      expect(content).toContain('LID to JID translation');
      expect(content).toContain('outgoing message queue');
      expect(content).toContain('group metadata sync');
      expect(content).toContain('ownsJid');
      expect(content).toContain('setTyping');
      expect(content).toContain('channel properties');
    });

    it('includes all media handling test sections', () => {
      // Image tests present (core skill feature)
      expect(content).toContain('downloads and processes image attachments');
      expect(content).toContain('handles image without caption');
    });
  });

  describe('modify/src/container-runner.ts', () => {
    it('adds imageAttachments to ContainerInput', () => {
      const content = fs.readFileSync(
        path.join(SKILL_DIR, 'modify', 'src', 'container-runner.ts'),
        'utf-8',
      );
      expect(content).toContain('imageAttachments?');
      expect(content).toContain('relativePath: string');
      expect(content).toContain('mediaType: string');
    });

    it('preserves core container-runner structure', () => {
      const content = fs.readFileSync(
        path.join(SKILL_DIR, 'modify', 'src', 'container-runner.ts'),
        'utf-8',
      );
      expect(content).toContain('export async function runContainerAgent');
      expect(content).toContain('ContainerInput');
    });
  });

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

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

    it('imports parseImageReferences', () => {
      expect(content).toContain("import { parseImageReferences } from './image.js'");
    });

    it('calls parseImageReferences in processGroupMessages', () => {
      expect(content).toContain('parseImageReferences(missedMessages)');
    });

    it('passes imageAttachments to runAgent', () => {
      expect(content).toContain('imageAttachments');
      expect(content).toMatch(/runAgent\(group,\s*prompt,\s*chatJid,\s*imageAttachments/);
    });

    it('spreads imageAttachments into container input', () => {
      expect(content).toContain('...(imageAttachments.length > 0 && { imageAttachments })');
    });

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

  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 ContentBlock types', () => {
      expect(content).toContain('interface ImageContentBlock');
      expect(content).toContain('interface TextContentBlock');
      expect(content).toContain('type ContentBlock = ImageContentBlock | TextContentBlock');
    });

    it('adds imageAttachments to ContainerInput', () => {
      expect(content).toContain('imageAttachments?');
    });

    it('adds pushMultimodal to MessageStream', () => {
      expect(content).toContain('pushMultimodal(content: ContentBlock[])');
    });

    it('includes image loading logic in runQuery', () => {
      expect(content).toContain('containerInput.imageAttachments');
      expect(content).toContain("path.join('/workspace/group', img.relativePath)");
      expect(content).toContain("toString('base64')");
      expect(content).toContain('stream.pushMultimodal(blocks)');
    });

    it('preserves core 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');
    });

    it('preserves core agent-runner exports', () => {
      expect(content).toContain('async function main');
      expect(content).toContain('function writeOutput');
    });
  });
});
