/**
 * Server 端权限处理器
 * 通过 WebSocket 发送权限请求并等待客户端响应
 */

import { randomUUID } from 'crypto';
import { broadcastToSession } from '../ws.js';
import type {
  PermissionType,
  PermissionRequestPayload,
  PermissionRequestContext,
  ServerMessage,
} from '../types.js';

/**
 * 权限决策结果
 */
export interface PermissionDecision {
  allow: boolean;
  remember?: boolean;
}

/**
 * 权限上下文（来自 core 模块）
 */
export interface PermissionContext {
  command: string;
  workdir: string;
  patterns?: string[];
  externalPaths?: string[];
}

// 等待中的权限请求
interface PendingRequest {
  resolve: (decision: PermissionDecision) => void;
  reject: (error: Error) => void;
  timeout: ReturnType<typeof setTimeout>;
}

const pendingRequests = new Map<string, PendingRequest>();

// 会话级别的 auto-approve 配置
// key: sessionId, value: auto-approve 配置
const sessionAutoApprove = new Map<string, { file?: { write?: 'allow'; edit?: 'allow' } }>();

// 默认超时时间（60秒）
const PERMISSION_TIMEOUT = 60000;

/**
 * 设置会话的 auto-approve 配置
 */
export function setSessionAutoApprove(
  sessionId: string,
  config: { file?: { write?: 'allow'; edit?: 'allow' } } | null
): void {
  if (config) {
    sessionAutoApprove.set(sessionId, config);
  } else {
    sessionAutoApprove.delete(sessionId);
  }
}

/**
 * 获取会话的 auto-approve 配置
 */
export function getSessionAutoApprove(sessionId: string): { file?: { write?: 'allow'; edit?: 'allow' } } | null {
  return sessionAutoApprove.get(sessionId) ?? null;
}

/**
 * 检查操作是否被 auto-approve
 */
function isAutoApproved(sessionId: string, ctx: PermissionContext): boolean {
  const config = sessionAutoApprove.get(sessionId);
  if (!config) return false;

  const command = ctx.command.toLowerCase();

  // 检查是否为文件写入操作
  if (command.startsWith('write ') && config.file?.write === 'allow') {
    return true;
  }

  // 检查是否为文件编辑操作
  if (command.startsWith('edit ') && config.file?.edit === 'allow') {
    return true;
  }

  return false;
}

/**
 * 从命令或上下文检测权限类型
 */
function detectPermissionType(ctx: PermissionContext): PermissionType {
  const command = ctx.command.toLowerCase();

  // 检测 git 操作
  if (command.startsWith('git ')) {
    return 'git';
  }

  // 检测文件操作
  const fileOps = ['read', 'write', 'edit', 'delete', 'move', 'copy', 'mkdir'];
  for (const op of fileOps) {
    if (command.startsWith(`${op} `)) {
      return 'file';
    }
  }

  // 检测 web 操作
  if (command.includes('fetch') || command.includes('http')) {
    return 'web';
  }

  // 默认为 bash
  return 'bash';
}

/**
 * 构建权限请求上下文
 */
function buildRequestContext(ctx: PermissionContext): PermissionRequestContext {
  const permType = detectPermissionType(ctx);

  switch (permType) {
    case 'file': {
      const parts = ctx.command.split(' ');
      const operation = parts[0];
      const path = parts.slice(1).join(' ');
      return {
        operation,
        path,
        patterns: ctx.patterns,
        externalPaths: ctx.externalPaths,
      };
    }
    case 'git': {
      const gitOp = ctx.command.replace(/^git\s+/, '').split(' ')[0];
      return {
        command: ctx.command,
        gitOperation: gitOp,
      };
    }
    case 'web': {
      return {
        command: ctx.command,
        query: ctx.command,
      };
    }
    default:
      return {
        command: ctx.command,
        patterns: ctx.patterns,
        externalPaths: ctx.externalPaths,
      };
  }
}

/**
 * 创建 Server 端权限回调函数
 * 用于在 Agent 创建时设置
 */
export function createServerPermissionCallback(sessionId: string) {
  return async (ctx: unknown): Promise<PermissionDecision> => {
    const permCtx = ctx as PermissionContext;

    // 检查 auto-approve 配置
    if (isAutoApproved(sessionId, permCtx)) {
      console.log(`[Permission] Auto-approved: ${permCtx.command}`);
      return { allow: true, remember: false };
    }

    const requestId = randomUUID();
    const permissionType = detectPermissionType(permCtx);
    const context = buildRequestContext(permCtx);

    // 构建请求 payload
    const payload: PermissionRequestPayload = {
      requestId,
      permissionType,
      context,
    };

    // 发送权限请求到客户端
    const message: ServerMessage = {
      type: 'permission_request',
      sessionId,
      payload,
    };

    broadcastToSession(sessionId, message);

    // 等待响应（带超时）
    return new Promise((resolve, reject) => {
      const timeout = setTimeout(() => {
        pendingRequests.delete(requestId);
        // 超时默认拒绝
        resolve({ allow: false, remember: false });
      }, PERMISSION_TIMEOUT);

      pendingRequests.set(requestId, { resolve, reject, timeout });
    });
  };
}

/**
 * 处理权限响应
 * 由 WebSocket 消息处理器调用
 */
export function handlePermissionResponse(
  requestId: string,
  allow: boolean,
  remember?: boolean
): boolean {
  const pending = pendingRequests.get(requestId);

  if (!pending) {
    console.warn(`[Permission] No pending request found for: ${requestId}`);
    return false;
  }

  clearTimeout(pending.timeout);
  pendingRequests.delete(requestId);
  pending.resolve({ allow, remember });

  return true;
}

/**
 * 取消会话的所有待处理权限请求
 * 用于会话断开时清理
 */
export function cancelPendingRequests(sessionId: string): void {
  // 由于我们没有存储 sessionId -> requestId 的映射，
  // 这个函数目前只是一个占位符
  // 在实际使用中，如果需要按会话取消请求，需要维护额外的映射
  console.log(`[Permission] Cancelling pending requests for session: ${sessionId}`);
}

/**
 * 获取待处理请求数量（用于调试）
 */
export function getPendingRequestCount(): number {
  return pendingRequests.size;
}
