import type { ParsedArgs } from "../args";
import { callDaemon } from "../client";
import { createUsageError } from "../errors";
import { parseNumberFlag } from "../utils/parse";
import { buildWorkflowCompletionMessage } from "../utils/workflow-message";
import { DEFAULT_WORKFLOW_TRANSPORT_TIMEOUT_MS } from "../transport-timeouts";
import { resolveWorkflowOutputDirFlag } from "./workflow-output";
import { isChallengeAutomationMode, type ChallengeAutomationMode } from "../../challenges/types";
import type { WorkflowBrowserMode } from "../../providers/types";

type ResearchCommandArgs = {
  topic?: string;
  days?: number;
  from?: string;
  to?: string;
  sourceSelection?: "auto" | "web" | "community" | "social" | "shopping" | "all";
  sources?: Array<"web" | "community" | "social" | "shopping">;
  mode?: "compact" | "json" | "md" | "context" | "path";
  includeEngagement?: boolean;
  limitPerSource?: number;
  timeoutMs?: number;
  outputDir?: string;
  ttlHours?: number;
  browserMode?: WorkflowBrowserMode;
  profile?: string;
  useCookies?: boolean;
  challengeAutomationMode?: ChallengeAutomationMode;
  cookiePolicyOverride?: "off" | "auto" | "required";
};

const SOURCE_VALUES = new Set(["web", "community", "social", "shopping"]);
const SOURCE_SELECTION_VALUES = new Set(["auto", "web", "community", "social", "shopping", "all"]);
const MODE_VALUES = new Set(["compact", "json", "md", "context", "path"]);
const BROWSER_MODE_VALUES = new Set(["auto", "extension", "managed"]);
const COOKIE_POLICY_VALUES = new Set(["off", "auto", "required"]);
const requireValue = (rawArgs: string[], index: number, flag: string): string => {
  const value = rawArgs[index + 1];
  if (!value) {
    throw createUsageError(`Missing value for ${flag}`);
  }
  return value;
};

const parseBoolean = (value: string, flag: string): boolean => {
  if (value === "true") return true;
  if (value === "false") return false;
  throw createUsageError(`Invalid ${flag}: ${value}`);
};

const parseSources = (raw: string): Array<"web" | "community" | "social" | "shopping"> => {
  const parsed = raw
    .split(",")
    .map((entry) => entry.trim().toLowerCase())
    .filter(Boolean);

  if (parsed.length === 0) {
    throw createUsageError("--sources requires at least one source");
  }

  const deduped = [...new Set(parsed)];
  for (const source of deduped) {
    if (!SOURCE_VALUES.has(source)) {
      throw createUsageError(`Invalid --sources value: ${source}`);
    }
  }
  return deduped as Array<"web" | "community" | "social" | "shopping">;
};

