'use strict';

const VERIFICATION_TOOL_NAME_RE = /(?:test|verify|screenshot|smoke|diagnostic|lint|build|check_url|url_check|pdf_info|pdf_render_pages|make_pdf)/i;
const VERIFICATION_COMMAND_RE = /\b(?:test|spec|lint|build|typecheck|tsc|pytest|jest|mocha|vitest|playwright|node\s+--(?:test|check)|npm\s+(?:test|run)|pnpm\s+(?:test|run)|yarn\s+(?:test|run)|git\s+diff\s+--check|curl\s+.*(?:localhost|127\.0\.0\.1)|check_url|pdfinfo|pdftoppm|pdftotext)\b/i;

function callName(call = {}) {
  return String(call.name || call.tool || '');
}

function callInput(call = {}) {
  return call.input || call.args || {};
}

function inputHashFor(call = {}) {
  if (call.inputHash) return String(call.inputHash);
  try {
    return JSON.stringify(callInput(call)).slice(0, 500);
  } catch {
    return String(callInput(call)).slice(0, 500);
  }
}

function hasResultEvidence(call = {}) {
  return Object.prototype.hasOwnProperty.call(call, 'result')
    || Object.prototype.hasOwnProperty.call(call, 'ok')
    || Object.prototype.hasOwnProperty.call(call, 'success')
    || Object.prototype.hasOwnProperty.call(call, 'exitCode')
    || Boolean(call.error);
}

function toolResultSucceeded(call = {}) {
  const result = Object.prototype.hasOwnProperty.call(call, 'result') ? call.result : call;
  if (call.error === true || typeof call.error === 'string') return false;
  if (!hasResultEvidence(call)) return false;
  if (result && typeof result === 'object') {
    if (result.error) return false;
    if (result.ok === false || result.success === false) return false;
    if (typeof result.exitCode === 'number' && result.exitCode !== 0) return false;
  }
  if (call.ok === false || call.success === false) return false;
  if (typeof call.exitCode === 'number' && call.exitCode !== 0) return false;
  return true;
}

function isVerificationToolCall(call = {}) {
  const name = callName(call);
  const input = String(inputHashFor(call));
  if (name === 'browser_screenshot' || name === 'browser_smoke_test' || name === 'check_url' || name === 'url_check'
      || name === 'pdf_info' || name === 'pdf_render_pages' || name === 'make_pdf') return true;
  if (name === 'run_shell') return VERIFICATION_COMMAND_RE.test(input);
  return VERIFICATION_TOOL_NAME_RE.test(name);
}

function isSuccessfulVerificationToolCall(call = {}) {
  return isVerificationToolCall(call) && toolResultSucceeded(call);
}

function hasVerificationEvidence(toolCallHistory = []) {
  return (toolCallHistory || []).some(isSuccessfulVerificationToolCall);
}

function hasFailedVerificationAttempt(toolCallHistory = []) {
  return (toolCallHistory || [])
    .some((call) => isVerificationToolCall(call) && hasResultEvidence(call) && !toolResultSucceeded(call));
}

function normalizeToolCallEvidence(call = {}, result) {
  const normalized = {
    name: callName(call),
    inputHash: inputHashFor(call),
  };
  if (call.id || call.toolCallId) normalized.id = call.id || call.toolCallId;
  if (Object.prototype.hasOwnProperty.call(call, 'input')) normalized.input = call.input;
  if (Object.prototype.hasOwnProperty.call(call, 'args')) normalized.args = call.args;
  if (Object.prototype.hasOwnProperty.call(call, 'error')) normalized.error = call.error;
  if (arguments.length > 1) normalized.result = result;
  else if (Object.prototype.hasOwnProperty.call(call, 'result')) normalized.result = call.result;
  if (hasResultEvidence(normalized)) normalized.ok = toolResultSucceeded(normalized);
  return normalized;
}

function hasSuccessfulToolEvidence(toolCallHistory = [], toolName = '') {
  const expected = String(toolName || '');
  if (!expected) return false;
  return (toolCallHistory || []).some((call) => callName(call) === expected && toolResultSucceeded(call));
}

function collectToolEvidence(toolCallHistory = [], toolName = '') {
  const expected = String(toolName || '');
  return (toolCallHistory || [])
    .filter((call) => callName(call) === expected)
    .map((call) => ({
      name: callName(call),
      ok: toolResultSucceeded(call),
      result: call.result && typeof call.result === 'object' ? call.result : call,
    }));
}

function buildAcceptanceContract({
  request = '',
  subtask = {},
  changedFiles = [],
  frontend = false,
  requiresFileChanges = false,
} = {}) {
  const explicit = subtask.acceptance && typeof subtask.acceptance === 'object' ? subtask.acceptance : {};
  const text = `${request}\n${subtask.title || ''}\n${subtask.prompt || ''}`;
  const frontendTask = frontend || /\b(?:website|web\s?page|frontend|ui|ux|html|css|javascript|responsive|layout|browser)\b/i.test(text);
  const validators = new Set(Array.isArray(explicit.validators) ? explicit.validators : []);
  if (frontendTask) {
    validators.add('frontend.static_contract');
    validators.add('frontend.screenshot_evidence');
    validators.add('frontend.browser_runtime');
  }
  const writePolicy = explicit.write_policy || explicit.writePolicy || (
    requiresFileChanges ? 'must-write' : 'may-write'
  );
  return {
    taskKind: explicit.task_kind || explicit.taskKind || (frontendTask ? 'frontend-ui' : 'code'),
    writePolicy,
    validators: [...validators],
    requiresFrontendValidation: frontendTask,
    changedFiles: [...new Set(changedFiles || [])],
    recoveryPolicy: explicit.recovery_policy || explicit.recoveryPolicy || 'retry-with-validator-failure',
  };
}

function validatorFailure(name, message, detail = {}) {
  return {
    name,
    ok: false,
    message,
    detail,
  };
}

function validatorPass(name, message, detail = {}) {
  return {
    name,
    ok: true,
    message,
    detail,
  };
}

function summarizeValidatorFailures(report = {}) {
  return (report.validators || [])
    .filter((item) => item && item.ok === false)
    .map((item) => item.message || item.name)
    .filter(Boolean);
}

module.exports = {
  callName,
  callInput,
  inputHashFor,
  hasResultEvidence,
  toolResultSucceeded,
  isVerificationToolCall,
  isSuccessfulVerificationToolCall,
  hasVerificationEvidence,
  hasFailedVerificationAttempt,
  normalizeToolCallEvidence,
  hasSuccessfulToolEvidence,
  collectToolEvidence,
  buildAcceptanceContract,
  validatorFailure,
  validatorPass,
  summarizeValidatorFailures,
};
