import React, { createContext, useContext, useState, useCallback, useRef, ReactNode } from 'react';
import { useEditor } from '@craftjs/core';
import { PageData } from '../types';
import { SerializedTreeNode } from '../types/sitesmith';
import { useSiteDesign, SiteDesign } from './SiteDesignContext';

interface PageContextValue {
  pages: PageData[];
  headerPage: PageData;
  footerPage: PageData;
  activePageId: string;
  isEditingHeader: boolean;
  isEditingFooter: boolean;
  switchPage: (pageId: string) => void;
  editHeader: () => void;
  editFooter: () => void;
  addPage: (name: string, slug: string) => void;
  deletePage: (pageId: string) => void;
  renamePage: (pageId: string, name: string, slug: string) => void;
  setHeaderCraftState: (craftState: string) => void;
  setFooterCraftState: (craftState: string) => void;
  setPagesCraftState: (pagesData: { id: string; name: string; slug: string; craftState: string | null }[]) => void;
  /** AI helpers — replace entire site or page with a new tree */
  replaceAllPages: (pages: { name: string; tree: SerializedTreeNode }[]) => void;
  replaceCurrentPage: (page: { name: string; tree: SerializedTreeNode }) => void;
  setHeader: (tree: SerializedTreeNode) => void;
  setFooter: (tree: SerializedTreeNode) => void;
  siteDesign: SiteDesign;
}

const HEADER_ID = '__header__';
const FOOTER_ID = '__footer__';

const EMPTY_CANVAS =
  '{"ROOT":{"type":{"resolvedName":"Container"},"isCanvas":true,"props":{"style":{"minHeight":"100vh","backgroundColor":"#ffffff"},"tag":"div"},"displayName":"Container","custom":{},"hidden":false,"nodes":[],"linkedNodes":{}}}';

const EMPTY_HEADER =
  '{"ROOT":{"type":{"resolvedName":"Container"},"isCanvas":true,"props":{"style":{"minHeight":"60px","backgroundColor":"#ffffff","padding":"12px 24px","display":"flex","alignItems":"center"},"tag":"header"},"displayName":"Container","custom":{},"hidden":false,"nodes":[],"linkedNodes":{}}}';

const EMPTY_FOOTER =
  '{"ROOT":{"type":{"resolvedName":"Container"},"isCanvas":true,"props":{"style":{"minHeight":"60px","backgroundColor":"#0f172a","color":"#94a3b8","padding":"40px 24px","textAlign":"center"},"tag":"footer"},"displayName":"Container","custom":{},"hidden":false,"nodes":[],"linkedNodes":{}}}';

const PageContext = createContext<PageContextValue>({
  pages: [],
  headerPage: { id: HEADER_ID, name: 'Header', slug: '__header__', craftState: null, headCode: '' },
  footerPage: { id: FOOTER_ID, name: 'Footer', slug: '__footer__', craftState: null, headCode: '' },
  activePageId: 'home',
  isEditingHeader: false,
  isEditingFooter: false,
  switchPage: () => {},
  editHeader: () => {},
  editFooter: () => {},
  addPage: () => {},
  deletePage: () => {},
  renamePage: () => {},
  setHeaderCraftState: () => {},
  setFooterCraftState: () => {},
  setPagesCraftState: () => {},
  replaceAllPages: () => {},
  replaceCurrentPage: () => {},
  setHeader: () => {},
  setFooter: () => {},
  siteDesign: {} as SiteDesign,
});

export const usePages = () => useContext(PageContext);

function slugify(name: string): string {
  return name
    .toLowerCase()
    .trim()
    .replace(/[^a-z0-9\s-]/g, '')
    .replace(/\s+/g, '-')
    .replace(/-+/g, '-');
}

const DEFAULT_PAGE: PageData = {
  id: 'home',
  name: 'Home',
  slug: 'index',
  craftState: null,
  headCode: '',
};

const DEFAULT_HEADER: PageData = {
  id: HEADER_ID,
  name: 'Header',
  slug: '__header__',
  craftState: null,
  headCode: '',
};

const DEFAULT_FOOTER: PageData = {
  id: FOOTER_ID,
  name: 'Footer',
  slug: '__footer__',
  craftState: null,
  headCode: '',
};