const parseResearchRunArgs = (rawArgs: string[]): ResearchCommandArgs => {
  const parsed: ResearchCommandArgs = {};

  for (let index = 0; index < rawArgs.length; index += 1) {
    const arg = rawArgs[index];

    if (arg === "--topic") {
      parsed.topic = requireValue(rawArgs, index, "--topic");
      index += 1;
      continue;
    }
    if (arg?.startsWith("--topic=")) {
      parsed.topic = arg.split("=", 2)[1];
      continue;
    }

    if (arg === "--days") {
      parsed.days = parseNumberFlag(requireValue(rawArgs, index, "--days"), "--days", { min: 1, max: 365 });
      index += 1;
      continue;
    }
    if (arg?.startsWith("--days=")) {
      parsed.days = parseNumberFlag(arg.split("=", 2)[1] ?? "", "--days", { min: 1, max: 365 });
      continue;
    }

    if (arg === "--from") {
      parsed.from = requireValue(rawArgs, index, "--from");
      index += 1;
      continue;
    }
    if (arg?.startsWith("--from=")) {
      parsed.from = arg.split("=", 2)[1];
      continue;
    }

    if (arg === "--to") {
      parsed.to = requireValue(rawArgs, index, "--to");
      index += 1;
      continue;
    }
    if (arg?.startsWith("--to=")) {
      parsed.to = arg.split("=", 2)[1];
      continue;
    }

    if (arg === "--source-selection") {
      const value = requireValue(rawArgs, index, "--source-selection").toLowerCase();
      if (!SOURCE_SELECTION_VALUES.has(value)) {
        throw createUsageError(`Invalid --source-selection: ${value}`);
      }
      parsed.sourceSelection = value as ResearchCommandArgs["sourceSelection"];
      index += 1;
      continue;
    }
    if (arg?.startsWith("--source-selection=")) {
      const value = (arg.split("=", 2)[1] ?? "").toLowerCase();
      if (!SOURCE_SELECTION_VALUES.has(value)) {
        throw createUsageError(`Invalid --source-selection: ${value}`);
      }
      parsed.sourceSelection = value as ResearchCommandArgs["sourceSelection"];
      continue;
    }

    if (arg === "--sources") {
      parsed.sources = parseSources(requireValue(rawArgs, index, "--sources"));
      index += 1;
      continue;
    }
    if (arg?.startsWith("--sources=")) {
      parsed.sources = parseSources(arg.split("=", 2)[1] ?? "");
      continue;
    }

    if (arg === "--mode") {
      const value = requireValue(rawArgs, index, "--mode").toLowerCase();
      if (!MODE_VALUES.has(value)) {
        throw createUsageError(`Invalid --mode: ${value}`);
      }
      parsed.mode = value as ResearchCommandArgs["mode"];
      index += 1;
      continue;
    }
    if (arg?.startsWith("--mode=")) {
      const value = (arg.split("=", 2)[1] ?? "").toLowerCase();
      if (!MODE_VALUES.has(value)) {
        throw createUsageError(`Invalid --mode: ${value}`);
      }
      parsed.mode = value as ResearchCommandArgs["mode"];
      continue;
    }

    if (arg === "--include-engagement") {
      parsed.includeEngagement = true;
      continue;
    }

    if (arg === "--limit-per-source") {
      parsed.limitPerSource = parseNumberFlag(requireValue(rawArgs, index, "--limit-per-source"), "--limit-per-source", { min: 1, max: 100 });
      index += 1;
      continue;
    }
    if (arg?.startsWith("--limit-per-source=")) {
      parsed.limitPerSource = parseNumberFlag(arg.split("=", 2)[1] ?? "", "--limit-per-source", { min: 1, max: 100 });
      continue;
    }

    if (arg === "--timeout-ms") {
      parsed.timeoutMs = parseNumberFlag(requireValue(rawArgs, index, "--timeout-ms"), "--timeout-ms", { min: 1 });
      index += 1;
      continue;
    }
    if (arg?.startsWith("--timeout-ms=")) {
      parsed.timeoutMs = parseNumberFlag(arg.split("=", 2)[1] ?? "", "--timeout-ms", { min: 1 });
      continue;
    }

    if (arg === "--output-dir") {
      parsed.outputDir = resolveWorkflowOutputDirFlag(requireValue(rawArgs, index, "--output-dir"));
      index += 1;
      continue;
    }
    if (arg?.startsWith("--output-dir=")) {
      parsed.outputDir = resolveWorkflowOutputDirFlag(arg.split("=", 2)[1]);
      continue;
    }

    if (arg === "--ttl-hours") {
      parsed.ttlHours = parseNumberFlag(requireValue(rawArgs, index, "--ttl-hours"), "--ttl-hours", { min: 1, max: 168 });
      index += 1;
      continue;
    }
    if (arg?.startsWith("--ttl-hours=")) {
      parsed.ttlHours = parseNumberFlag(arg.split("=", 2)[1] ?? "", "--ttl-hours", { min: 1, max: 168 });
      continue;
    }

    if (arg === "--browser-mode") {
      const value = requireValue(rawArgs, index, "--browser-mode").toLowerCase();
      if (!BROWSER_MODE_VALUES.has(value)) {
        throw createUsageError(`Invalid --browser-mode: ${value}`);
      }
      parsed.browserMode = value as WorkflowBrowserMode;
      index += 1;
      continue;
    }
    if (arg?.startsWith("--browser-mode=")) {
      const value = (arg.split("=", 2)[1] ?? "").toLowerCase();
      if (!BROWSER_MODE_VALUES.has(value)) {
        throw createUsageError(`Invalid --browser-mode: ${value}`);
      }
      parsed.browserMode = value as WorkflowBrowserMode;
      continue;
    }

    if (arg === "--profile") {
      parsed.profile = requireValue(rawArgs, index, "--profile");
      index += 1;
      continue;
    }
    if (arg?.startsWith("--profile=")) {
      parsed.profile = arg.split("=", 2)[1];
      continue;
    }

    if (arg === "--use-cookies") {
      parsed.useCookies = true;
      continue;
    }
    if (arg?.startsWith("--use-cookies=")) {
      parsed.useCookies = parseBoolean(arg.split("=", 2)[1] ?? "", "--use-cookies");
      continue;
    }

    if (arg === "--challenge-automation-mode") {
      const value = requireValue(rawArgs, index, "--challenge-automation-mode");
      if (!isChallengeAutomationMode(value)) {
        throw createUsageError(`Invalid --challenge-automation-mode: ${value}`);
      }
      parsed.challengeAutomationMode = value;
      index += 1;
      continue;
    }
    if (arg?.startsWith("--challenge-automation-mode=")) {
      const value = arg.split("=", 2)[1] ?? "";
      if (!isChallengeAutomationMode(value)) {
        throw createUsageError(`Invalid --challenge-automation-mode: ${value}`);
      }
      parsed.challengeAutomationMode = value;
      continue;
    }

    if (arg === "--cookie-policy-override" || arg === "--cookie-policy") {
      const value = requireValue(rawArgs, index, arg).toLowerCase();
      if (!COOKIE_POLICY_VALUES.has(value)) {
        throw createUsageError(`Invalid ${arg}: ${value}`);
      }
      parsed.cookiePolicyOverride = value as ResearchCommandArgs["cookiePolicyOverride"];
      index += 1;
      continue;
    }
    if (arg?.startsWith("--cookie-policy-override=") || arg?.startsWith("--cookie-policy=")) {
      const value = (arg.split("=", 2)[1] ?? "").toLowerCase();
      if (!COOKIE_POLICY_VALUES.has(value)) {
        throw createUsageError(`Invalid --cookie-policy-override: ${value}`);
      }
      parsed.cookiePolicyOverride = value as ResearchCommandArgs["cookiePolicyOverride"];
      continue;
    }
  }

  return parsed;
};

