import { parseArgs } from "@std/cli/parse-args";
import type { Args } from "@std/cli/parse-args";
import { ensureDir } from "@std/fs";
import { parse, stringify } from "@std/yaml";
import { answerQuery, cleanTextFromHtml, getNewsUrls } from "./websearch.ts";

export interface Config {
  model?: string;
  search_url?: string;
}

const parsed: Args = parseArgs(Deno.args, {
  boolean: ["help"],
  string: ["model", "search_url"],
});

if (parsed.help) {
  console.log(`
    Usage:
      websearch [--model MODEL] [--search_url SEARCH_URL] QUERY

    Options:
      --model Ollama model to use
      --search_url URL for SearXNG endpoint

    Arguments:
      QUERY The topic to search for news to summarize

    Configuration:
      The websearch configuration file is stored in the XDG Config directory
      /home/$USER/.config/websearch/config.yml. Both the model and search_url
      can be customized as an alternative to providing the options for each.
      If both the Ollama model and SearXNG endpoint are successful, the
      configuration is automatically saved/updated.
  `);
  Deno.exit();
}

const configDir = `${Deno.env.get("HOME")}/.config/websearch`;
const configPath = `${Deno.env.get("HOME")}/.config/websearch/config.yml`;

async function loadConfig(): Promise<Config> {
  try {
    const yamlString = await Deno.readTextFile(configPath);
    return parse(yamlString) as Config;
  } catch {
    return {};
  }
}

async function saveConfig(config: Config) {
  await ensureDir(configDir);
  await Deno.writeTextFile(
    configPath,
    stringify(config),
  );
}

async function main(args: Args) {
  const query = args._.join(" ");
  if (!query) {
    throw new Error("Please provide a search query");
  }
  console.log(`Query: ${query}`);

  try {
    const config = await loadConfig();
    if (!config.model) {
      if (args.model) {
        config.model = args.model;
      } else {
        throw new Error("Provide --model or add Ollama model to configuration");
      }
    } else if (args.model && args.model !== config.model) {
      config.model = args.model;
    }
    if (!config.search_url) {
      if (args.search_url) {
        config.search_url = args.search_url;
      } else {
        throw new Error(
          "Provide --search_url or add search_url to configuration",
        );
      }
    } else if (args.search_url && args.search_url !== config.search_url) {
      config.search_url = args.search_url;
    }

    const urls = await getNewsUrls(config, query);
    if (!urls || urls.length === 0) {
      console.log("No results");
      Deno.exit(1);
    }

    const cleanedTexts = await Promise.all(
      urls.map((url) => cleanTextFromHtml(url)),
    );
    await answerQuery(config, query, cleanedTexts.join("\n\n"));
    await saveConfig(config);
  } catch (error: any) {
    console.error(`Error processing query "${query}":`, error.message);
    Deno.exit(1);
  }
}

if (import.meta.main) {
  main(parsed).catch((error) => {
    console.error("Unhandled exception:", error);
    Deno.exit(1);
  });
}
