/**
 * Workspace Service — 工作空间管理
 *
 * 负责：
 * 1. 工作空间目录的创建和验证
 * 2. 4 个必需磁盘文件的加载和自动创建
 * 3. MEMORY.md 格式校验和自动修正
 *
 * @see docs/MetonaAI-Desktop 架构与交互设计.html — 工作空间
 * @see standard/开发规范.md — 使用 fs/path 内置模块（非第三方库）
 */

import { join } from 'path';
import { existsSync, mkdirSync, readFileSync, writeFileSync } from 'fs';
import { app } from 'electron';
import log from 'electron-log';

// ===== 类型定义 =====

export interface WorkspaceFiles {
  soul: string;
  agents: string;
  memory: string;
  users: string;
}

export interface WorkspaceInfo {
  path: string;
  files: WorkspaceFiles;
  isValid: boolean;
  missingFiles: string[];
}

// ===== 常量 =====

const REQUIRED_FILES = ['SOUL.md', 'AGENTS.md', 'MEMORY.md', 'USERS.md'] as const;

const AUTO_CREATED_DIRS = ['logs', 'traces', '.metona'] as const;

const MEMORY_TEMPLATE = `# MEMORY.md — AI 持久记忆
#
# 格式版本: 1.0
# 创建时间: ${new Date().toISOString()}
# 最后更新: ${new Date().toISOString()}
# 工作空间: __WORKSPACE_PATH__
#
# 此文件由 Metona Agent 自动维护，用户可手动编辑。
# 格式规范详见文档，Agent 写入时会自动校验格式。

## 用户偏好
# 格式: - [类别] 内容描述
# 示例: - [沟通风格] 用户喜欢简洁的回答

## 项目上下文
# 格式: - [项目名] 关键信息
# 示例: - [MyApp] 技术栈: React + TypeScript

## 重要决策
# 格式: - YYYY-MM-DD: 决策内容
# 示例: - 2026-06-25: 选择 sql.js 作为数据库方案

## 待办事项
# 格式: - [状态] 任务描述 (状态: pending/done/cancelled)
# 示例: - [pending] 实现用户登录功能

## 已知问题
# 格式: - 问题描述 | 影响范围 | 解决方案
# 示例: - 首次加载慢 | 启动 | 预加载优化
`;

// ===== 服务类 =====

export class WorkspaceService {
  private workspacePath: string;
  private files: WorkspaceFiles = { soul: '', agents: '', memory: '', users: '' };

  constructor(workspacePath?: string) {
    this.workspacePath = workspacePath ?? join(app.getPath('userData'), 'MetonaWorkspaces', 'default');
  }

  /**
   * 初始化工作空间
   *
   * 1. 创建目录结构
   * 2. 验证/创建 4 个必需文件
   * 3. 加载文件内容
   */
  initialize(): WorkspaceInfo {
    log.info(`Initializing workspace: ${this.workspacePath}`);

    // 创建工作空间目录
    this.ensureDirectory(this.workspacePath);

    // 创建自动目录（logs/, traces/, .metona/）
    for (const dir of AUTO_CREATED_DIRS) {
      this.ensureDirectory(join(this.workspacePath, dir));
    }

    // 验证/创建必需文件
    const missingFiles: string[] = [];
    for (const fileName of REQUIRED_FILES) {
      const filePath = join(this.workspacePath, fileName);
      if (!existsSync(filePath)) {
        missingFiles.push(fileName);
        this.createFile(fileName);
      }
    }

    // 加载文件内容
    this.loadFiles();

    // 校验 MEMORY.md 格式
    this.validateMemoryFormat();

    const isValid = missingFiles.length === 0;
    if (missingFiles.length > 0) {
      log.info(`Auto-created missing files: ${missingFiles.join(', ')}`);
    }

    log.info(`Workspace initialized: ${this.workspacePath} (valid: ${isValid})`);

    return {
      path: this.workspacePath,
      files: { ...this.files },
      isValid,
      missingFiles,
    };
  }

  /**
   * 获取工作空间路径
   */
  getPath(): string {
    return this.workspacePath;
  }

  /**
   * 获取文件内容
   */
  getFiles(): WorkspaceFiles {
    return { ...this.files };
  }

  /**
   * 重新加载文件（用户可能在外部编辑）
   */
  reload(): WorkspaceFiles {
    this.loadFiles();
    this.validateMemoryFormat();
    return { ...this.files };
  }

  /**
   * 更新 MEMORY.md 的最后更新时间戳
   */
  updateMemoryTimestamp(): void {
    const memoryPath = join(this.workspacePath, 'MEMORY.md');
    if (!existsSync(memoryPath)) return;

    let content = readFileSync(memoryPath, 'utf-8');
    const now = new Date().toISOString();

    // 替换最后更新时间戳
    content = content.replace(
      /# 最后更新: .*/,
      `# 最后更新: ${now}`,
    );

    writeFileSync(memoryPath, content, 'utf-8');
    this.files.memory = content;
    log.info('MEMORY.md timestamp updated');
  }

