import { Agent, fetch as undiciFetch } from 'undici';
import { buildPageEditAgentPolicy } from './capabilities.mjs';
import { buildPageEditSubAgentInstructions } from './mindspace-chat-context.mjs';
import { buildMindSpacePageSaveInstructions } from './mindspace-page-patch.mjs';
import { reconcileAgentSession } from './session-reconcile.mjs';

const insecureDispatcher = new Agent({
  connect: { rejectUnauthorized: false },
});

function isHttpsTarget(target) {
  return target.startsWith('https://');
}

function createApiFetch(apiTarget, apiSecret) {
  return async (pathname, init = {}) => {
    const url = new URL(pathname, apiTarget);
    const headers = {
      ...(init.headers ?? {}),
      'X-Secret-Key': apiSecret,
    };
    if (init.body && !headers['Content-Type']) {
      headers['Content-Type'] = 'application/json';
    }
    return undiciFetch(url, {
      ...init,
      headers,
      dispatcher: isHttpsTarget(apiTarget) ? insecureDispatcher : undefined,
    });
  };
}

async function readJson(upstream) {
  const text = await upstream.text();
  if (!upstream.ok) {
    throw Object.assign(new Error(text || `upstream ${upstream.status}`), {
      code: 'worker_unavailable',
    });
  }
  return text ? JSON.parse(text) : null;
}

function buildPageEditSeedContent({ page, parentSessionId, h5ApiBase, sessionId }) {
  const context = {
    spaceId: 'mindspace',
    spaceName: 'MindSpace',
    view: 'page',
    route: `/mindspace/page/${page.id}/preview`,
    pageEditMode: true,
    parentAgentSessionId: parentSessionId,
    agentSessionId: sessionId,
    h5ApiBase,
    page: {
      id: page.id,
      title: page.title,
      summary: page.summary ?? '',
      status: page.status,
      versionNo: page.versionNo,
      templateId: page.templateId,
      contentFormat: page.contentFormat ?? 'html',
    },
  };

  const lines = [
    ...buildPageEditSubAgentInstructions(context).split('\n'),
    '[MindSpace 页面编辑子会话]',
    `- 页面：${page.title}（id: ${page.id}）`,
    `- 内容格式：${page.contentFormat ?? 'html'}`,
    `- 当前版本：v${page.versionNo ?? 1}`,
    ...buildMindSpacePageSaveInstructions(
      {
        id: page.id,
        contentFormat: page.contentFormat ?? 'html',
      },
      { sessionId, h5ApiBase },
    ),
    '请用一句话确认你已准备好修改此页面，并等待用户指令。',
  ];
  return lines.join('\n');
}

export function buildPageEditSessionConstraints(pageTitle) {
  return [
    '【页面编辑子 Agent 沙箱】',
    `- 当前任务：仅修改 MindSpace 页面「${pageTitle}」`,
    '- 禁止读写工作区其它文件；禁止 delegate / load_skill / 发布新页面',
    '- 改页面优先 curl 调用 mindspace_page_patch；若无 shell 权限则在回复末尾输出 ```mindspace-page-update``` 块',
    '- 每次改动后立即触发预览更新，不要只口头说「已修改」',
  ].join('\n');
}

