const { WebSearchTool } = require("./backend/search_tool");
const { normalizeOrigin } = require("./backend/result_formatter");
const {
  capabilityAvailable,
  capabilityEnabled,
  ensureSettings,
  readSettings,
  readStatus
} = require("./backend/settings");

const REASON_SCHEMA = {
  type: "string",
  required: true,
  enum: [
    "fact_lookup",
    "resource_lookup",
    "troubleshooting",
    "documentation_lookup",
    "news_or_recent",
    "general_lookup"
  ]
};

module.exports.checkAvailability = ({ paths }) => {
  const settings = ensureSettings(paths.data);
  const enabled = ["search", "fetch_url", "summarize_url"]
    .filter((capability) => capabilityAvailable(settings, capability));
  if (!enabled.length) {
    return {
      available: false,
      message: "All web-search capabilities are disabled in tool settings."
    };
  }
  if (settings.provider === "external_json" &&
      settings.enable_search &&
      !settings.external_provider_endpoint) {
    return {
      available: true,
      message: "Explicit URL tools are available. Search requires the selected external endpoint or Lumi search broker."
    };
  }
  return {
    available: true,
    message: settings.provider === "lumi_search_broker"
      ? "Self-contained Lumi search broker is ready; no external provider setup is required."
      : "Optional external JSON provider is configured."
  };
};

module.exports.register = ({ registerTool, paths }) => {
  ensureSettings(paths.data);
  const tool = new WebSearchTool({ dataDir: paths.data });
  const register = (capability, definition) => {
    const settings = readSettings(paths.data);
    if (!capabilityAvailable(settings, capability)) return;
    registerTool({
      ...definition,
      required_role: "user",
      required_permission: `lumi_ai_web_search.${capability}`,
      audit_category: "web_search",
      confirmation_required: false,
      risk_level: "low",
      read_only: true,
      origin_check: ({ context }) => originAllowed(paths.data, context, capability),
      prompt_permission_check: ({ user }) => Boolean(user?.id),
      permission_check: ({ user, context }) =>
        Boolean(user?.id) && originAllowed(paths.data, context, capability)
    });
  };

  register("search", {
    tool_id: "web_search.search",
    display_name: "Search the public web",
    description: "Search current public web information when verified Lumi-local context is insufficient or the user requests current, external, sourced, or verified facts.",
    use_cases: [
      "Current, recent, niche, or likely outdated public facts",
      "Verification, citations, comparisons, changelogs, releases, policies, and public documentation",
      "Current third-party information about Twitch, Discord, YouTube, Kick, Throne, Gitea, llama.cpp, Hugging Face, hardware, software, APIs, and services"
    ],
    output_expectations: "Returns compact policy-filtered structured results. Use only returned facts and URLs in the final answer; state uncertainty when results are incomplete.",
    schema: {
      query: { type: "string", required: true },
      reason: REASON_SCHEMA,
      freshness: { type: "string", required: false },
      max_results: { type: "integer", required: false },
      target_url: { type: "string", required: false }
    },
    workflow_handler: ({ arguments: args, user, ctx }) => tool.search({ ...args, user, ctx })
  });

  register("fetch_url", {
    tool_id: "web_search.fetch_url",
    display_name: "Fetch a public URL",
    description: "Safely fetch and extract readable information from an explicit public HTTP or HTTPS URL supplied by the user.",
    use_cases: [
      "Read an explicit public URL without search discovery",
      "Inspect public documentation, release notes, articles, or status pages",
      "Verify the current contents of a user-supplied page"
    ],
    output_expectations: "Returns sanitized page metadata and bounded readable text. Never claim JavaScript execution or browser interaction.",
    schema: {
      url: { type: "string", required: true },
      reason: { ...REASON_SCHEMA, required: false }
    },
    workflow_handler: ({ arguments: args, user, ctx }) => tool.fetchUrl({ ...args, user, ctx })
  });

  register("summarize_url", {
    tool_id: "web_search.summarize_url",
    display_name: "Summarize a public URL",
    description: "Safely fetch an explicit public HTTP or HTTPS URL and return compact extracted content for a concise summary.",
    use_cases: [
      "Summarize a user-supplied public article, documentation page, or release note",
      "Condense a public page without discovering unrelated search results"
    ],
    output_expectations: "Returns bounded sanitized source text and metadata. The assistant writes the final concise summary using only that content.",
    schema: {
      url: { type: "string", required: true },
      reason: { ...REASON_SCHEMA, required: false }
    },
    workflow_handler: ({ arguments: args, user, ctx }) => tool.summarizeUrl({ ...args, user, ctx })
  });
};

module.exports.diagnostics = ({ paths }) => {
  const settings = readSettings(paths.data);
  const status = readStatus(paths.data);
  const metrics = status.metrics || {};
  const capabilities = ["search", "fetch_url", "summarize_url"].map((capability) => ({
    tool_id: `web_search.${capability}`,
    enabled: capabilityEnabled(settings, capability),
    available: capabilityAvailable(settings, capability)
  }));
  return {
    provider: settings.provider,
    provider_health: status.provider_health || "not_tested",
    policy_mode: settings.policy_mode,
    allowed_origins: settings.allowed_origins,
    capabilities,
    last_success_at: status.last_success_at || null,
    last_error: status.last_error || null,
    cache: status.cache || { entries: 0, bytes: 0 },
    metrics: {
      ...metrics,
      average_search_ms: metrics.searches
        ? Math.round(Number(metrics.total_search_ms || 0) / Number(metrics.searches))
        : 0,
      average_fetch_ms: metrics.fetches
        ? Math.round(Number(metrics.total_fetch_ms || 0) / Number(metrics.fetches))
        : 0,
      cache_hit_rate: Number(metrics.searches || 0) + Number(metrics.fetches || 0)
        ? Math.round(
          Number(metrics.cache_hits || 0) /
          (Number(metrics.searches || 0) + Number(metrics.fetches || 0)) *
          1000
        ) / 10
        : 0
    },
    recent: Array.isArray(status.recent) ? status.recent.slice(0, 10) : []
  };
};

function originAllowed(dataDir, context, capability) {
  const settings = readSettings(dataDir);
  const origin = normalizeOrigin(context?.origin || context?.platform || "other");
  return capabilityAvailable(settings, capability) && settings.allowed_origins.includes(origin);
}
