import type { UniDeskConfig } from "../config";
import type { RenderedCliResult } from "../output";
import { defaultSub2ApiTargetId } from "../platform-infra/config";

import { projectSub2ApiOps } from "./projection";
import { querySub2ApiOps } from "./query";
import { renderSub2ApiOps } from "./render";
import type { Sub2ApiOpsOptions } from "./types";

export async function runSub2ApiOpsCommand(config: UniDeskConfig, args: string[]): Promise<Record<string, unknown> | RenderedCliResult> {
  const options = parseSub2ApiOpsOptions(args);
  const raw = await querySub2ApiOps(config, options);
  const projected = projectSub2ApiOps(raw, options);
  return options.json ? projected : renderSub2ApiOps(projected);
}

export function parseSub2ApiOpsOptions(args: string[]): Sub2ApiOpsOptions {
  const [actionRaw, ...rest] = args;
  if (actionRaw !== "diagnosis" && actionRaw !== "channels") {
    throw new Error("sub2api ops usage: diagnosis|channels [--target <id>] [--platform <name>] [--json]");
  }
  let targetId = defaultSub2ApiTargetId();
  let json = false;
  let platform: string | null = null;
  let group: string | null = null;
  let diagnosisId: string | null = null;
  let timeRange = "1h" as Sub2ApiOpsOptions["timeRange"];
  let channel: string | null = null;
  let model: string | null = null;
  let window = "7d" as Sub2ApiOpsOptions["window"];
  let pageToken: string | null = null;
  let recordId: string | null = null;
  for (let index = 0; index < rest.length; index += 1) {
    const arg = rest[index]!;
    const readValue = (name: string): string => {
      const value = rest[index + 1];
      if (value === undefined || value.startsWith("--")) throw new Error(`${name} requires a value`);
      index += 1;
      return value.trim();
    };
    if (arg === "--json") json = true;
    else if (arg === "--target") targetId = readValue(arg);
    else if (arg === "--platform") platform = readValue(arg);
    else if (arg === "--group") group = readValue(arg);
    else if (arg === "--id") diagnosisId = readValue(arg);
    else if (arg === "--time-range") timeRange = parseTimeRange(readValue(arg));
    else if (arg === "--channel") channel = readValue(arg);
    else if (arg === "--model") model = readValue(arg);
    else if (arg === "--window") window = parseWindow(readValue(arg));
    else if (arg === "--page-token") pageToken = parseRecordId(readValue(arg), arg);
    else if (arg === "--record") recordId = parseRecordId(readValue(arg), arg);
    else throw new Error(`unknown sub2api ops option: ${arg}`);
  }
  if (actionRaw === "diagnosis" && (channel !== null || model !== null || window !== "7d" || pageToken !== null || recordId !== null)) throw new Error("ops diagnosis does not accept channel history options");
  if (actionRaw === "channels" && (group !== null || diagnosisId !== null || timeRange !== "1h")) throw new Error("ops channels does not accept --group, --id, or --time-range");
  if (actionRaw === "channels" && model !== null && channel === null) throw new Error("--model requires --channel");
  if (actionRaw === "channels" && (pageToken !== null || recordId !== null) && channel === null) throw new Error("--page-token and --record require --channel");
  if (pageToken !== null && recordId !== null) throw new Error("use only one of --page-token or --record");
  return { action: actionRaw, targetId, json, platform, group, diagnosisId, timeRange, channel, model, window, pageToken, recordId };
}

function parseTimeRange(value: string): Sub2ApiOpsOptions["timeRange"] {
  if (value === "5m" || value === "30m" || value === "1h" || value === "6h" || value === "24h") return value;
  throw new Error("--time-range must be one of 5m, 30m, 1h, 6h, 24h");
}

function parseWindow(value: string): Sub2ApiOpsOptions["window"] {
  if (value === "7d" || value === "15d" || value === "30d") return value;
  throw new Error("--window must be one of 7d, 15d, 30d");
}

function parseRecordId(value: string, option: string): string {
  if (/^[1-9][0-9]*$/u.test(value)) return value;
  throw new Error(`${option} must be a positive native history record ID`);
}