export async function runResearchCommand(args: ParsedArgs) {
  const [subcommand, ...rest] = args.rawArgs;
  if (subcommand !== "run") {
    throw createUsageError("Usage: opendevbrowser research run --topic <value> [options]");
  }

  const parsed = parseResearchRunArgs(rest);
  if (!parsed.topic?.trim()) {
    throw createUsageError("Missing --topic");
  }

  const payload = {
    topic: parsed.topic,
    days: parsed.days,
    from: parsed.from,
    to: parsed.to,
    sourceSelection: parsed.sourceSelection,
    sources: parsed.sources,
    mode: parsed.mode ?? "compact",
    includeEngagement: parsed.includeEngagement ?? false,
    limitPerSource: parsed.limitPerSource,
    timeoutMs: parsed.timeoutMs ?? DEFAULT_WORKFLOW_TRANSPORT_TIMEOUT_MS,
    outputDir: resolveWorkflowOutputDirFlag(parsed.outputDir),
    ttlHours: parsed.ttlHours,
    browserMode: parsed.browserMode,
    profile: parsed.profile,
    useCookies: parsed.useCookies,
    challengeAutomationMode: parsed.challengeAutomationMode,
    cookiePolicyOverride: parsed.cookiePolicyOverride
  };

  const data = await callDaemon("research.run", payload);

  return {
    success: true,
    message: buildWorkflowCompletionMessage("Research workflow", data),
    data
  };
}

export const __test__ = {
  parseResearchRunArgs,
  parseSources
};
