'use client'

import { useState, useEffect, useCallback, useRef } from 'react'
import { Loader2, AlertTriangle } from 'lucide-react'
import { toast } from 'sonner'
import { cmsApi } from '../../lib/api.js'
import { useNavigationBlocker } from '../../router/index.js'
import { ErrorBoundary } from '../../components/ErrorBoundary.js'
import {
  useBuilderState,
  type BuilderState,
  type BuilderActions,
  type PageSettings,
} from '../../hooks/useBuilderState.js'
import type { PageNode } from '@actuate-media/cms-core'
import { BuilderToolbar } from './BuilderToolbar.js'
import { BottomBar } from './BottomBar.js'
import { BuilderCanvas } from './canvas/index.js'
import { BuilderSectionsPanel } from './BuilderSectionsPanel.js'
import { ContextPanel } from './ContextPanel.js'
import { AIGenerateDialog } from './AIGenerateDialog.js'

export interface PageBuilderProps {
  documentId?: string
  /** Seed a NEW page from a saved template (`/page-builder/new?template=<id>`). */
  templateId?: string
  collectionSlug: string
  config: any
  onNavigate: (path: string) => void
}

type DocumentStatus = 'DRAFT' | 'PUBLISHED' | 'SCHEDULED'

const DEVICE_WIDTHS = {
  desktop: '100%',
  tablet: '768px',
  mobile: '375px',
} as const

const SECTIONS_PANEL_KEY = 'actuate-builder-sections-panel'

/**
 * Left sections panel default: open on wide viewports (≥1280px), collapsed
 * below so the canvas keeps room. An explicit user choice, persisted in
 * localStorage, always wins over the breakpoint default.
 */
function initialSectionsCollapsed(): boolean {
  try {
    const stored = localStorage.getItem(SECTIONS_PANEL_KEY)
    if (stored === 'open') return false
    if (stored === 'collapsed') return true
  } catch {
    /* localStorage unavailable — fall through to the breakpoint default */
  }
  if (typeof window !== 'undefined') {
    return window.innerWidth < 1280
  }
  return false
}

