import type {
  SidebarBrandConfig,
  SidebarComponentConfig,
  SidebarFooterAction,
  SidebarNavItem,
  SidebarScopeConfig,
  SidebarSection,
  SidebarUser,
} from '../sidebar/types'
import { SidebarComponent } from '../sidebar/component'
import { resolveContainer } from '../primitives/utils'
import {
  TopMenuBar,
  type TopMenuBarActionInput,
  type TopMenuBarConfig,
  type TopMenuBarUser,
} from './app-shell'

export interface CoreAppRouteLabel {
  pattern: RegExp
  label: string
}

export interface CoreAppSidebarPresetOptions extends Omit<
  SidebarComponentConfig,
  'container' | 'sections'
> {
  basePath?: string
  sections?: SidebarSection[]
}

export interface CoreAppTopbarPresetOptions extends Omit<
  TopMenuBarConfig,
  'actions' | 'current' | 'product'
> {
  basePath?: string
  pathname?: string
  product?: string
  current?: string
  actions?: TopMenuBarActionInput[]
  includeSearchAction?: boolean
  includeFeedbackAction?: boolean
  includeHelpAction?: boolean
}

export interface CoreAppChromePreset {
  sidebar: Omit<SidebarComponentConfig, 'container'>
  topbar: TopMenuBarConfig
}

export interface CoreAppChromePresetOptions {
  basePath?: string
  pathname?: string
  scope?: SidebarScopeConfig
  sidebarUser?: SidebarUser
  sidebarFooterActions?: SidebarFooterAction[]
  topbarUser?: TopMenuBarUser
  topbarActions?: TopMenuBarActionInput[]
}

export interface CoreAppChromeMountOptions extends CoreAppChromePresetOptions {
  sidebarContainer: HTMLElement | string
  topbarContainer?: HTMLElement | string
  sidebar?: CoreAppSidebarPresetOptions
  topbar?: CoreAppTopbarPresetOptions
  /**
   * Move explicitly marked server-rendered topbar action nodes into the new topbar.
   * Useful for native hooks that are initialized outside the chrome mount.
   * @default true
   */
  preserveTopbarActions?: boolean
  /**
   * Selector for preserved action nodes inside the topbar container.
   * @default '[data-core-app-topbar-action]'
   */
  topbarActionSelector?: string
  /**
   * Remove existing placeholder/server-rendered children before mounting.
   * @default true
   */
  clearContainers?: boolean
}

export interface CoreAppChromeDomMountOptions extends CoreAppChromePresetOptions {
  root?: ParentNode
  sidebarSelector?: string
  topbarSelector?: string
  sidebar?: CoreAppSidebarPresetOptions
  topbar?: CoreAppTopbarPresetOptions
  preserveTopbarActions?: boolean
  topbarActionSelector?: string
  clearContainers?: boolean
}

export interface CoreAppChromeMount {
  sidebar: SidebarComponent
  topbar?: TopMenuBar
  destroy: () => void
}

interface CoreAppNavItemBlueprint {
  id: string
  label: string
  href: string
  icon: string
  end?: boolean
}

interface CoreAppNavSectionBlueprint {
  id: string
  label: string
  items: CoreAppNavItemBlueprint[]
}

const DEFAULT_DOM_SIDEBAR_SELECTOR = '[data-core-app-sidebar]'
const DEFAULT_DOM_TOPBAR_SELECTOR = '[data-core-app-topbar]'
const DEFAULT_TOPBAR_ACTION_SELECTOR = '[data-core-app-topbar-action]'

const CORE_APP_NAV_SECTIONS: CoreAppNavSectionBlueprint[] = [
  {
    id: 'dashboards',
    label: 'Dashboards',
    items: [
      { id: 'library', label: 'Library', href: '/', icon: 'library', end: true },
      { id: 'capacity', label: 'Capacity', href: '/capacity', icon: 'capacity' },
      { id: 'operational-alerts', label: 'Operational Alerts', href: '/alerts', icon: 'alerts' },
    ],
  },
  {
    id: 'threat-library',
    label: 'Threat Library',
    items: [
      { id: 'detections', label: 'Detections', href: '/detections', icon: 'detections' },
      { id: 'actors', label: 'Actors', href: '/actors', icon: 'actors' },
      { id: 'library-reports', label: 'Library Reports', href: '/intel', icon: 'intel-reports' },
      { id: 'mitre', label: 'MITRE ATT&CK', href: '/mitre', icon: 'mitre' },
    ],
  },
  {
    id: 'library-operations',
    label: 'Library Operations',
    items: [{ id: 'pipeline', label: 'Pipeline', href: '/pipeline', icon: 'pipeline' }],
  },
  {
    id: 'integrations',
    label: 'Integrations',
    items: [
      { id: 'connectors', label: 'Connectors', href: '/connectors', icon: 'connectors' },
      { id: 'jobs', label: 'Jobs', href: '/jobs', icon: 'jobs' },
    ],
  },
  {
    id: 'platform',
    label: 'Platform',
    items: [
      { id: 'tenants', label: 'Tenants', href: '/tenants', icon: 'tenants' },
      { id: 'runners', label: 'Runners', href: '/runners', icon: 'runners' },
      { id: 'topology', label: 'Topology', href: '/topology', icon: 'topology' },
      { id: 'api-access', label: 'API Access', href: '/api-access', icon: 'api-access' },
    ],
  },
]