  /**
   * 追加记忆到 MEMORY.md
   */
  appendMemory(section: string, entry: string): void {
    const memoryPath = join(this.workspacePath, 'MEMORY.md');
    if (!existsSync(memoryPath)) return;

    let content = readFileSync(memoryPath, 'utf-8');

    // 查找目标 section
    const sectionRegex = new RegExp(`## ${section}\\b`);
    const sectionMatch = content.match(sectionRegex);

    if (sectionMatch) {
      // 在 section 末尾追加
      const sectionIndex = content.indexOf(sectionMatch[0]) + sectionMatch[0].length;
      const nextSectionIndex = content.indexOf('\n## ', sectionIndex);
      const insertPoint = nextSectionIndex === -1 ? content.length : nextSectionIndex;

      const before = content.slice(0, insertPoint).trimEnd();
      const after = content.slice(insertPoint);
      content = `${before}\n- ${entry}\n${after}`;
    } else {
      // section 不存在，追加到文件末尾
      content += `\n## ${section}\n- ${entry}\n`;
    }

    // 更新时间戳
    content = content.replace(
      /# 最后更新: .*/,
      `# 最后更新: ${new Date().toISOString()}`,
    );

    writeFileSync(memoryPath, content, 'utf-8');
    this.files.memory = content;
    log.info(`MEMORY.md: appended to section "${section}"`);
  }

  /**
   * 校验 MEMORY.md 格式（6 条规则）
   *
   * 规则：
   * 1. 元数据头 — 必须包含 # 格式版本、# 创建时间、# 最后更新、# 工作空间
   * 2. 分区结构 — 必须包含 ## 用户偏好、## 项目上下文、## 重要决策
   * 3. 条目前缀 — 每个条目必须以 - 开头，后跟 [类别/标签]
   * 4. 日期格式 — 决策条目必须使用 YYYY-MM-DD
   * 5. 状态标记 — 待办事项必须包含 [pending/done/cancelled]
   * 6. 时间戳更新 — 每次写入时自动更新 # 最后更新 时间戳
   *
   * @see docs/MetonaAI-Desktop 架构与交互设计.html — MEMORY.md 格式校验规则
   */
  validateMemoryFormat(): boolean {
    const memoryPath = join(this.workspacePath, 'MEMORY.md');
    if (!existsSync(memoryPath)) return false;

    let content = readFileSync(memoryPath, 'utf-8');
    let modified = false;

    // 规则 1: 元数据头
    const requiredMeta = ['# 格式版本', '# 创建时间', '# 最后更新', '# 工作空间'];
    for (const meta of requiredMeta) {
      if (!content.includes(meta)) {
        // 自动补充缺失的元数据
        const metaLine = meta === '# 工作空间'
          ? `# 工作空间: ${this.workspacePath}`
          : `${meta}: ${new Date().toISOString()}`;
        content = content.replace(/^# MEMORY/m, `# MEMORY\n#\n# ${metaLine.replace('# ', '')}`);
        modified = true;
        log.info(`MEMORY.md: auto-added missing metadata "${meta}"`);
      }
    }

    // 规则 2: 分区结构
    const requiredSections = ['## 用户偏好', '## 项目上下文', '## 重要决策'];
    for (const section of requiredSections) {
      if (!content.includes(section)) {
        content += `\n${section}\n# 格式: - [类别] 内容描述\n`;
        modified = true;
        log.info(`MEMORY.md: auto-added missing section "${section}"`);
      }
    }

    // 规则 6: 时间戳更新
    const now = new Date().toISOString();
    content = content.replace(/# 最后更新: .*/, `# 最后更新: ${now}`);

    if (modified) {
      writeFileSync(memoryPath, content, 'utf-8');
      this.files.memory = content;
      log.info('MEMORY.md: format validation completed, auto-corrected');
    }

    return !modified;
  }

  // ===== 私有方法 =====

  /**
   * 确保目录存在
   */
  private ensureDirectory(dirPath: string): void {
    if (!existsSync(dirPath)) {
      mkdirSync(dirPath, { recursive: true });
      log.debug(`Created directory: ${dirPath}`);
    }
  }

  /**
   * 创建必需文件
   */
  private createFile(fileName: string): void {
    const filePath = join(this.workspacePath, fileName);

    switch (fileName) {
      case 'MEMORY.md': {
        const content = MEMORY_TEMPLATE.replace('__WORKSPACE_PATH__', this.workspacePath);
        writeFileSync(filePath, content, 'utf-8');
        break;
      }
      case 'SOUL.md':
        writeFileSync(filePath, '# SOUL.md — AI 灵魂定义\n\n# 用户可在此定义 Agent 的身份、性格和核心价值观\n', 'utf-8');
        break;
      case 'AGENTS.md':
        writeFileSync(filePath, '# AGENTS.md — AI 行为定义\n\n# 用户可在此定义 Agent 的行为规则和边界\n', 'utf-8');
        break;
      case 'USERS.md':
        writeFileSync(filePath, '# USERS.md — 用户信息画像\n\n# 用户可在此描述自己的背景、技能和偏好\n', 'utf-8');
        break;
    }

    log.info(`Auto-created file: ${fileName}`);
  }

  /**
   * 加载所有文件内容
   */
  private loadFiles(): void {
    this.files.soul = this.readFile('SOUL.md');
    this.files.agents = this.readFile('AGENTS.md');
    this.files.memory = this.readFile('MEMORY.md');
    this.files.users = this.readFile('USERS.md');
  }

  /**
   * 读取单个文件
   */
  private readFile(fileName: string): string {
    const filePath = join(this.workspacePath, fileName);
    try {
      return readFileSync(filePath, 'utf-8');
    } catch {
      log.warn(`Failed to read file: ${filePath}`);
      return '';
    }
  }
}
