import { describe, it, expect, beforeEach, afterEach } from 'vitest';
import os from 'node:os';
import path from 'node:path';
import { promises as fs } from 'node:fs';
import { getInstanceStateFile, loadInstanceState, saveInstanceState, getAgentInitRoot, } from './instance-state.js';
describe('instance-state service', () => {
    const testAgentId = 'test-agent-123';
    const stateFilePath = getInstanceStateFile(testAgentId);
    beforeEach(async () => {
        // 清理测试文件
        try {
            await fs.rm(path.dirname(stateFilePath), { recursive: true, force: true });
        }
        catch {
            // 目录不存在，忽略
        }
    });
    afterEach(async () => {
        // 清理测试文件
        try {
            await fs.rm(path.dirname(stateFilePath), { recursive: true, force: true });
        }
        catch {
            // 目录不存在，忽略
        }
    });
    describe('getInstanceStateFile', () => {
        it('should return correct path in temp directory', () => {
            const result = getInstanceStateFile(testAgentId);
            const expected = path.join(os.tmpdir(), 'agentswork-runtime-init', testAgentId, 'state.json');
            expect(result).toBe(expected);
        });
        it('should handle agentId with special characters', () => {
            const specialAgentId = 'agent-with-dashes_and_underscores';
            const result = getInstanceStateFile(specialAgentId);
            expect(result).toContain(specialAgentId);
            expect(result).toContain('state.json');
        });
        it('should convert numeric agentId to string', () => {
            const numericId = 12345;
            const result = getInstanceStateFile(numericId);
            expect(result).toContain('12345');
        });
    });
    describe('getAgentInitRoot', () => {
        it('should return correct init root directory', () => {
            const result = getAgentInitRoot(testAgentId);
            const expected = path.join(os.tmpdir(), 'agentswork-runtime-init', testAgentId);
            expect(result).toBe(expected);
        });
    });
    describe('loadInstanceState', () => {
        it('should return default state when file does not exist', async () => {
            const state = await loadInstanceState('non-existent-agent-id');
            expect(state.initialized).toBe(false);
            expect(state.skills).toEqual([]);
            expect(state.mcpServers).toEqual([]);
            expect(state.enabledTools).toEqual(['claude', 'opencode', 'codex']);
            expect(state.toolStatus).toEqual({});
            expect(state.skillEnabled).toBe(true);
            expect(state.mcpEnabled).toBe(true);
            expect(state.updatedAt).toBeNull();
        });
        it('should load existing state from file', async () => {
            // 先保存一个状态
            const savedState = {
                initialized: true,
                skills: [
                    {
                        id: 'skill-1',
                        name: 'test-skill',
                        fileName: 'test.zip',
                        filePath: '/path/to/test.zip',
                        bytes: 1024,
                        installedAt: '2024-01-01T00:00:00Z',
                    },
                ],
                enabledTools: ['claude', 'gemini'],
                skillEnabled: false,
                mcpEnabled: true,
            };
            await saveInstanceState(testAgentId, savedState);
            // 然后加载
            const loadedState = await loadInstanceState(testAgentId);
            expect(loadedState.initialized).toBe(true);
            expect(loadedState.skills).toHaveLength(1);
            expect(loadedState.skills[0].name).toBe('test-skill');
            expect(loadedState.enabledTools).toEqual(['claude', 'gemini']);
            expect(loadedState.skillEnabled).toBe(false);
            expect(loadedState.mcpEnabled).toBe(true);
            expect(loadedState.updatedAt).not.toBeNull();
        });
        it('should handle corrupted JSON file gracefully', async () => {
            // 创建损坏的 JSON 文件
            await fs.mkdir(path.dirname(stateFilePath), { recursive: true });
            await fs.writeFile(stateFilePath, '{ invalid json }', 'utf-8');
            const state = await loadInstanceState(testAgentId);
            // 应该返回默认状态
            expect(state.initialized).toBe(false);
            expect(state.skills).toEqual([]);
        });
    });
    describe('saveInstanceState', () => {
        it('should save complete state with all fields', async () => {
            const partialState = {
                initialized: true,
                skills: [],
                mcpServers: [],
                enabledTools: ['opencode'],
                toolStatus: {
                    claude: {
                        tool: 'claude',
                        installed: true,
                        executable: '/usr/local/bin/claude',
                        version: '1.0.0',
                        installing: false,
                        error: null,
                    },
                },
                skillEnabled: false,
                mcpEnabled: true,
            };
            const result = await saveInstanceState(testAgentId, partialState);
            expect(result.initialized).toBe(true);
            expect(result.enabledTools).toEqual(['opencode']);
            expect(result.toolStatus.claude.installed).toBe(true);
            expect(result.skillEnabled).toBe(false);
            expect(result.mcpEnabled).toBe(true);
            expect(result.updatedAt).not.toBeNull();
            // 验证文件已创建
            const fileContent = await fs.readFile(stateFilePath, 'utf-8');
            const parsed = JSON.parse(fileContent);
            expect(parsed.initialized).toBe(true);
        });
        it('should use default values for missing arrays', async () => {
            const partialState = {
                initialized: true,
            };
            const result = await saveInstanceState(testAgentId, partialState);
            expect(result.skills).toEqual([]);
            expect(result.mcpServers).toEqual([]);
            expect(result.enabledTools).toEqual(['claude', 'opencode', 'codex']);
        });
        it('should handle empty state object', async () => {
            const result = await saveInstanceState(testAgentId, {});
            expect(result.initialized).toBe(false);
            expect(result.skills).toEqual([]);
            expect(result.mcpServers).toEqual([]);
            expect(result.enabledTools).toEqual(['claude', 'opencode', 'codex']);
            expect(result.toolStatus).toEqual({});
            expect(result.skillEnabled).toBe(true);
            expect(result.mcpEnabled).toBe(true);
        });
        it('should handle null/undefined values', async () => {
            const partialState = {
                initialized: undefined,
                skills: null,
                mcpServers: undefined,
                enabledTools: null,
                toolStatus: null,
                skillEnabled: undefined,
                mcpEnabled: null,
            };
            const result = await saveInstanceState(testAgentId, partialState);
            expect(result.initialized).toBe(false);
            expect(result.skills).toEqual([]);
            expect(result.mcpServers).toEqual([]);
            expect(result.enabledTools).toEqual(['claude', 'opencode', 'codex']);
            expect(result.toolStatus).toEqual({});
            expect(result.skillEnabled).toBe(true);
            expect(result.mcpEnabled).toBe(true);
        });
        it('should handle invalid toolStatus type', async () => {
            const partialState = {
                toolStatus: 'invalid',
            };
            const result = await saveInstanceState(testAgentId, partialState);
            expect(result.toolStatus).toEqual({});
        });
        it('should handle array as toolStatus', async () => {
            const partialState = {
                toolStatus: [],
            };
            const result = await saveInstanceState(testAgentId, partialState);
            expect(result.toolStatus).toEqual({});
        });
        it('should deduplicate and normalize enabledTools', async () => {
            const partialState = {
                enabledTools: ['CLAUDE', 'claude', 'OpenCode', '  gemini  ', ''],
            };
            const result = await saveInstanceState(testAgentId, partialState);
            expect(result.enabledTools).toEqual(['claude', 'opencode', 'gemini']);
        });
        it('should overwrite existing state', async () => {
            // 第一次保存
            await saveInstanceState(testAgentId, { initialized: true });
            // 第二次保存
            const result = await saveInstanceState(testAgentId, { initialized: false });
            expect(result.initialized).toBe(false);
            // 验证文件内容
            const fileContent = await fs.readFile(stateFilePath, 'utf-8');
            const parsed = JSON.parse(fileContent);
            expect(parsed.initialized).toBe(false);
        });
        it('should update updatedAt timestamp on each save', async () => {
            const first = await saveInstanceState(testAgentId, { initialized: true });
            // 等待一小段时间确保时间戳不同
            await new Promise((resolve) => setTimeout(resolve, 10));
            const second = await saveInstanceState(testAgentId, { initialized: false });
            expect(second.updatedAt).not.toBe(first.updatedAt);
        });
    });
});