export const CORE_APP_ROUTE_LABELS: CoreAppRouteLabel[] = [
  { pattern: /^\/(?:dashboards\/)?capacity(?:\/|$)/, label: 'Capacity' },
  { pattern: /^\/(?:dashboards\/)?alerts(?:\/|$)/, label: 'Operational Alerts' },
  { pattern: /^\/dashboards\/library(?:\/|$)/, label: 'Library Dashboard' },
  { pattern: /^\/detections(?:\/|$)/, label: 'Detections' },
  { pattern: /^\/actors(?:\/|$)/, label: 'Actors' },
  { pattern: /^\/intel(?:\/|$)/, label: 'Library Reports' },
  { pattern: /^\/mitre(?:\/|$)/, label: 'MITRE ATT&CK' },
  { pattern: /^\/pipeline(?:\/|$)/, label: 'Pipeline' },
  { pattern: /^\/connectors(?:\/|$)/, label: 'Connectors' },
  { pattern: /^\/jobs(?:\/|$)/, label: 'Jobs' },
  { pattern: /^\/topology(?:\/|$)/, label: 'Topology' },
  { pattern: /^\/tenants(?:\/|$)/, label: 'Tenants' },
  { pattern: /^\/runners(?:\/|$)/, label: 'Runners' },
  { pattern: /^\/api-access(?:\/|$)/, label: 'API Access' },
  { pattern: /^\/settings(?:\/|$)/, label: 'Settings' },
]

function normalizeBasePath(basePath: string): string {
  const trimmed = basePath.trim()
  if (trimmed === '' || trimmed === '/') {
    return ''
  }
  return `/${trimmed.replace(/^\/+|\/+$/g, '')}`
}

function joinBasePath(basePath: string, href: string): string {
  const normalizedBase = normalizeBasePath(basePath)
  if (href === '/' || href === '') {
    return normalizedBase || '/'
  }
  return `${normalizedBase}/${href.replace(/^\/+/, '')}`
}

function stripBasePath(pathname: string, basePath: string): string {
  const normalizedBase = normalizeBasePath(basePath)
  if (normalizedBase === '') {
    return pathname || '/'
  }

  if (pathname === normalizedBase) {
    return '/'
  }

  if (pathname.startsWith(`${normalizedBase}/`)) {
    return pathname.slice(normalizedBase.length) || '/'
  }

  return pathname || '/'
}

function cloneSections(sections: SidebarSection[]): SidebarSection[] {
  return sections.map(section => ({
    ...section,
    items: section.items.map(item => ({ ...item })),
  }))
}

export function createCoreAppSidebarSections(basePath = '/app'): SidebarSection[] {
  return CORE_APP_NAV_SECTIONS.map(section => ({
    id: section.id,
    label: section.label,
    items: section.items.map(item => {
      const navItem: SidebarNavItem = {
        id: item.id,
        label: item.label,
        href: joinBasePath(basePath, item.href),
        icon: item.icon,
        tooltip: item.label,
        activeMatch: item.end === true ? 'exact' : 'prefix',
      }
      if (item.end !== undefined) {
        navItem.end = item.end
      }
      return navItem
    }),
  }))
}

export function getCoreAppRouteLabel(pathname: string, basePath = '/app'): string {
  const relativePathname = stripBasePath(pathname, basePath)
  if (relativePathname === '/' || relativePathname === '') {
    return 'Platform Overview'
  }

  return (
    CORE_APP_ROUTE_LABELS.find(route => route.pattern.test(relativePathname))?.label ??
    'Threat Library'
  )
}

