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

export type PageAggregateClientPageSubtreeSource = "server" | "local" | "none";

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

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

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

function withResolvedPageSubtreeTitle(
  pageSubtree: PageSubtreeProjection,
  title: string,
): PageSubtreeProjection {
  const normalizedTitle = normalizePageTitle(title);
  if (normalizePageTitle(pageSubtree.rootNode.metadata.title) === normalizedTitle) {
    return pageSubtree;
  }
  return {
    ...pageSubtree,
    rootNode: {
      ...pageSubtree.rootNode,
      metadata: {
        ...pageSubtree.rootNode.metadata,
        title: normalizedTitle,
      },
    },
  };
}

export function createPageAggregateClientState(
  page: PageAggregateProjection,
): PageAggregateClientState {
  return {
    documentId: page.identity.documentId,
    serverPageTitle: normalizePageTitle(page.head.title),
    persistedPageTitle: null,
    draftPageTitle: null,
    options: page.layout.pageOptions,
    content: page.body.content,
    serverContentSnapshot: page.body.content,
    serverPageSubtreeSnapshot: page.tree.pageSubtree,
    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 "set_draft_page_title":
      return {
        ...state,
        draftPageTitle: action.title,
      };
    case "commit_persisted_page_title": {
      const normalizedTitle = normalizePageTitle(action.title);
      return {
        ...state,
        persistedPageTitle: normalizedTitle,
        draftPageTitle: normalizedTitle,
      };
    }
    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,
      };
    default:
      return state;
  }
}

export function selectPageAggregateClientTitleState(
  state: PageAggregateClientState,
  input: {
    liveSidebarTitle: string | null;
  },
): {
  displayTitle: string;
  committedTitle: string;
  hasDraft: boolean;
} {
  const liveCommittedTitle = normalizePageTitle(input.liveSidebarTitle ?? state.serverPageTitle);
  const committedTitle =
    state.persistedPageTitle != null &&
    normalizePageTitle(state.persistedPageTitle) !== liveCommittedTitle
      ? normalizePageTitle(state.persistedPageTitle)
      : liveCommittedTitle;
  const hasDraft =
    state.draftPageTitle != null &&
    normalizePageTitle(state.draftPageTitle) !== committedTitle;

  return {
    displayTitle: hasDraft ? state.draftPageTitle ?? committedTitle : committedTitle,
    committedTitle,
    hasDraft,
  };
}

export function selectPageAggregateClientPageSubtree(
  state: PageAggregateClientState,
  input: {
    liveSidebarTitle: string | null;
  },
): PageSubtreeProjection | null {
  return selectPageAggregateClientPageSubtreeState(state, input).pageSubtree;
}

export function selectPageAggregateClientPageSubtreeState(
  state: PageAggregateClientState,
  input: {
    liveSidebarTitle: string | null;
  },
): {
  pageSubtree: PageSubtreeProjection | null;
  source: PageAggregateClientPageSubtreeSource;
} {
  const titleState = selectPageAggregateClientTitleState(state, input);
  const contentUnchanged = state.content === state.serverContentSnapshot;

  if (state.serverPageSubtreeSnapshot && !titleState.hasDraft && contentUnchanged) {
    return {
      pageSubtree: withResolvedPageSubtreeTitle(state.serverPageSubtreeSnapshot, titleState.committedTitle),
      source: "server",
    };
  }

  if (state.content != null) {
    return {
      pageSubtree: buildPageSubtreeProjection({
        documentId: state.documentId,
        title: titleState.displayTitle,
        content: state.content,
      }),
      source: "local",
    };
  }

  return {
    pageSubtree: null,
    source: "none",
  };
}

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

  return {
    blocks,
    pageSubtree: pageSubtreeState.pageSubtree,
    pageSubtreeSource: pageSubtreeState.source,
    persistedMeta: {
      workspaceId: input.workspaceId,
      revision: state.contentRevision,
      conflictDetectionKey: state.conflictDetectionKey,
    },
    pageOptions: state.options,
  };
}
