import type { PageBodyPersistedMeta } from "@/lib/documents/page-command-client";
import type { PageAggregateProjection } from "@/lib/documents/page-aggregate";
import type { PageSubtreeProjection } from "@/lib/documents/page-subtree";
import type { PageOptionsState } from "@/types/page-options";
import type { Json } from "@/types/supabase";

export type PageAggregateClientState = {
  options: PageOptionsState;
  content: unknown;
  serverContentSnapshot: unknown;
  serverPageSubtreeSnapshot: PageSubtreeProjection | null;
  serverPageSubtreeTitle: string;
  contentRevision: number | null;
  conflictDetectionKey: string | null;
};

export type PageAggregateClientStateAction =
  | {
      type: "hydrate_from_page";
      page: PageAggregateProjection;
    }
  | {
      type: "patch_page_options";
      patch: Partial<PageOptionsState>;
    }
  | {
      type: "apply_local_content_snapshot";
      content: unknown;
    }
  | {
      type: "apply_persisted_body_meta";
      meta: PageBodyPersistedMeta;
    }
  | {
      type: "update_server_page_subtree_title";
      title: string;
    };

function normalizePageTitle(title: string | null | undefined): string {
  const normalized = String(title ?? "").trim();
  return normalized || "无标题";
}

function resolveServerPageSubtreeTitle(page: PageAggregateProjection): string {
  const subtreeTitle = page.tree.pageSubtree?.rootNode.metadata.title;
  if (typeof subtreeTitle === "string" && subtreeTitle.trim()) {
    return subtreeTitle.trim();
  }
  return normalizePageTitle(page.head.title);
}

export function createPageAggregateClientState(
  page: PageAggregateProjection,
): PageAggregateClientState {
  return {
    options: page.layout.pageOptions,
    content: page.body.content,
    serverContentSnapshot: page.body.content,
    serverPageSubtreeSnapshot: page.tree.pageSubtree,
    serverPageSubtreeTitle: resolveServerPageSubtreeTitle(page),
    contentRevision: page.body.revision,
    conflictDetectionKey: page.body.conflictDetectionKey,
  };
}

export function pageAggregateClientStateReducer(
  state: PageAggregateClientState,
  action: PageAggregateClientStateAction,
): PageAggregateClientState {
  switch (action.type) {
    case "hydrate_from_page":
      return createPageAggregateClientState(action.page);
    case "patch_page_options":
      return {
        ...state,
        options: {
          ...state.options,
          ...action.patch,
        },
      };
    case "apply_local_content_snapshot":
      return {
        ...state,
        content: action.content,
      };
    case "apply_persisted_body_meta":
      return {
        ...state,
        contentRevision: action.meta.revision,
        conflictDetectionKey: action.meta.conflictDetectionKey,
      };
    case "update_server_page_subtree_title":
      return {
        ...state,
        serverPageSubtreeTitle: normalizePageTitle(action.title),
      };
    default:
      return state;
  }
}

export function selectPageAggregateClientPageSubtree(
  state: PageAggregateClientState,
  pageTitle: string,
): PageSubtreeProjection | null {
  const hasServerPageSubtree = Boolean(state.serverPageSubtreeSnapshot);
  const titleUnchanged = normalizePageTitle(pageTitle) === state.serverPageSubtreeTitle;
  const contentUnchanged = state.content === state.serverContentSnapshot;

  if (hasServerPageSubtree && titleUnchanged && contentUnchanged) {
    return state.serverPageSubtreeSnapshot;
  }
  return null;
}

export function selectPageAggregateClientAiSnapshot(
  state: PageAggregateClientState,
  input: {
    workspaceId: string | null;
    pageTitle: string;
  },
): {
  blocks: Json | null;
  pageSubtree: PageSubtreeProjection | null;
  persistedMeta: {
    workspaceId: string | null;
    revision: number | null;
    conflictDetectionKey: string | null;
  };
  pageOptions: PageOptionsState;
} {
  const blocks = state.content as Json | null;

  return {
    blocks,
    pageSubtree: selectPageAggregateClientPageSubtree(state, input.pageTitle),
    persistedMeta: {
      workspaceId: input.workspaceId,
      revision: state.contentRevision,
      conflictDetectionKey: state.conflictDetectionKey,
    },
    pageOptions: state.options,
  };
}