export function createCoreAppSidebarConfig(
  options: CoreAppSidebarPresetOptions = {}
): Omit<SidebarComponentConfig, 'container'> {
  const {
    basePath = '/app',
    sections,
    variant = 'cm',
    brand,
    scope,
    beforeNav,
    afterNav,
    collapsible = true,
    collapseButtonVisible = true,
    user,
    footerActions,
    iconSet,
    collapsed,
    activeItemId,
    pathname,
    storageKey = 'cm-sidebar-collapsed',
    persistCollapsed,
    mobileBreakpoint,
    mobileBackdrop = true,
    closeOnNavigate = true,
    open,
    onNavigate,
    onCollapse,
    onOpenChange,
  } = options

  const resolvedBrand: SidebarBrandConfig = brand ?? {
    label: 'CounterMeasure',
    href: joinBasePath(basePath, '/'),
  }

  const config: Omit<SidebarComponentConfig, 'container'> = {
    variant,
    sections:
      sections === undefined ? createCoreAppSidebarSections(basePath) : cloneSections(sections),
    brand: resolvedBrand,
    collapsible,
    collapseButtonVisible,
    storageKey,
    mobileBackdrop,
    closeOnNavigate,
  }

  if (scope !== undefined) config.scope = scope
  if (beforeNav !== undefined) config.beforeNav = beforeNav
  if (afterNav !== undefined) config.afterNav = afterNav
  if (user !== undefined) config.user = user
  if (footerActions !== undefined) config.footerActions = footerActions
  if (iconSet !== undefined) config.iconSet = iconSet
  if (collapsed !== undefined) config.collapsed = collapsed
  if (activeItemId !== undefined) config.activeItemId = activeItemId
  if (pathname !== undefined) config.pathname = pathname
  if (persistCollapsed !== undefined) config.persistCollapsed = persistCollapsed
  if (mobileBreakpoint !== undefined) config.mobileBreakpoint = mobileBreakpoint
  if (open !== undefined) config.open = open
  if (onNavigate !== undefined) config.onNavigate = onNavigate
  if (onCollapse !== undefined) config.onCollapse = onCollapse
  if (onOpenChange !== undefined) config.onOpenChange = onOpenChange

  return config
}

export function createCoreAppTopbarActions(
  options: Pick<
    CoreAppTopbarPresetOptions,
    'includeSearchAction' | 'includeFeedbackAction' | 'includeHelpAction'
  > = {}
): TopMenuBarActionInput[] {
  const {
    includeSearchAction = true,
    includeFeedbackAction = true,
    includeHelpAction = true,
  } = options
  const actions: TopMenuBarActionInput[] = []

  if (includeSearchAction) {
    actions.push({
      id: 'search',
      label: 'Find...',
      icon: 'search',
      showLabel: true,
      className: 'cmm-topbar__action--search',
      attributes: { 'data-app-search-trigger': true },
    })
  }

  if (includeFeedbackAction) {
    actions.push({
      id: 'feedback',
      label: 'Feedback',
      showLabel: true,
      attributes: { 'data-feedback-toggle': true },
    })
  }

  if (includeHelpAction) {
    actions.push({
      id: 'help',
      label: 'Help',
      icon: 'help',
      attributes: { 'data-help-toggle': true },
    })
  }

  return actions
}

export function createCoreAppTopbarConfig(
  options: CoreAppTopbarPresetOptions = {}
): TopMenuBarConfig {
  const {
    basePath = '/app',
    pathname = typeof window === 'undefined' ? '/' : window.location.pathname,
    product = 'CounterMeasure Core',
    current = getCoreAppRouteLabel(pathname, basePath),
    actions,
    beforeActions,
    afterActions,
    user,
    iconSet,
    className,
    breadcrumbs,
    container,
    includeSearchAction,
    includeFeedbackAction,
    includeHelpAction,
  } = options

  const actionOptions: Pick<
    CoreAppTopbarPresetOptions,
    'includeSearchAction' | 'includeFeedbackAction' | 'includeHelpAction'
  > = {}
  if (includeSearchAction !== undefined) actionOptions.includeSearchAction = includeSearchAction
  if (includeFeedbackAction !== undefined)
    actionOptions.includeFeedbackAction = includeFeedbackAction
  if (includeHelpAction !== undefined) actionOptions.includeHelpAction = includeHelpAction

  const config: TopMenuBarConfig = {
    product,
    current,
    actions: actions ?? createCoreAppTopbarActions(actionOptions),
  }

  if (container !== undefined) config.container = container
  if (breadcrumbs !== undefined) config.breadcrumbs = breadcrumbs
  if (beforeActions !== undefined) config.beforeActions = beforeActions
  if (afterActions !== undefined) config.afterActions = afterActions
  if (user !== undefined) config.user = user
  if (iconSet !== undefined) config.iconSet = iconSet
  if (className !== undefined) config.className = className

  return config
}

