/**
 * Git 管理器
 *
 * 整合 GitRepo、AutoCommitManager、MessageGenerator、UndoManager
 * 提供统一的 Git 集成接口
 */

import type {
  GitConfig,
  GitStatus,
  CommitResult,
  UndoResult,
  UndoEntry,
  DiffResult,
  CommitInfo,
  GitEvent,
  GitEventListener,
} from './types.js';
import { DEFAULT_GIT_CONFIG } from './types.js';
import { GitRepo } from './repo.js';
import { AutoCommitManager } from './auto-commit.js';
import { MessageGenerator } from './message-generator.js';
import { UndoManager } from './undo-manager.js';

export class GitManager {
  private repo: GitRepo;
  private autoCommit: AutoCommitManager;
  private messageGenerator: MessageGenerator;
  private undoManager: UndoManager;
  private config: GitConfig;
  private workdir: string;

  /** 事件监听器 */
  private eventListeners: GitEventListener[] = [];

  /** 是否已初始化 */
  private initialized: boolean = false;

  constructor(workdir: string, config?: Partial<GitConfig>) {
    this.workdir = workdir;
    this.config = { ...DEFAULT_GIT_CONFIG, ...config };

    // 创建组件
    this.repo = new GitRepo(workdir, this.config);
    this.messageGenerator = new MessageGenerator(this.config.messageFormat);
    this.autoCommit = new AutoCommitManager(
      this.repo,
      this.config.autoCommit,
      this.messageGenerator
    );
    this.undoManager = new UndoManager(this.repo, this.config.undo);

    // 设置自动提交回调
    this.autoCommit.setOnCommit((result) => {
      if (result.success && result.shortHash && result.message) {
        // 记录到 undo 历史
        const files = this.autoCommit.getPendingFiles();
        this.undoManager.recordCommit(
          result.hash!,
          result.shortHash,
          result.message,
          files
        );

        // 发送事件
        this.emitEvent('commit', {
          hash: result.shortHash,
          message: result.message,
          auto: true,
        });
      }
    });
  }

  /**
   * 初始化 Git 管理器
   */
  async initialize(): Promise<boolean> {
    if (!this.config.enabled) {
      return false;
    }

    const isRepo = await this.repo.initialize();
    this.initialized = isRepo;
    return isRepo;
  }

  /**
   * 检查是否已初始化
   */
  isInitialized(): boolean {
    return this.initialized;
  }

  /**
   * 获取仓库状态
   */
  async getStatus(): Promise<GitStatus> {
    return this.repo.getStatus();
  }

  /**
   * 文件变更后调用（由工具执行器调用）
   */
  async onFileChanged(
    filePath: string,
    changeType: 'create' | 'modify' | 'delete'
  ): Promise<void> {
    if (!this.initialized || !this.config.enabled) {
      return;
    }

    await this.autoCommit.onFileChanged(filePath, changeType);
  }

  /**
   * 手动提交
   */
  async commit(options: {
    message?: string;
    files?: string[];
    all?: boolean;
  } = {}): Promise<CommitResult> {
    if (!this.initialized) {
      return { success: false, error: 'Git not initialized' };
    }

    // 如果有待提交的文件，先处理
    if (this.autoCommit.hasPendingFiles()) {
      await this.autoCommit.flush();
    }

    // 获取差异用于生成消息
    const diff = await this.repo.getDiff({ staged: options.all });
    const message = options.message || this.messageGenerator.generate(diff);

    const result = await this.repo.commit({
      message,
      files: options.files,
      all: options.all,
      aiEdits: true,
    });

    if (result.success && result.shortHash && result.message) {
      // 记录到 undo 历史
      const files = options.files || [];
      this.undoManager.recordCommit(
        result.hash!,
        result.shortHash,
        result.message,
        files
      );

      // 发送事件
      this.emitEvent('commit', {
        hash: result.shortHash,
        message: result.message,
        auto: false,
      });
    }

    return result;
  }

  /**
   * 撤销上一次 AI 提交
   */
  async undo(): Promise<UndoResult> {
    if (!this.initialized) {
      return { success: false, message: 'Git not initialized' };
    }

    const result = await this.undoManager.undo();

    if (result.success) {
      this.emitEvent('undo', {
        hash: result.commitHash,
        files: result.restoredFiles,
      });
    }

    return result;
  }

  /**
   * 获取 undo 预览
   */
  getUndoPreview(): UndoEntry | null {
    return this.undoManager.getUndoPreview();
  }

  /**
   * 获取 undo 历史
   */
  getUndoHistory(): UndoEntry[] {
    return this.undoManager.getHistory();
  }

  /**
   * 检查是否可以 undo
   */
  async canUndo(): Promise<{ canUndo: boolean; reason?: string }> {
    return this.undoManager.canUndo();
  }

  /**
   * 获取差异
   */
  async getDiff(options: {
    staged?: boolean;
    file?: string;
    commit?: string;
  } = {}): Promise<DiffResult> {
    return this.repo.getDiff(options);
  }

  /**
   * 获取最近的提交
   */
  async getRecentCommits(count: number = 10): Promise<CommitInfo[]> {
    return this.repo.getRecentCommits(count);
  }

  /**
   * 获取当前分支
   */
  async getCurrentBranch(): Promise<string> {
    return this.repo.getCurrentBranch();
  }

  /**
   * 强制刷新待提交
   */
  async flushPendingCommits(): Promise<CommitResult | null> {
    return this.autoCommit.flush();
  }

  /**
   * 获取待提交文件
   */
  getPendingFiles(): string[] {
    return this.autoCommit.getPendingFiles();
  }

  /**
   * 添加事件监听器
   */
  addEventListener(listener: GitEventListener): void {
    this.eventListeners.push(listener);
  }

  /**
   * 移除事件监听器
   */
  removeEventListener(listener: GitEventListener): void {
    const index = this.eventListeners.indexOf(listener);
    if (index !== -1) {
      this.eventListeners.splice(index, 1);
    }
  }

  /**
   * 发送事件
   */
  private emitEvent(type: GitEvent['type'], data: unknown): void {
    const event: GitEvent = {
      type,
      timestamp: Date.now(),
      data,
    };

    for (const listener of this.eventListeners) {
      try {
        listener(event);
      } catch (error) {
        console.error('Git event listener error:', error);
      }
    }
  }

  /**
   * 获取配置
   */
  getConfig(): GitConfig {
    return { ...this.config };
  }

  /**
   * 更新配置
   */
  updateConfig(config: Partial<GitConfig>): void {
    this.config = { ...this.config, ...config };
  }
}

// 全局 Git 管理器实例
let gitManager: GitManager | null = null;

/**
 * 获取全局 Git 管理器
 */
export function getGitManager(): GitManager | null {
  return gitManager;
}

/**
 * 初始化全局 Git 管理器
 */
export async function initGitManager(
  workdir: string,
  config?: Partial<GitConfig>
): Promise<GitManager | null> {
  gitManager = new GitManager(workdir, config);
  const initialized = await gitManager.initialize();

  if (!initialized) {
    gitManager = null;
    return null;
  }

  return gitManager;
}

/**
 * 重置全局 Git 管理器
 */
export function resetGitManager(): void {
  gitManager = null;
}
