// SPEC: PJ2026-010405 云端控制台.
// Implementation reference: draft-2026-07-13-p0-cloud-console.

import { computed, type ComputedRef } from "vue";
import { useRoute, useRouter, type LocationQueryRaw } from "vue-router";

export type ConsoleCollectionView = "cards" | "list";
export type ConsoleCollectionDensity = "compact" | "comfortable";

export interface ConsoleViewStateDefaults<
  TView extends string = ConsoleCollectionView,
> {
  view?: TView;
  viewValues?: readonly TView[];
  density?: ConsoleCollectionDensity;
  q?: string;
  filter?: string;
  sort?: string;
  cursor?: string;
  tab?: string;
}

export type ConsoleViewStatePatch<
  TView extends string = ConsoleCollectionView,
> = Omit<ConsoleViewStateDefaults<TView>, "viewValues">;

export interface ConsoleViewState<
  TView extends string = ConsoleCollectionView,
> {
  view: ComputedRef<TView>;
  density: ComputedRef<ConsoleCollectionDensity>;
  q: ComputedRef<string>;
  filter: ComputedRef<string>;
  sort: ComputedRef<string>;
  cursor: ComputedRef<string>;
  tab: ComputedRef<string>;
  update: (
    patch: Partial<ConsoleViewStatePatch<TView>>,
    replace?: boolean,
  ) => Promise<void>;
}

export function useConsoleViewState(): ConsoleViewState<ConsoleCollectionView>;
export function useConsoleViewState(
  defaults: ConsoleViewStateDefaults<ConsoleCollectionView>,
): ConsoleViewState<ConsoleCollectionView>;
export function useConsoleViewState<TView extends string>(
  defaults: ConsoleViewStateDefaults<TView> & {
    view: TView;
    viewValues: readonly TView[];
  },
): ConsoleViewState<TView>;
export function useConsoleViewState<
  TView extends string = ConsoleCollectionView,
>(defaults: ConsoleViewStateDefaults<TView> = {}): ConsoleViewState<TView> {
  const route = useRoute();
  const router = useRouter();
  const viewValues =
    defaults.viewValues ?? (["cards", "list"] as unknown as readonly TView[]);
  const defaultView = defaults.view ?? viewValues[0] ?? ("cards" as TView);

  const view = computed<TView>(() =>
    queryEnum(route.query.view, viewValues, defaultView),
  );
  const density = computed(() =>
    queryEnum(
      route.query.density,
      ["compact", "comfortable"] as const,
      defaults.density ?? "comfortable",
    ),
  );
  const q = computed(() => queryText(route.query.q) || defaults.q || "");
  const filter = computed(
    () => queryText(route.query.filter) || defaults.filter || "",
  );
  const sort = computed(
    () => queryText(route.query.sort) || defaults.sort || "",
  );
  const cursor = computed(
    () => queryText(route.query.cursor) || defaults.cursor || "",
  );
  const tab = computed(() => queryText(route.query.tab) || defaults.tab || "");

  async function update(
    patch: Partial<ConsoleViewStatePatch<TView>>,
    replace = true,
  ): Promise<void> {
    const query: LocationQueryRaw = { ...route.query };
    for (const [key, value] of Object.entries(patch)) {
      if (value === undefined || value === null || value === "")
        delete query[key];
      else query[key] = value;
    }
    if ("q" in patch || "filter" in patch || "sort" in patch)
      delete query.cursor;
    const location = { path: route.path, query, hash: route.hash };
    if (router.resolve(location).fullPath === route.fullPath) return;
    if (replace) await router.replace(location);
    else await router.push(location);
  }

  return { view, density, q, filter, sort, cursor, tab, update };
}

function queryText(value: unknown): string {
  if (Array.isArray(value)) return queryText(value[0]);
  return typeof value === "string" ? value.trim() : "";
}

function queryEnum<T extends string>(
  value: unknown,
  allowed: readonly T[],
  fallback: T,
): T {
  const text = queryText(value);
  return allowed.includes(text as T) ? (text as T) : fallback;
}