export function createCoreAppChromePreset(
  options: CoreAppChromePresetOptions = {}
): CoreAppChromePreset {
  const {
    basePath = '/app',
    pathname,
    scope,
    sidebarUser,
    sidebarFooterActions,
    topbarUser,
    topbarActions,
  } = options

  const sidebarOptions: CoreAppSidebarPresetOptions = { basePath }
  if (scope !== undefined) sidebarOptions.scope = scope
  if (sidebarUser !== undefined) sidebarOptions.user = sidebarUser
  if (sidebarFooterActions !== undefined) sidebarOptions.footerActions = sidebarFooterActions
  if (pathname !== undefined) sidebarOptions.pathname = pathname

  const topbarOptions: CoreAppTopbarPresetOptions = { basePath }
  if (pathname !== undefined) topbarOptions.pathname = pathname
  if (topbarUser !== undefined) topbarOptions.user = topbarUser
  if (topbarActions !== undefined) topbarOptions.actions = topbarActions

  return {
    sidebar: createCoreAppSidebarConfig(sidebarOptions),
    topbar: createCoreAppTopbarConfig(topbarOptions),
  }
}

function clearContainer(container: HTMLElement, clearContainers: boolean | undefined): void {
  if (clearContainers !== false) {
    container.replaceChildren()
  }
}

function collectTopbarActionNodes(options: {
  container: HTMLElement
  preserveTopbarActions: boolean | undefined
  selector: string | undefined
}): HTMLElement[] {
  if (options.preserveTopbarActions === false) {
    return []
  }

  return Array.from(
    options.container.querySelectorAll<HTMLElement>(
      options.selector ?? DEFAULT_TOPBAR_ACTION_SELECTOR
    )
  )
}

function mergeElements(
  existing: HTMLElement | HTMLElement[] | undefined,
  additions: HTMLElement[]
): HTMLElement | HTMLElement[] | undefined {
  if (additions.length === 0) {
    return existing
  }

  if (existing === undefined) {
    return additions
  }

  return Array.isArray(existing) ? [...existing, ...additions] : [existing, ...additions]
}

function hasPreservedActionAttribute(actions: HTMLElement[], attribute: string): boolean {
  return actions.some(action => action.hasAttribute(attribute))
}

function dedupeDefaultActionsForPreservedNodes(
  options: CoreAppTopbarPresetOptions,
  preservedActions: HTMLElement[]
): void {
  if (options.actions !== undefined || preservedActions.length === 0) {
    return
  }

  if (
    options.includeSearchAction === undefined &&
    hasPreservedActionAttribute(preservedActions, 'data-app-search-trigger')
  ) {
    options.includeSearchAction = false
  }

  if (
    options.includeFeedbackAction === undefined &&
    hasPreservedActionAttribute(preservedActions, 'data-feedback-toggle')
  ) {
    options.includeFeedbackAction = false
  }

  if (
    options.includeHelpAction === undefined &&
    hasPreservedActionAttribute(preservedActions, 'data-help-toggle')
  ) {
    options.includeHelpAction = false
  }
}

function buildSidebarMountOptions(options: CoreAppChromeMountOptions): CoreAppSidebarPresetOptions {
  const basePath = options.sidebar?.basePath ?? options.basePath ?? '/app'
  const sidebarOptions: CoreAppSidebarPresetOptions = {
    ...options.sidebar,
    basePath,
  }

  if (options.scope !== undefined) sidebarOptions.scope = options.scope
  if (options.sidebarUser !== undefined) sidebarOptions.user = options.sidebarUser
  if (options.sidebarFooterActions !== undefined)
    sidebarOptions.footerActions = options.sidebarFooterActions
  if (options.pathname !== undefined && sidebarOptions.pathname === undefined) {
    sidebarOptions.pathname = options.pathname
  }

  return sidebarOptions
}

