import { useCallback } from 'react';
import { useEditor } from '@craftjs/core';
import { useEditorConfig } from '../state/EditorConfigContext';
import { usePages } from '../state/PageContext';
import { exportBodyHtml } from '../utils/html-export';
import { PageData } from '../types';

export interface BuildSavePayloadInput {
  siteId: number;
  siteName: string;
  /** query.serialize() of whatever is currently on the live canvas. */
  liveCraftState: string;
  pages: PageData[];
  headerPage: PageData;
  footerPage: PageData;
  activePageId: string;
  /** True when the live canvas is showing the header zone (activePageId === '__header__'). */
  isEditingHeader: boolean;
  /** True when the live canvas is showing the footer zone (activePageId === '__footer__'). */
  isEditingFooter: boolean;
}

/**
 * Pure payload builder for the save() API call. Extracted so the
 * header/footer-vs-page routing logic can be unit-tested without mounting
 * React/Craft.js.
 *
 * Bug this fixes: when the user is editing the Header or Footer,
 * `activePageId` is `'__header__'`/`'__footer__'` — which matches no entry
 * in `pages`. The live canvas serialization must be routed into
 * `header_craft_state`/`footer_craft_state` in that case, NOT into a page
 * slot or the top-level `craft_state`/`html` (which must always represent
 * an actual page). Conversely, header/footer must be sourced from the FRESH
 * live state when that zone is being edited, not from the stale stored
 * `headerPage.craftState`/`footerPage.craftState`.
 */
export function buildSavePayload(input: BuildSavePayloadInput) {
  const {
    siteId,
    siteName,
    liveCraftState,
    pages,
    headerPage,
    footerPage,
    activePageId,
    isEditingHeader,
    isEditingFooter,
  } = input;

  const isPageActive = !isEditingHeader && !isEditingFooter;

  // Fresh header/footer state: the live canvas wins when that zone is the
  // one currently being edited; otherwise fall back to the last-committed
  // stored state (updated on zone switch by PageContext's saveCurrentState).
  const headerCraftState = isEditingHeader ? liveCraftState : (headerPage.craftState || null);
  const footerCraftState = isEditingFooter ? liveCraftState : (footerPage.craftState || null);

  let headerHtml = '';
  try {
    if (headerCraftState) {
      headerHtml = exportBodyHtml(headerCraftState).html;
    }
  } catch (e) {
    console.error('Header HTML export failed:', e);
  }

  let footerHtml = '';
  try {
    if (footerCraftState) {
      footerHtml = exportBodyHtml(footerCraftState).html;
    }
  } catch (e) {
    console.error('Footer HTML export failed:', e);
  }

  // The top-level `craft_state`/`html` fields (and the matching per-page
  // slot below) must always represent an actual PAGE. When editing the
  // header/footer, activePageId matches no page — use the landing page's
  // own stored state instead of leaking the live header/footer canvas into
  // a page slot or mislabeling it as page content.
  let currentCraftState: string | null;
  let currentHtml = '';
  let css = '';

  if (isPageActive) {
    currentCraftState = liveCraftState;
    try {
      const result = exportBodyHtml(currentCraftState);
      currentHtml = result.html;
      css = result.css;
    } catch (e) {
      console.error('HTML export failed, saving state only:', e);
    }
  } else {
    const landingPage = pages[0] ?? null;
    currentCraftState = landingPage?.craftState ?? null;
    try {
      if (currentCraftState) {
        const result = exportBodyHtml(currentCraftState);
        currentHtml = result.html;
        css = result.css;
      }
    } catch (e) {
      console.error('HTML export failed, saving state only:', e);
    }
  }

  // Build the pages array with HTML for each page. For the active page (only
  // possible when a real page is active), use the freshly exported HTML from
  // the canvas; for others, export from their stored craft state.
  const pagesPayload = pages.map((page, i) => {
    // The first page is ALWAYS the landing page → publishes to index.html
    // regardless of the page name/slug. Apache serves '/' from index.html,
    // and renaming the first page should not break the root URL.
    const filename = i === 0 ? 'index.html' : page.slug + '.html';
    let pageHtml = '';

    if (isPageActive && page.id === activePageId) {
      // Active page: use the current canvas HTML (already exported above)
      pageHtml = currentHtml;
    } else if (page.craftState) {
      try {
        pageHtml = exportBodyHtml(page.craftState).html;
      } catch (e) {
        console.error(`HTML export failed for page ${page.name}:`, e);
      }
    }

    return {
      filename,
      title: page.name,
      html: pageHtml,
    };
  });

  // Build pages_craft_state array: for each page, store its craft state.
  // For the currently active page (only when a real page is active), always
  // use the fresh canvas state since page.craftState may be stale (not
  // updated until page switch). When editing header/footer, activePageId
  // matches no page, so every page correctly falls back to its own stored
  // state below.
  const pagesGrapesjs = pages.map((page, i) => ({
    id: page.id,
    name: page.name,
    // Pin the landing page's slug to 'index' on the wire too, so that on
    // reload the editor's clean-URL routing (.htaccess rewrite of /name →
    // name.html) lines up with the file we just wrote (index.html).
    slug: i === 0 ? 'index' : page.slug,
    craftState: (isPageActive && page.id === activePageId) ? liveCraftState : (page.craftState || null),
  }));

  return {
    site_id: siteId,
    name: siteName,
    html: currentHtml,
    css,
    pages: pagesPayload,
    header_html: headerHtml,
    footer_html: footerHtml,
    craft_state: currentCraftState,
    header_craft_state: headerCraftState,
    footer_craft_state: footerCraftState,
    pages_craft_state: pagesGrapesjs,
  };
}

