export const COURSEWARE_RUNTIME_CONFIG_PATH = "/courseware-runtime.json";
export const LAB1_DEFAULT_NETRON_URL = "http://127.0.0.1:8338";
export const LAB2_DEFAULT_OLLAMA_URL = "http://127.0.0.1:11434";
export const LAB2_DEFAULT_OLLAMA_MODELS = [
  {
    label: "Gemma 4 E2B Q4",
    value: "batiai/gemma4-e2b:q4",
  },
  {
    label: "Gemma 4 E2B Q6",
    value: "batiai/gemma4-e2b:q6",
  },
] as const;
export const LAB3_DEFAULT_TERMINAL_PATH = "/wetty";
export const COURSEWARE_SERVICE_IDS = [
  "open-webui",
  "promptfoo",
  "chunkviz",
  "embedding-atlas",
  "unsloth",
  "ssh",
] as const;

export type CoursewareRuntimeModelOption = {
  label: string;
  value: string;
};

export type CoursewareServiceId = (typeof COURSEWARE_SERVICE_IDS)[number];

export type CoursewareRuntimeServices = Partial<
  Record<CoursewareServiceId, string>
>;

export type ResolvedCoursewareRuntimeServices = Record<
  CoursewareServiceId,
  string
>;

export const COURSEWARE_SERVICE_DEFAULTS: ResolvedCoursewareRuntimeServices = {
  "chunkviz": "http://127.0.0.1:3000",
  "embedding-atlas": "http://127.0.0.1:5055",
  "open-webui": "http://127.0.0.1:8080",
  "promptfoo": "http://127.0.0.1:15500",
  "ssh": "ssh://127.0.0.1:22",
  "unsloth": "http://127.0.0.1:8888",
};

export type CoursewareRuntimeConfig = {
  lab1NetronUrl?: string;
  lab2OllamaModels?: CoursewareRuntimeModelOption[];
  lab2OllamaUrl?: string;
  lab3TerminalUrl?: string;
  services?: CoursewareRuntimeServices;
};

export type ResolvedCoursewareRuntimeConfig = {
  lab1NetronUrl: string;
  lab2OllamaModels: CoursewareRuntimeModelOption[];
  lab2OllamaUrl: string;
  lab3TerminalUrl: string;
  services: ResolvedCoursewareRuntimeServices;
};

const loopbackHosts = new Set(["127.0.0.1", "localhost", "::1"]);

function rewriteLoopbackHost(urlValue: string, currentHostname?: string) {
  try {
    const url = new URL(urlValue);
    if (!currentHostname || !loopbackHosts.has(url.hostname)) {
      return url.toString();
    }

    url.hostname = currentHostname;
    return url.toString();
  } catch {
    return urlValue;
  }
}

function getCurrentHostname() {
  if (typeof window === "undefined") {
    return undefined;
  }

  const hostname = window.location.hostname?.trim();
  return hostname || undefined;
}

export function isCoursewareServiceId(
  value: string,
): value is CoursewareServiceId {
  return (COURSEWARE_SERVICE_IDS as readonly string[]).includes(value);
}

export function getCoursewareServiceBaseUrl(
  serviceId: CoursewareServiceId,
  envValue?: string,
  currentHostname = getCurrentHostname(),
) {
  const trimmedValue = envValue?.trim();
  const baseUrl = trimmedValue || COURSEWARE_SERVICE_DEFAULTS[serviceId];
  return rewriteLoopbackHost(baseUrl, currentHostname);
}

export function getCoursewareServices(
  envValue?: CoursewareRuntimeServices,
  currentHostname = getCurrentHostname(),
): ResolvedCoursewareRuntimeServices {
  const services = {} as ResolvedCoursewareRuntimeServices;

  for (const serviceId of COURSEWARE_SERVICE_IDS) {
    services[serviceId] = getCoursewareServiceBaseUrl(
      serviceId,
      envValue?.[serviceId],
      currentHostname,
    );
  }

  return services;
}

function appendUrlPath(urlValue: string, pathSuffix: string) {
  const trimmedSuffix = pathSuffix.trim();
  if (!trimmedSuffix) {
    return urlValue;
  }

  try {
    const url = new URL(urlValue);
    const normalizedSuffix = trimmedSuffix.startsWith("/")
      ? trimmedSuffix
      : `/${trimmedSuffix}`;
    const basePath = url.pathname === "/" ? "" : url.pathname.replace(/\/$/, "");

    url.pathname = `${basePath}${normalizedSuffix}`;
    return url.toString();
  } catch {
    return urlValue;
  }
}