function buildTopbarMountOptions(
  options: CoreAppChromeMountOptions,
  topbarContainer: HTMLElement,
  preservedActions: HTMLElement[]
): CoreAppTopbarPresetOptions {
  const basePath = options.topbar?.basePath ?? options.basePath ?? '/app'
  const topbarOptions: CoreAppTopbarPresetOptions = {
    ...options.topbar,
    basePath,
    container: topbarContainer,
  }
  const afterActions = mergeElements(options.topbar?.afterActions, preservedActions)

  if (options.pathname !== undefined) topbarOptions.pathname = options.pathname
  if (options.topbarUser !== undefined) topbarOptions.user = options.topbarUser
  if (options.topbarActions !== undefined) topbarOptions.actions = options.topbarActions
  if (afterActions !== undefined) topbarOptions.afterActions = afterActions
  dedupeDefaultActionsForPreservedNodes(topbarOptions, preservedActions)

  return topbarOptions
}

export function mountCoreAppChrome(options: CoreAppChromeMountOptions): CoreAppChromeMount {
  const sidebarContainer = resolveContainer(options.sidebarContainer)
  clearContainer(sidebarContainer, options.clearContainers)

  const sidebar = new SidebarComponent({
    container: sidebarContainer,
    ...createCoreAppSidebarConfig(buildSidebarMountOptions(options)),
  })

  const topbarContainerOption = options.topbarContainer ?? options.topbar?.container
  const topbarContainer =
    topbarContainerOption === undefined ? undefined : resolveContainer(topbarContainerOption)
  let topbar: TopMenuBar | undefined

  if (topbarContainer !== undefined) {
    const preservedActions = collectTopbarActionNodes({
      container: topbarContainer,
      preserveTopbarActions: options.preserveTopbarActions,
      selector: options.topbarActionSelector,
    })
    clearContainer(topbarContainer, options.clearContainers)
    topbar = new TopMenuBar(
      createCoreAppTopbarConfig(buildTopbarMountOptions(options, topbarContainer, preservedActions))
    )
  }

  const mounted: CoreAppChromeMount = {
    sidebar,
    destroy: () => {
      topbar?.destroy()
      sidebar.destroy()
    },
  }

  if (topbar !== undefined) {
    mounted.topbar = topbar
  }

  return mounted
}

function readDataValue(element: HTMLElement | undefined, key: string): string | undefined {
  const value = element?.dataset[key]
  return value === undefined || value.length === 0 ? undefined : value
}

function buildDeclarativeTopbarOptions(
  options: CoreAppChromeDomMountOptions,
  sidebarContainer: HTMLElement,
  topbarContainer: HTMLElement | null
): CoreAppTopbarPresetOptions | undefined {
  const product =
    options.topbar?.product ??
    readDataValue(topbarContainer ?? undefined, 'product') ??
    readDataValue(sidebarContainer, 'product')
  const current =
    options.topbar?.current ??
    readDataValue(topbarContainer ?? undefined, 'current') ??
    readDataValue(sidebarContainer, 'current')

  if (options.topbar === undefined && product === undefined && current === undefined) {
    return undefined
  }

  const topbar: CoreAppTopbarPresetOptions = { ...(options.topbar ?? {}) }
  if (product !== undefined) topbar.product = product
  if (current !== undefined) topbar.current = current
  return topbar
}

export function mountCoreAppChromeFromDom(
  options: CoreAppChromeDomMountOptions = {}
): CoreAppChromeMount | null {
  const root = options.root ?? document
  const sidebarContainer = root.querySelector<HTMLElement>(
    options.sidebarSelector ?? DEFAULT_DOM_SIDEBAR_SELECTOR
  )

  if (sidebarContainer === null) {
    return null
  }

  const topbarContainer = root.querySelector<HTMLElement>(
    options.topbarSelector ?? DEFAULT_DOM_TOPBAR_SELECTOR
  )
  const basePath =
    options.basePath ??
    options.sidebar?.basePath ??
    options.topbar?.basePath ??
    readDataValue(sidebarContainer, 'basePath') ??
    readDataValue(topbarContainer ?? undefined, 'basePath') ??
    '/app'
  const pathname =
    options.pathname ??
    readDataValue(sidebarContainer, 'pathname') ??
    readDataValue(topbarContainer ?? undefined, 'pathname')

  const mountOptions: CoreAppChromeMountOptions = {
    ...options,
    sidebarContainer,
    basePath,
  }
  const topbar = buildDeclarativeTopbarOptions(options, sidebarContainer, topbarContainer)
  if (topbar !== undefined) mountOptions.topbar = topbar
  if (topbarContainer !== null) mountOptions.topbarContainer = topbarContainer
  if (pathname !== undefined) mountOptions.pathname = pathname

  return mountCoreAppChrome(mountOptions)
}