export const PageProvider: React.FC<{ children: ReactNode }> = ({ children }) => {
  const { query, actions } = useEditor();
  const { design } = useSiteDesign();
  const [pages, setPages] = useState<PageData[]>([DEFAULT_PAGE]);
  const [headerPage, setHeaderPage] = useState<PageData>(DEFAULT_HEADER);
  const [footerPage, setFooterPage] = useState<PageData>(DEFAULT_FOOTER);
  const [activePageId, setActivePageId] = useState('home');
  const activePageIdRef = useRef(activePageId);
  activePageIdRef.current = activePageId;

  const isEditingHeader = activePageId === HEADER_ID;
  const isEditingFooter = activePageId === FOOTER_ID;

  /** Save whatever is on the current Frame back to the right state slot */
  const saveCurrentState = useCallback(() => {
    const currentState = query.serialize();
    const currentId = activePageIdRef.current;

    if (currentId === HEADER_ID) {
      setHeaderPage((prev) => ({ ...prev, craftState: currentState }));
    } else if (currentId === FOOTER_ID) {
      setFooterPage((prev) => ({ ...prev, craftState: currentState }));
    } else {
      setPages((prev) =>
        prev.map((p) => (p.id === currentId ? { ...p, craftState: currentState } : p)),
      );
    }
  }, [query]);

  /** Load a craft state into the Frame */
  const loadState = useCallback(
    (craftState: string | null, fallback: string) => {
      setTimeout(() => {
        try {
          actions.deserialize(craftState || fallback);
        } catch (e) {
          console.error('Failed to deserialize state:', e);
          try {
            actions.deserialize(fallback);
          } catch (_e2) {
            // give up
          }
        }
      }, 0);
    },
    [actions],
  );

  const switchPage = useCallback(
    (pageId: string) => {
      if (pageId === activePageIdRef.current) return;

      // Serialize the current Craft.js state synchronously BEFORE switching
      const currentState = query.serialize();
      const currentId = activePageIdRef.current;

      // Persist the serialized state to the correct page slot
      if (currentId === HEADER_ID) {
        setHeaderPage((prev) => ({ ...prev, craftState: currentState }));
      } else if (currentId === FOOTER_ID) {
        setFooterPage((prev) => ({ ...prev, craftState: currentState }));
      } else {
        setPages((prev) =>
          prev.map((p) => (p.id === currentId ? { ...p, craftState: currentState } : p)),
        );
      }

      // Load target page state.
      // For header/footer we need the latest saved state. Since setState above is async,
      // read from the ref-like state getter. For header/footer, we read the current
      // state value and fall back to what we just saved if the target is the same slot.
      if (pageId === HEADER_ID) {
        // Use functional state read to get the latest value
        setHeaderPage((prev) => {
          loadState(prev.craftState, EMPTY_HEADER);
          return prev;
        });
      } else if (pageId === FOOTER_ID) {
        setFooterPage((prev) => {
          loadState(prev.craftState, EMPTY_FOOTER);
          return prev;
        });
      } else {
        setPages((prev) => {
          const target = prev.find((p) => p.id === pageId);
          loadState(target?.craftState || null, EMPTY_CANVAS);
          return prev;
        });
      }

      setActivePageId(pageId);
      activePageIdRef.current = pageId;
    },
    [query, loadState],
  );

  const editHeader = useCallback(() => {
    switchPage(HEADER_ID);
  }, [switchPage]);

  const editFooter = useCallback(() => {
    switchPage(FOOTER_ID);
  }, [switchPage]);

  const addPage = useCallback(
    (name: string, slug: string) => {
      const finalSlug = slug || slugify(name);
      const id = `page_${Date.now()}`;

      // Save current page first
      saveCurrentState();

      setPages((prev) => [
        ...prev,
        {
          id,
          name,
          slug: finalSlug,
          craftState: null,
          headCode: '',
        },
      ]);

      // Switch to the new page with empty canvas
      loadState(null, EMPTY_CANVAS);

      setActivePageId(id);
      activePageIdRef.current = id;
    },
    [saveCurrentState, loadState],
  );

  const deletePage = useCallback(
    (pageId: string) => {
      // Can't delete header/footer
      if (pageId === HEADER_ID || pageId === FOOTER_ID) return;

      setPages((prev) => {
        if (prev.length <= 1) return prev;

        const filtered = prev.filter((p) => p.id !== pageId);

        // If deleting the active page, switch to the first remaining
        if (pageId === activePageIdRef.current) {
          const nextPage = filtered[0];
          setActivePageId(nextPage.id);
          activePageIdRef.current = nextPage.id;
          loadState(nextPage.craftState, EMPTY_CANVAS);
        }

        return filtered;
      });
    },
    [loadState],
  );

  const renamePage = useCallback((pageId: string, name: string, slug: string) => {
    setPages((prev) =>
      prev.map((p) =>
        p.id === pageId ? { ...p, name, slug: slug || slugify(name) } : p,
      ),
    );
  }, []);

  /** Allow external code (e.g., load from API) to set the header craft state */
  const setHeaderCraftState = useCallback((craftState: string) => {
    setHeaderPage((prev) => ({ ...prev, craftState }));
  }, []);

  /** Allow external code (e.g., load from API) to set the footer craft state */
  const setFooterCraftState = useCallback((craftState: string) => {
    setFooterPage((prev) => ({ ...prev, craftState }));
  }, []);

  /** Allow external code (e.g., load from API) to restore pages with craft states */
  const setPagesCraftState = useCallback((pagesData: { id: string; name: string; slug: string; craftState: string | null }[]) => {
    setPages(pagesData.map((p) => ({
      id: p.id,
      name: p.name,
      slug: p.slug,
      craftState: p.craftState,
      headCode: '',
    })));
  }, []);

  /** Flatten a SerializedTreeNode into a Craft.js SerializedNodes JSON string */
  const treeToState = useCallback((tree: SerializedTreeNode): string => {
    let counter = 0;
    const nodes: Record<string, unknown> = {};
    const walk = (node: SerializedTreeNode, parent: string | null): string => {
      const id = (node.props.node_id as string | undefined) || `ai-auto-${counter++}`;
      const childIds: string[] = [];
      nodes[id] = {
        type: node.type,
        isCanvas: true,
        props: node.props,
        displayName: node.type.resolvedName,
        custom: {},
        hidden: false,
        parent,
        nodes: childIds,
        linkedNodes: {},
      };
      for (const child of node.nodes ?? []) {
        childIds.push(walk(child, id));
      }
      return id;
    };
    const rootId = walk(tree, null);
    // Craft.js deserialize requires the root node keyed as 'ROOT'
    if (rootId !== 'ROOT') {
      nodes['ROOT'] = nodes[rootId];
      (nodes['ROOT'] as any).parent = null;
      delete nodes[rootId];
      // Fix up parent references from ROOT's children
      for (const childId of (nodes['ROOT'] as any).nodes) {
        if (nodes[childId]) (nodes[childId] as any).parent = 'ROOT';
      }
    }
    return JSON.stringify(nodes);
  }, []);

  /**
   * AI helper: replace all pages with newly generated trees.
   * Stores each page's serialized state without touching the live canvas
   * (the canvas still shows the currently active page — call switchPage() if needed).
   */
  const replaceAllPages = useCallback((newPages: { name: string; tree: SerializedTreeNode }[]) => {
    if (newPages.length === 0) return;
    const built = newPages.map((p, i) => ({
      id: i === 0 ? 'home' : `page_${Date.now()}_${i}`,
      name: p.name,
      slug: slugify(p.name),
      craftState: treeToState(p.tree),
      headCode: '',
    }));
    setPages(built);
    // Load the first page into the live canvas
    const firstState = built[0].craftState;
    setActivePageId(built[0].id);
    activePageIdRef.current = built[0].id;
    loadState(firstState, EMPTY_CANVAS);
  }, [treeToState, loadState]);

  /**
   * AI helper: replace the current page's tree.
   * Deserializes the new tree into the live Craft.js canvas and persists it.
   */
  const replaceCurrentPage = useCallback((page: { name: string; tree: SerializedTreeNode }) => {
    const craftState = treeToState(page.tree);
    const currentId = activePageIdRef.current;
    if (currentId === HEADER_ID) {
      setHeaderPage((prev) => ({ ...prev, name: page.name, craftState }));
    } else if (currentId === FOOTER_ID) {
      setFooterPage((prev) => ({ ...prev, name: page.name, craftState }));
    } else {
      setPages((prev) =>
        prev.map((p) => (p.id === currentId ? { ...p, name: page.name, craftState } : p)),
      );
    }
    loadState(craftState, EMPTY_CANVAS);
  }, [treeToState, loadState]);

  /**
   * AI helper: replace the shared header tree.
   * Updates stored state; does NOT switch the canvas to header view.
   */
  const setHeader = useCallback((tree: SerializedTreeNode) => {
    const craftState = treeToState(tree);
    setHeaderPage((prev) => ({ ...prev, craftState }));
    // If the canvas is currently showing the header, refresh it live
    if (activePageIdRef.current === HEADER_ID) {
      loadState(craftState, EMPTY_HEADER);
    }
  }, [treeToState, loadState]);

  /**
   * AI helper: replace the shared footer tree.
   * Updates stored state; does NOT switch the canvas to footer view.
   */
  const setFooter = useCallback((tree: SerializedTreeNode) => {
    const craftState = treeToState(tree);
    setFooterPage((prev) => ({ ...prev, craftState }));
    // If the canvas is currently showing the footer, refresh it live
    if (activePageIdRef.current === FOOTER_ID) {
      loadState(craftState, EMPTY_FOOTER);
    }
  }, [treeToState, loadState]);

  return (
    <PageContext.Provider
      value={{
        pages,
        headerPage,
        footerPage,
        activePageId,
        isEditingHeader,
        isEditingFooter,
        switchPage,
        editHeader,
        editFooter,
        addPage,
        deletePage,
        renamePage,
        setHeaderCraftState,
        setFooterCraftState,
        setPagesCraftState,
        replaceAllPages,
        replaceCurrentPage,
        setHeader,
        setFooter,
        siteDesign: design,
      }}
    >
      {children}
    </PageContext.Provider>
  );
};
