import { normalizeCourseCoreSkillsContent } from "@/components/page-blocks/CourseCoreSkillsBlock";
import { normalizeCourseHeroContent } from "@/components/page-blocks/course-hero/normalizeContent";
import { normalizeHowEachCourseSeesContent } from "@/components/page-blocks/how-each-course-sees/normalizeContent";
import { normalizeHeroContent } from "@/components/page-blocks/hero/normalizeContent";
import { normalizeGradeHeroContent } from "@/components/page-blocks/GradeHeroBlock";
import { normalizeParentCourseOverviewContent } from "@/components/page-blocks/parent-course-overview/parseContent";
import { normalizeApiQueryFilters } from "@/lib/apiQueryFilters";
import { cloneBlockContent } from "@/lib/cloneBlockContent";
import { normalizeOptionalObjectArrays } from "@/lib/contentFormUtils";
import type { ContentPlaceholderVars } from "@/lib/contentPlaceholders";
import { resolveBlockContentForRender } from "@/lib/contentPlaceholders";

export type ComponentLibraryRecord = {
  id: number;
  slug: string;
  name?: string;
  content?: Record<string, unknown> | null;
};

function isPlainObject(value: unknown): value is Record<string, unknown> {
  return typeof value === "object" && value !== null && !Array.isArray(value);
}

function isEmptyOverride(value: unknown): boolean {
  if (value === null || value === undefined) return true;
  if (typeof value === "string" && value.trim() === "") return true;
  return false;
}

const HOW_EACH_COURSE_SEES_SLUGS = new Set([
  "how-each-course-sees",
  "quarter-courses",
  "quarter-learning-tabs",
  "quarter-courses-and-learning",
]);

/** Bottom-nav fields where "" is an intentional clear (must not fall back to library defaults). */
const NAV_CLEARABLE_KEYS = [
  "navPrevLabel",
  "navPrevHref",
  "navNextLabel",
  "navNextHref",
  "navCenterLabel",
  "navCenterHref",
] as const;

function applyExplicitStringOverride(
  merged: Record<string, unknown>,
  blockContent: Record<string, unknown>,
  key: string
): void {
  if (!Object.prototype.hasOwnProperty.call(blockContent, key)) return;
  const raw = blockContent[key];
  merged[key] = typeof raw === "string" ? raw : raw == null ? "" : String(raw);
}

/** Deep-merge page block content over component library defaults (non-empty overrides win). */
export function mergeBlockContentWithDefaults(
  blockContent: Record<string, unknown>,
  libraryContent: Record<string, unknown> | null | undefined,
  componentSlug: string
): Record<string, unknown> {
  const defaults = cloneBlockContent(libraryContent ?? {}, componentSlug);
  const merged = deepMergePreferOverrides(defaults, blockContent);

  // Grade Hero: an explicit subtitle key (including "") must win over library defaults.
  // Empty string is an intentional clear and must not restore the seeded default.
  if (
    (componentSlug === "grade-hero" || componentSlug === "design-to-impact-hero")
    && Object.prototype.hasOwnProperty.call(blockContent, "subtitle")
  ) {
    applyExplicitStringOverride(merged, blockContent, "subtitle");
  }

  // How Each Course Sees: empty bottom-nav fields must win over seeded Q2 (etc.) defaults.
  if (HOW_EACH_COURSE_SEES_SLUGS.has(componentSlug)) {
    for (const key of NAV_CLEARABLE_KEYS) {
      applyExplicitStringOverride(merged, blockContent, key);
    }
  }

  return merged;
}

function deepMergePreferOverrides(
  base: Record<string, unknown>,
  overrides: Record<string, unknown>
): Record<string, unknown> {
  const out: Record<string, unknown> = { ...base };

  for (const [key, override] of Object.entries(overrides)) {
    if (isEmptyOverride(override)) continue;

    const baseValue = base[key];

    if (Array.isArray(override)) {
      if (override.length > 0) out[key] = override;
      continue;
    }

    if (isPlainObject(override) && isPlainObject(baseValue)) {
      out[key] = deepMergePreferOverrides(baseValue, override);
      continue;
    }

    out[key] = override;
  }

  return out;
}

export function findComponentLibraryContent(
  block: { componentId?: number; componentSlug?: string },
  components: ComponentLibraryRecord[],
  resolvedSlug: string
): Record<string, unknown> | undefined {
  const byId = components.find((c) => c.id === block.componentId);
  if (byId?.content && typeof byId.content === "object") {
    return byId.content as Record<string, unknown>;
  }

  const slug = block.componentSlug ?? resolvedSlug;
  const bySlug = components.find((c) => c.slug === slug || c.slug === resolvedSlug);
  return bySlug?.content && typeof bySlug.content === "object"
    ? (bySlug.content as Record<string, unknown>)
    : undefined;
}

/** Normalize block content for the editor form (library defaults + saved overrides). */
export function prepareBlockContentForEditor(
  blockContent: Record<string, unknown>,
  libraryContent: Record<string, unknown> | null | undefined,
  componentSlug: string
): Record<string, unknown> {
  const merged = mergeBlockContentWithDefaults(blockContent, libraryContent, componentSlug);

  if (componentSlug === "parent-course-overview") {
    return normalizeParentCourseOverviewContent(merged) as Record<string, unknown>;
  }
  if (componentSlug === "hero") {
    return normalizeHeroContent(merged) as Record<string, unknown>;
  }
  if (componentSlug === "grade-hero" || componentSlug === "design-to-impact-hero") {
    return normalizeGradeHeroContent(merged) as Record<string, unknown>;
  }
  if (componentSlug === "course-core-skills") {
    return normalizeCourseCoreSkillsContent(merged) as Record<string, unknown>;
  }
  if (componentSlug === "course-hero") {
    return normalizeCourseHeroContent(merged) as Record<string, unknown>;
  }
  if (
    componentSlug === "how-each-course-sees" ||
    componentSlug === "quarter-courses" ||
    componentSlug === "quarter-learning-tabs" ||
    componentSlug === "quarter-courses-and-learning"
  ) {
    return normalizeHowEachCourseSeesContent(merged) as Record<string, unknown>;
  }
  if (componentSlug === "grade-family-guides-api") {
    merged.filters = normalizeApiQueryFilters(merged.filters);
  }

  return normalizeOptionalObjectArrays(merged);
}

/**
 * Resolve block content for preview/live/editor rendering:
 * library defaults → page overrides → slug normalization → placeholders.
 */
export function resolveEditorBlockContent(
  blockContent: Record<string, unknown>,
  options: {
    blockSlug: string;
    libraryContent?: Record<string, unknown> | null;
    pageVars?: ContentPlaceholderVars;
  }
): Record<string, unknown> {
  const merged = mergeBlockContentWithDefaults(
    blockContent,
    options.libraryContent,
    options.blockSlug
  );

  return resolveBlockContentForRender(merged, options.pageVars ?? {}, {
    blockSlug: options.blockSlug,
  });
}