export function useWhpApi() {
  const { query, actions } = useEditor();
  const { whpConfig, isWHP } = useEditorConfig();
  const {
    pages,
    headerPage,
    footerPage,
    activePageId,
    isEditingHeader,
    isEditingFooter,
    setHeaderCraftState,
    setFooterCraftState,
    setPagesCraftState,
  } = usePages();

  const save = useCallback(async () => {
    if (!isWHP || !whpConfig) return null;

    // Serialize whatever is currently on the live canvas (a page, the
    // header, or the footer — depending on activePageId/isEditingHeader/
    // isEditingFooter).
    const liveCraftState = query.serialize();

    const payload = buildSavePayload({
      siteId: whpConfig.siteId,
      siteName: whpConfig.siteName,
      liveCraftState,
      pages,
      headerPage,
      footerPage,
      activePageId,
      isEditingHeader,
      isEditingFooter,
    });

    const resp = await fetch(`${whpConfig.apiUrl}?action=save`, {
      method: 'POST',
      headers: {
        'Content-Type': 'application/json',
        'X-CSRF-Token': whpConfig.csrfToken,
      },
      body: JSON.stringify(payload),
    });
    return resp.json();
  }, [isWHP, whpConfig, query, pages, activePageId, headerPage, footerPage, isEditingHeader, isEditingFooter]);

  const publish = useCallback(async () => {
    if (!isWHP || !whpConfig) return null;

    // First save to ensure staging is up to date
    await save();

    // Then publish from staging to live
    const resp = await fetch(
      `${whpConfig.apiUrl}?action=publish&site_id=${whpConfig.siteId}`,
      {
        method: 'POST',
        headers: {
          'Content-Type': 'application/json',
          'X-CSRF-Token': whpConfig.csrfToken,
        },
        body: JSON.stringify({ site_id: whpConfig.siteId }),
      },
    );
    return resp.json();
  }, [isWHP, whpConfig, save]);

  const load = useCallback(async () => {
    if (!isWHP || !whpConfig) return null;

    const resp = await fetch(
      `${whpConfig.apiUrl}?action=load&site_id=${whpConfig.siteId}`,
    );
    const data = await resp.json();

    if (data.success && data.project) {
      const proj = data.project;

      // Restore header craft state
      if (proj.header_craft_state) {
        setHeaderCraftState(typeof proj.header_craft_state === 'string'
          ? proj.header_craft_state : JSON.stringify(proj.header_craft_state));
      }

      // Restore footer craft state
      if (proj.footer_craft_state) {
        setFooterCraftState(typeof proj.footer_craft_state === 'string'
          ? proj.footer_craft_state : JSON.stringify(proj.footer_craft_state));
      }

      // Restore pages and load the first page into the canvas
      if (proj.pages_craft_state && Array.isArray(proj.pages_craft_state) && proj.pages_craft_state.length > 0) {
        setPagesCraftState(proj.pages_craft_state.map((p: { id: string; name: string; slug: string; craftState: string | null }) => ({
          id: p.id, name: p.name, slug: p.slug, craftState: p.craftState || null,
        })));

        // Load the first page (home) into the canvas
        const firstPage = proj.pages_craft_state[0];
        if (firstPage.craftState) {
          try {
            const state = typeof firstPage.craftState === 'string'
              ? firstPage.craftState : JSON.stringify(firstPage.craftState);
            actions.deserialize(state);
          } catch (e) {
            console.warn('Failed to load page state:', e);
          }
        }
      }
    }
    return data;
  }, [isWHP, whpConfig, actions, setHeaderCraftState, setFooterCraftState, setPagesCraftState]);

  const uploadAsset = useCallback(
    async (file: File) => {
      if (!isWHP || !whpConfig) return null;

      const formData = new FormData();
      formData.append('file', file);

      const resp = await fetch(
        `${whpConfig.apiUrl}?action=upload_asset&site_id=${whpConfig.siteId}`,
        {
          method: 'POST',
          headers: { 'X-CSRF-Token': whpConfig.csrfToken },
          body: formData,
        },
      );
      return resp.json();
    },
    [isWHP, whpConfig],
  );

  return { save, publish, load, uploadAsset, isWHP };
}