export function PageBuilder({
  documentId,
  templateId,
  collectionSlug,
  config,
  onNavigate,
}: PageBuilderProps) {
  const [loading, setLoading] = useState(!!documentId)
  const [loadError, setLoadError] = useState<string | null>(null)
  const [saving, setSaving] = useState(false)
  const [status, setStatus] = useState<DocumentStatus>('DRAFT')
  const [aiDialogOpen, setAiDialogOpen] = useState(false)
  const [sectionsCollapsed, setSectionsCollapsed] = useState(initialSectionsCollapsed)
  const canvasRef = useRef<HTMLDivElement>(null)

  const builder = useBuilderState()
  const {
    tree,
    pageSettings,
    deviceMode,
    dirty,
    canUndo,
    canRedo,
    selectedNodeId,
    selectedNode,
    activeTab,
    showGridOverlay,
    selectNode,
    setDeviceMode,
    setActiveTab,
    setPageSettings,
    setShowGridOverlay,
    addSection,
    addRowToSection,
    addBlockToColumn,
    addNodeAtId,
    removeNodeById,
    moveNodeById,
    updateSettings,
    updateBlock,
    duplicateNode,
    moveNodeUp,
    moveNodeDown,
    undo,
    redo,
    markClean,
    replaceTree,
  } = builder

  useEffect(() => {
    if (!documentId) {
      // A new page can be seeded from a saved template ("Use template" on
      // the Templates grid). Load the template tree, then hand the canvas
      // over as a dirty, unsaved draft.
      if (templateId) {
        let cancelledNew = false
        setLoading(true)
        cmsApi<{ name?: string; tree?: PageNode }>(`/page-templates/${templateId}`).then((res) => {
          if (cancelledNew) return
          if (res.error) {
            toast.error(`Couldn't load template: ${res.error}`)
          } else if (res.data?.tree) {
            replaceTree(res.data.tree)
          }
          setLoading(false)
        })
        return () => {
          cancelledNew = true
        }
      }
      setLoading(false)
      return
    }

    let cancelled = false

    async function loadDocument() {
      const res = await cmsApi<any>(`/collections/${collectionSlug}/${documentId}`)

      if (cancelled) return

      if (res.error) {
        setLoadError(res.error)
        setLoading(false)
        return
      }

      const doc = res.data
      if (doc?.layout) {
        replaceTree(doc.layout as PageNode)
        markClean()
      }
      if (doc?.pageSettings) {
        setPageSettings(doc.pageSettings)
      }
      if (doc?.status) {
        setStatus(doc.status as DocumentStatus)
      }
      if (doc?.title) {
        setPageSettings({ title: doc.title })
      }

      setLoading(false)
    }

    loadDocument()
    return () => {
      cancelled = true
    }
    // eslint-disable-next-line react-hooks/exhaustive-deps -- replaceTree/setPageSettings are stable builder actions
  }, [documentId, templateId, collectionSlug])

  // Warn before discarding unsaved builder changes on navigation / unload.
  useNavigationBlocker(dirty)

  const handleSave = useCallback(async () => {
    setSaving(true)
    const body = JSON.stringify({
      layout: tree,
      pageSettings,
      title: pageSettings.title,
      slug: pageSettings.slug,
    })

    const endpoint = documentId
      ? `/collections/${collectionSlug}/${documentId}`
      : `/collections/${collectionSlug}`
    const method = documentId ? 'PUT' : 'POST'

    const res = await cmsApi(endpoint, { method, body })
    setSaving(false)

    if (res.error) {
      toast.error(res.error)
    } else {
      markClean()
      toast.success('Page saved')
      if (!documentId && (res.data as any)?.id) {
        onNavigate(`/pages/${(res.data as any).id}/builder`)
      }
    }
  }, [tree, pageSettings, documentId, collectionSlug, markClean, onNavigate])

  const handlePublish = useCallback(async () => {
    setSaving(true)
    const body = JSON.stringify({
      layout: tree,
      pageSettings,
      title: pageSettings.title,
      slug: pageSettings.slug,
      status: 'PUBLISHED',
    })

    const endpoint = documentId
      ? `/collections/${collectionSlug}/${documentId}`
      : `/collections/${collectionSlug}`
    const method = documentId ? 'PUT' : 'POST'

    const res = await cmsApi(endpoint, { method, body })
    setSaving(false)

    if (res.error) {
      toast.error(res.error)
    } else {
      markClean()
      setStatus('PUBLISHED')
      toast.success('Page published')
      if (!documentId && (res.data as any)?.id) {
        onNavigate(`/pages/${(res.data as any).id}/builder`)
      }
    }
  }, [tree, pageSettings, documentId, collectionSlug, markClean, onNavigate])

  const handleAIAccept = useCallback(
    (generatedTree: PageNode) => {
      replaceTree(generatedTree)
    },
    [replaceTree],
  )

  const toggleSectionsPanel = useCallback(() => {
    setSectionsCollapsed((prev) => {
      const next = !prev
      try {
        localStorage.setItem(SECTIONS_PANEL_KEY, next ? 'collapsed' : 'open')
      } catch {
        /* localStorage unavailable — the choice just won't persist */
      }
      return next
    })
  }, [])

  // Selecting from the left panel highlights the section on the canvas (the
  // canvas already outlines the selected node) and opens its settings in the
  // right-hand context panel, then scrolls the section into view.
  const handlePanelSelect = useCallback(
    (id: string) => {
      selectNode(id)
      canvasRef.current
        ?.querySelector(`[data-node-id="${CSS.escape(id)}"]`)
        ?.scrollIntoView({ behavior: 'smooth', block: 'nearest' })
    },
    [selectNode],
  )

  const handlePanelReorder = useCallback(
    (id: string, toIndex: number) => {
      moveNodeById(id, tree.id, toIndex)
    },
    [moveNodeById, tree.id],
  )

  if (loading) {
    return (
      <div className="bg-background flex h-full items-center justify-center">
        <Loader2 className="text-muted-foreground animate-spin" size={24} />
      </div>
    )
  }

  if (loadError) {
    return (
      <div className="bg-background flex h-full items-center justify-center">
        <div className="border-destructive/30 bg-destructive/5 flex max-w-md items-center gap-3 rounded-lg border p-4">
          <AlertTriangle className="text-destructive shrink-0" size={20} />
          <div>
            <p className="text-foreground text-sm font-medium">Failed to load page</p>
            <p className="text-muted-foreground mt-1 text-sm">{loadError}</p>
          </div>
        </div>
      </div>
    )
  }

  const canvasWidth = DEVICE_WIDTHS[deviceMode]
  const isConstrained = deviceMode !== 'desktop'

  // `pageBuilder.previewTheme` lets consumers preview blocks with their
  // brand fonts/colors/radii without baking them into the admin's tokens.
  // We scope the CSS variables to the canvas wrapper so they never leak
  // into the rest of the admin chrome.
  const previewTheme = config?.pageBuilder?.previewTheme ?? {}
  const previewStyle: Record<string, string> = {}
  if (previewTheme.fontFamily) previewStyle['--preview-font-family'] = previewTheme.fontFamily
  if (previewTheme.headingFontFamily)
    previewStyle['--preview-heading-font-family'] = previewTheme.headingFontFamily
  if (previewTheme.primaryColor) previewStyle['--preview-primary'] = previewTheme.primaryColor
  if (previewTheme.secondaryColor) previewStyle['--preview-secondary'] = previewTheme.secondaryColor
  if (previewTheme.borderRadius) previewStyle['--preview-radius'] = previewTheme.borderRadius
  const canvasShellStyle: React.CSSProperties = {
    ...previewStyle,
    fontFamily: previewTheme.fontFamily ?? undefined,
  }

  return (
    <ErrorBoundary>
      <div className="bg-background flex h-full flex-col overflow-hidden">
        <BuilderToolbar
          collectionSlug={collectionSlug}
          pageSettings={pageSettings}
          status={status}
          dirty={dirty}
          saving={saving}
          canUndo={canUndo}
          canRedo={canRedo}
          deviceMode={deviceMode}
          onNavigate={onNavigate}
          onTitleChange={(title) => setPageSettings({ title })}
          onUndo={undo}
          onRedo={redo}
          onDeviceMode={setDeviceMode}
          onSave={handleSave}
          onPublish={handlePublish}
          onOpenAI={() => setAiDialogOpen(true)}
        />

        <div className="flex flex-1 overflow-hidden">
          {/* Sections panel (design parity: sections list left of the canvas) */}
          <BuilderSectionsPanel
            tree={tree}
            selectedNodeId={selectedNodeId}
            collapsed={sectionsCollapsed}
            onToggleCollapsed={toggleSectionsPanel}
            onSelect={handlePanelSelect}
            onReorder={handlePanelReorder}
            onAddSection={addSection}
          />

          {/* Canvas area */}
          <div ref={canvasRef} className="bg-muted flex-1 overflow-auto">
            <div
              className="mx-auto h-full max-w-full transition-all duration-200"
              style={{ width: canvasWidth }}
            >
              <div
                className={`bg-background page-builder-canvas-shell h-full ${isConstrained ? 'border-border border-x shadow-lg' : ''}`}
                style={canvasShellStyle}
              >
                <BuilderCanvas
                  tree={tree}
                  selectedNodeId={selectedNodeId}
                  showGridOverlay={showGridOverlay}
                  deviceMode={deviceMode}
                  onSelectNode={selectNode}
                />
              </div>
            </div>
          </div>

          {/* Context panel */}
          <div className="border-border bg-card w-[35%] max-w-[420px] min-w-[280px] overflow-y-auto border-l">
            <ContextPanel
              activeTab={activeTab}
              onTabChange={setActiveTab}
              selectedNode={selectedNode}
              tree={tree}
              pageSettings={pageSettings}
              onUpdateSettings={updateSettings}
              onUpdateBlock={updateBlock}
              onRemoveNode={removeNodeById}
              onDuplicateNode={duplicateNode}
              onMoveNodeUp={moveNodeUp}
              onMoveNodeDown={moveNodeDown}
              onPageSettingsChange={setPageSettings}
              onAddRow={addRowToSection}
              config={config}
            />
          </div>
        </div>

        <BottomBar
          deviceMode={deviceMode}
          showGridOverlay={showGridOverlay}
          onAddSection={addSection}
          onToggleGrid={setShowGridOverlay}
        />
      </div>
      <AIGenerateDialog
        open={aiDialogOpen}
        onClose={() => setAiDialogOpen(false)}
        onAccept={handleAIAccept}
      />
    </ErrorBoundary>
  )
}
