#!/usr/bin/env node
'use strict';

const fs = require('fs');

const ROUTES = {
  2: {
    brand: '长安',
    subAgentKey: 'changan_new_car_audit',
    description: '长安新车审核子Agent',
    agentId: 6,
    agentName: 'agent_c020c385',
  },
  11: {
    brand: '赛力斯',
    subAgentKey: 'seres_new_car_audit',
    description: '赛力斯审核子Agent',
    agentId: 9,
    agentName: 'agent_6a442e52',
  },
  16: {
    brand: '阿维塔',
    subAgentKey: 'avatr_new_car_audit',
    description: '阿维塔审核子Agent',
    agentId: 10,
    agentName: 'agent_7d380038',
  },
};

function emit(stage, message, status = 'running', extra = {}) {
  process.stderr.write(JSON.stringify({
    type: 'process_event',
    stage,
    message,
    status,
    timestamp: new Date().toISOString(),
    ...extra,
  }) + '\n');
}

function readInput() {
  const raw = String(process.argv[2] || process.env.SKILL_INPUT || process.env.AIFLOW_SKILL_INPUT || fs.readFileSync(0, 'utf8')).trim();
  return raw ? JSON.parse(raw) : {};
}

function boolValue(value, fallback) {
  if (value === undefined || value === null || value === '') return fallback;
  if (typeof value === 'boolean') return value;
  if (typeof value === 'number') return value !== 0;
  return ['1', 'true', 'yes', 'y', 'on'].includes(String(value).toLowerCase());
}

function parseMessage(message) {
  if (message === undefined || message === null || message === '') return {};
  if (typeof message === 'string') {
    try {
      return JSON.parse(message);
    } catch {
      return { text: message };
    }
  }
  if (typeof message === 'object' && !Array.isArray(message)) return message;
  return { value: message };
}

function normalizeOemId(value) {
  if (value === undefined || value === null || value === '') return undefined;
  const text = String(value).trim();
  if (!/^\d+$/.test(text)) return undefined;
  return Number(text);
}

function pickOemId(input, message) {
  return normalizeOemId(input.oemId)
    ?? normalizeOemId(message.oemId)
    ?? normalizeOemId(message.data && message.data.oemId);
}

function firstNonEmpty(...values) {
  for (const value of values) {
    if (value !== undefined && value !== null && value !== '') return value;
  }
  return undefined;
}

function pickAgentName(input, env, oemId) {
  const key = String(oemId);
  const route = ROUTES[oemId];
  const agentNames = input.agentNames && typeof input.agentNames === 'object' ? input.agentNames : {};
  return firstNonEmpty(
    agentNames[key],
    input[`agentName${key}`],
    env[`OEM_AGENT_NAME_${key}`],
    route && route.agentName,
  );
}

function buildChatUrl(input, env) {
  const url = firstNonEmpty(input.chatUrl, env.AIFLOW_NETACLAW_CHAT_URL);
  if (!url) return '';
  try {
    return new URL(String(url)).toString();
  } catch {
    throw new Error('chatUrl must be an absolute URL');
  }
}

function buildChatRequest(input, message, agentName) {
  const forwardedMessage = { ...message };
  if (boolValue(input.stripCallbackUrl, true)) {
    delete forwardedMessage.callbackUrl;
    if (forwardedMessage.data && typeof forwardedMessage.data === 'object' && !Array.isArray(forwardedMessage.data)) {
      forwardedMessage.data = { ...forwardedMessage.data };
      delete forwardedMessage.data.callbackUrl;
    }
  }
  const requestBody = {
    message: JSON.stringify(forwardedMessage),
    agentName,
  };
  if (input.sessionId) requestBody.sessionId = String(input.sessionId);
  if (input.userId) requestBody.userId = String(input.userId);
  return requestBody;
}