export function resolveCoursewareServiceBaseUrl(
  runtimeConfig: Pick<ResolvedCoursewareRuntimeConfig, "services">,
  serviceId: CoursewareServiceId,
) {
  return runtimeConfig.services[serviceId];
}

export function resolveCoursewareServiceUrl(
  runtimeConfig: Pick<ResolvedCoursewareRuntimeConfig, "services">,
  serviceId: CoursewareServiceId,
  pathSuffix?: string,
) {
  const baseUrl = resolveCoursewareServiceBaseUrl(runtimeConfig, serviceId);
  if (!pathSuffix?.trim()) {
    return baseUrl;
  }

  return appendUrlPath(baseUrl, pathSuffix);
}

export function resolveCoursewareServiceAddress(
  runtimeConfig: Pick<ResolvedCoursewareRuntimeConfig, "services">,
  serviceId: CoursewareServiceId,
) {
  const baseUrl = resolveCoursewareServiceBaseUrl(runtimeConfig, serviceId);

  try {
    const url = new URL(baseUrl);
    return url.port ? `${url.hostname}:${url.port}` : url.hostname;
  } catch {
    return baseUrl;
  }
}

export function getLab1NetronUrl(
  envValue?: string,
  currentHostname = getCurrentHostname(),
) {
  const trimmedValue = envValue?.trim();

  if (!trimmedValue) {
    return rewriteLoopbackHost(LAB1_DEFAULT_NETRON_URL, currentHostname);
  }

  return rewriteLoopbackHost(trimmedValue, currentHostname);
}

export function getLab2OllamaUrl(
  envValue?: string,
  currentHostname = getCurrentHostname(),
) {
  const trimmedValue = envValue?.trim();

  if (!trimmedValue) {
    return rewriteLoopbackHost(LAB2_DEFAULT_OLLAMA_URL, currentHostname);
  }

  return rewriteLoopbackHost(trimmedValue, currentHostname);
}

export function getLab2OllamaModels(
  envValue?: CoursewareRuntimeModelOption[],
) {
  if (!Array.isArray(envValue) || envValue.length === 0) {
    return LAB2_DEFAULT_OLLAMA_MODELS.map((model) => ({ ...model }));
  }

  const normalizedModels = envValue
    .map((model) => {
      const label = model?.label?.trim();
      const value = model?.value?.trim();

      if (!label || !value) {
        return null;
      }

      return { label, value } satisfies CoursewareRuntimeModelOption;
    })
    .filter(
      (model): model is CoursewareRuntimeModelOption => model !== null,
    );

  if (normalizedModels.length === 0) {
    return LAB2_DEFAULT_OLLAMA_MODELS.map((model) => ({ ...model }));
  }

  return normalizedModels;
}

export function getLab3TerminalPath(
  envValue?: string,
  currentHostname = getCurrentHostname(),
) {
  const trimmedValue = envValue?.trim();

  if (!trimmedValue) {
    return LAB3_DEFAULT_TERMINAL_PATH;
  }

  if (/^https?:\/\//i.test(trimmedValue)) {
    return rewriteLoopbackHost(trimmedValue, currentHostname);
  }

  return trimmedValue.startsWith("/") ? trimmedValue : `/${trimmedValue}`;
}

export function normalizeCoursewareRuntimeConfig(
  config?: CoursewareRuntimeConfig,
  currentHostname = getCurrentHostname(),
): ResolvedCoursewareRuntimeConfig {
  return {
    lab1NetronUrl: getLab1NetronUrl(config?.lab1NetronUrl, currentHostname),
    lab2OllamaModels: getLab2OllamaModels(config?.lab2OllamaModels),
    lab2OllamaUrl: getLab2OllamaUrl(config?.lab2OllamaUrl, currentHostname),
    lab3TerminalUrl: getLab3TerminalPath(
      config?.lab3TerminalUrl,
      currentHostname,
    ),
    services: getCoursewareServices(config?.services, currentHostname),
  };
}

export async function fetchCoursewareRuntimeConfig() {
  const response = await fetch(COURSEWARE_RUNTIME_CONFIG_PATH, {
    cache: "no-store",
  });

  if (!response.ok) {
    throw new Error(`Runtime config request failed: ${response.status}`);
  }

  const config = (await response.json()) as CoursewareRuntimeConfig;
  return normalizeCoursewareRuntimeConfig(config);
}