export function createPageEditSessionService({
  apiTarget,
  apiSecret,
  userAuth,
  pageService,
  pageLiveEdit,
  llmProviderService,
}) {
  const apiFetch = createApiFetch(apiTarget, apiSecret);

  const applySessionLlmProvider = async (sessionId) => {
    if (!llmProviderService || !sessionId) return null;
    try {
      return await llmProviderService.applyBestProviderForSession(sessionId);
    } catch {
      return null;
    }
  };

  return {
    async forkSession({ userId, pageId, parentSessionId, h5ApiBase = null }) {
      if (!userId || !pageId || !parentSessionId) {
        throw Object.assign(new Error('缺少 fork 参数'), { code: 'invalid_request' });
      }

      const ownsParent = await userAuth.ownsSession(userId, parentSessionId);
      if (!ownsParent) {
        throw Object.assign(new Error('无权使用父会话'), { code: 'forbidden' });
      }

      const page = await pageService.getPage(userId, pageId);
      if (page.contentFormat !== 'html') {
        throw Object.assign(new Error('仅 HTML 页面支持编辑子会话'), { code: 'invalid_request' });
      }

      const gate = await userAuth.canUseChat(userId);
      if (!gate.ok) {
        throw Object.assign(new Error(gate.message || '当前用户无法使用 Agent'), { code: 'forbidden' });
      }

      const workingDir = await userAuth.resolveWorkingDir(userId);
      const basePolicy = await userAuth.getAgentSessionPolicy(userId);
      const sessionPolicy = buildPageEditAgentPolicy(basePolicy);
      const publishLayout = await userAuth.getUserPublishLayout(userId);

      const startSession = await readJson(
        await apiFetch('/agent/start', {
          method: 'POST',
          body: JSON.stringify({
            working_dir: workingDir,
            enable_context_memory: sessionPolicy.enableContextMemory,
            ...(sessionPolicy.extensionOverrides
              ? { extension_overrides: sessionPolicy.extensionOverrides }
              : {}),
          }),
        }),
      );

      const sessionId = startSession?.id;
      if (!sessionId) {
        throw Object.assign(new Error('Agent 会话启动失败'), { code: 'worker_unavailable' });
      }

      await userAuth.registerAgentSession(userId, sessionId);

      if (sessionPolicy.gooseMode) {
        await readJson(
          await apiFetch('/agent/update_session', {
            method: 'POST',
            body: JSON.stringify({
              session_id: sessionId,
              goose_mode: sessionPolicy.gooseMode,
            }),
          }),
        );
      }

      const sandboxConstraints = [
        publishLayout?.constraints ?? '',
        buildPageEditSessionConstraints(page.title),
      ]
        .filter(Boolean)
        .join('\n\n');

      await reconcileAgentSession(apiFetch, sessionId, {
        workingDir,
        sessionPolicy,
        sandboxConstraints,
        userContext: publishLayout
          ? {
              userId,
              displayName: publishLayout.displayName,
              username: publishLayout.username,
              slug: publishLayout.slug,
            }
          : null,
      });

      await applySessionLlmProvider(sessionId);

      await pageLiveEdit.bindSession({
        userId,
        sessionId,
        pageId,
        parentSessionId,
      });

      const seed = buildPageEditSeedContent({
        page,
        parentSessionId,
        h5ApiBase,
        sessionId,
      });

      await apiFetch('/agent/harness_remember', {
        method: 'POST',
        body: JSON.stringify({
          sessionId,
          title: `页面编辑 · ${page.title}`,
          content: seed,
        }),
      });

      await apiFetch('/agent/harness_bootstrap', {
        method: 'POST',
        body: JSON.stringify({ sessionId, force: true }),
      });

      return {
        sessionId,
        pageId,
        parentSessionId,
      };
    },

    async closeSession({ userId, sessionId, pageId, parentSessionId, summary = '' }) {
      if (!userId || !sessionId || !pageId) {
        throw Object.assign(new Error('缺少 close 参数'), { code: 'invalid_request' });
      }

      const owns = await userAuth.ownsSession(userId, sessionId);
      if (!owns) {
        throw Object.assign(new Error('无权关闭该子会话'), { code: 'forbidden' });
      }

      const binding = pageLiveEdit.getBinding(sessionId);
      if (binding && binding.pageId !== String(pageId)) {
        throw Object.assign(new Error('子会话未绑定该页面'), { code: 'page_binding_mismatch' });
      }

      pageLiveEdit.unbindSession(sessionId);

      const trimmedSummary = String(summary ?? '').trim();
      const parentId = String(parentSessionId ?? binding?.parentSessionId ?? '').trim();
      if (trimmedSummary && parentId) {
        const ownsParent = await userAuth.ownsSession(userId, parentId);
        if (ownsParent) {
          const page = await pageService.getPage(userId, pageId).catch(() => null);
          await apiFetch('/agent/harness_remember', {
            method: 'POST',
            body: JSON.stringify({
              sessionId: parentId,
              title: `页面编辑摘要 · ${page?.title ?? pageId}`,
              content: trimmedSummary,
            }),
          });
        }
      }

      return { sessionId, pageId, merged: Boolean(trimmedSummary && parentId) };
    },
  };
}

export const pageEditSessionInternals = {
  buildPageEditSeedContent,
  buildPageEditSessionConstraints,
};