async function postJson(url, bodyText, headers, timeoutMs, retries) {
  let lastErr;
  for (let attempt = 0; attempt <= retries; attempt += 1) {
    const controller = new AbortController();
    const timer = setTimeout(() => controller.abort(), timeoutMs);
    try {
      const response = await fetch(url, {
        method: 'POST',
        headers,
        body: bodyText,
        signal: controller.signal,
      });
      const text = await response.text();
      let parsed = text;
      try {
        parsed = text ? JSON.parse(text) : {};
      } catch {
        parsed = text;
      }
      if (!response.ok) {
        const err = new Error(`HTTP ${response.status}: ${typeof parsed === 'string' ? parsed.slice(0, 300) : JSON.stringify(parsed).slice(0, 300)}`);
        err.statusCode = response.status;
        err.response = parsed;
        throw err;
      }
      return { statusCode: response.status, response: parsed };
    } catch (err) {
      lastErr = err;
      if (attempt < retries) await new Promise(resolve => setTimeout(resolve, 300 * (attempt + 1)));
    } finally {
      clearTimeout(timer);
    }
  }
  throw lastErr;
}

async function run(input, env) {
  const message = parseMessage(input.message);
  const oemId = pickOemId(input, message);
  const route = ROUTES[oemId];

  if (!route) {
    return {
      success: false,
      routed: false,
      invoked: false,
      oemId: oemId ?? null,
      error: `Unsupported oemId: ${oemId ?? 'missing'}. Supported oemId values are 2, 11, 16.`,
      message,
    };
  }

  const invoke = boolValue(input.invoke, true);
  const subAgentName = String(pickAgentName(input, env, oemId) || '');
  const base = {
    success: true,
    routed: true,
    invoked: false,
    oemId,
    brand: route.brand,
    subAgentKey: route.subAgentKey,
    subAgentDescription: route.description,
    subAgentId: route.agentId,
    subAgentName,
    reason: `oemId=${oemId} routed to ${route.description}`,
  };

  if (!invoke) {
    emit('route', base.reason, 'completed', { oemId, brand: route.brand });
    return base;
  }

  if (!subAgentName) {
    return {
      ...base,
      success: false,
      error: `Missing subAgent internal name for oemId=${oemId}. Provide agentNames["${oemId}"], agentName${oemId}, or OEM_AGENT_NAME_${oemId}.`,
    };
  }

  const chatUrl = buildChatUrl(input, env);
  if (!chatUrl) {
    return {
      ...base,
      success: false,
      error: 'Missing chatUrl. Provide input.chatUrl or AIFLOW_NETACLAW_CHAT_URL.',
    };
  }

  const requestBody = buildChatRequest(input, message, subAgentName);
  const headers = {
    'Content-Type': 'application/json',
  };
  if (input.headers && typeof input.headers === 'object' && !Array.isArray(input.headers)) {
    Object.assign(headers, input.headers);
  }

  const request = {
    url: chatUrl,
    method: 'POST',
    headers,
    body: requestBody,
  };

  if (boolValue(input.dryRun, false)) {
    emit('dry-run', `OEM路由dryRun完成: ${route.description}`, 'completed', { oemId, brand: route.brand });
    return {
      ...base,
      invoked: true,
      dryRun: true,
      request,
    };
  }

  const timeoutMs = Number(input.timeoutMs || env.OEM_ROUTER_TIMEOUT_MS || 300000);
  const retries = Number(input.retries ?? env.OEM_ROUTER_RETRIES ?? 0);
  emit('invoke', `调用${route.description}`, 'running', { oemId, brand: route.brand, subAgentName });
  const response = await postJson(chatUrl, JSON.stringify(requestBody), headers, timeoutMs, retries);
  emit('complete', `${route.description}响应完成`, 'completed', { statusCode: response.statusCode });

  return {
    ...base,
    invoked: true,
    dryRun: false,
    statusCode: response.statusCode,
    response: response.response,
    request,
  };
}

(async () => {
  try {
    const input = readInput();
    process.stdout.write(JSON.stringify(await run(input, process.env)));
  } catch (err) {
    process.stdout.write(JSON.stringify({
      success: false,
      routed: false,
      invoked: false,
      error: err && err.message ? err.message : String(err),
      statusCode: err && err.statusCode ? err.statusCode : undefined,
      response: err && err.response ? err.response : undefined,
    }));
  }
})();
