import {
  DEFAULT_CHARACTER,
  getCharacterBySlug,
  type CharacterProfile,
} from "@/data/constants/character";

import { getCharacterRoutes, ROUTES } from "./routes";

export const GLOBAL_RETURN_TO_PARAM = "returnTo";

export type GlobalPageRoute =
  | typeof ROUTES.profile
  | typeof ROUTES.feedback
  | typeof ROUTES.coinsRules;

export interface GlobalRouteContext {
  readonly characterSlug: CharacterProfile["slug"];
  readonly chatUrl: string;
  readonly splashUrl: string;
  readonly profileUrl: string;
  readonly feedbackUrl: string;
  readonly coinsRulesUrl: string;
}

export type GlobalReturnToValue =
  | string
  | readonly string[]
  | null
  | undefined;

export function resolveGlobalRouteContext(
  value?: GlobalReturnToValue,
): GlobalRouteContext {
  const character = resolveReturnCharacter(getFirstValue(value));
  const characterRoutes = getCharacterRoutes(character.slug);
  const chatUrl = characterRoutes.chat;

  return Object.freeze({
    characterSlug: character.slug,
    chatUrl,
    splashUrl: characterRoutes.splash,
    profileUrl: buildGlobalPageUrl(ROUTES.profile, chatUrl),
    feedbackUrl: buildGlobalPageUrl(ROUTES.feedback, chatUrl),
    coinsRulesUrl: buildGlobalPageUrl(ROUTES.coinsRules, chatUrl),
  });
}

export function buildGlobalPageUrl(
  route: GlobalPageRoute,
  returnTo: string,
): string {
  const safeReturnTo = resolveGlobalRouteContextValue(returnTo);
  const params = new URLSearchParams({
    [GLOBAL_RETURN_TO_PARAM]: safeReturnTo,
  });
  return `${route}?${params.toString()}`;
}

export function resolveGlobalRouteContextValue(
  value?: GlobalReturnToValue,
): string {
  const character = resolveReturnCharacter(getFirstValue(value));
  return getCharacterRoutes(character.slug).chat;
}

function resolveReturnCharacter(value: string | null): CharacterProfile {
  const match = value?.match(/^\/characters\/([^/?#]+)\/chat$/);
  if (!match?.[1]) return DEFAULT_CHARACTER;
  return getCharacterBySlug(match[1]) ?? DEFAULT_CHARACTER;
}

function getFirstValue(value: GlobalReturnToValue): string | null {
  if (typeof value === "string") return value;
  if (Array.isArray(value)) return value[0] ?? null;
  return null;
}
