import { Menu, MenuItem } from 'electron';
import { createEffect, createResource, createSignal, Index, Match, onCleanup, onMount, Show, Switch } from 'solid-js';
import { css } from 'solid-styled-components';
import { TransitionGroup } from 'solid-transition-group';

import { MenuButton } from './MenuButton';
import { Panel } from './Panel';
import { PanelItem } from './PanelItem';
import { IconButton } from './IconButton';
import { WindowController } from './WindowController';

import { cache } from '@/providers/decorators';

import type { RendererContext } from '@/types/contexts';
import type { InAppMenuConfig } from '../constants';

const titleStyle = cache(() => css`
  -webkit-app-region: drag;
  box-sizing: border-box;

  position: fixed;
  top: 0;
  z-index: 10000000;

  width: 100%;
  height: var(--menu-bar-height, 32px);

  display: flex;
  flex-flow: row;
  justify-content: flex-start;
  align-items: center;
  gap: 4px;

  color: #f1f1f1;
  font-size: 12px;
  padding: 4px 4px 4px var(--offset-left, 4px);
  background-color: var(--titlebar-background-color, #030303);
  user-select: none;

  transition: opacity 200ms ease 0s,
  transform 300ms cubic-bezier(0.2, 0, 0.6, 1) 0s,
  background-color 300ms cubic-bezier(0.2, 0, 0.6, 1) 0s;

  &[data-macos="true"] {
    padding: 4px 4px 4px 74px;
  }

  ytmusic-app:has(ytmusic-player[player-ui-state=FULLSCREEN]) ~ &:not([data-show="true"]) {
    transform: translateY(calc(-1 * var(--menu-bar-height, 32px)));
  }
`);

const separatorStyle = cache(() => css`
  min-height: 1px;
  height: 1px;
  margin: 4px 0;

  background-color: rgba(255, 255, 255, 0.2);
`);

const animationStyle = cache(() => ({
  enter: css`
    opacity: 0;
    transform: translateX(-50%) scale(0.8);
  `,
  enterActive: css`
    transition: opacity 0.1s cubic-bezier(0.33, 1, 0.68, 1), transform 0.1s cubic-bezier(0.33, 1, 0.68, 1);
  `,
  exitTo: css`
    opacity: 0;
    transform: translateX(-50%) scale(0.8);
  `,
  exitActive: css`
    transition: opacity 0.1s cubic-bezier(0.32, 0, 0.67, 0), transform 0.1s cubic-bezier(0.32, 0, 0.67, 0);
  `,
  move: css`
    transition: all 0.1s cubic-bezier(0.65, 0, 0.35, 1);
  `,
  fakeTarget: css`
    position: absolute;
    opacity: 0;
  `,
  fake: css`
    transition: all 0.00000000001s;
  `,
}));

export type PanelRendererProps = {
  items: Electron.Menu['items'];
  level?: number[];
  onClick?: (commandId: number, radioGroup?: MenuItem[]) => void;
}
const PanelRenderer = (props: PanelRendererProps) => {
  const radioGroup = () => props.items.filter((it) => it.type === 'radio');

  return (
    <Index each={props.items}>
      {(subItem) => (
        <Show when={subItem().visible}>
          <Switch>
            <Match when={subItem().type === 'normal'}>
              <PanelItem
                type={'normal'}
                name={subItem().label}
                chip={subItem().sublabel}
                toolTip={subItem().toolTip}
                commandId={subItem().commandId}
                onClick={() => props.onClick?.(subItem().commandId)}
              />
            </Match>
            <Match when={subItem().type === 'submenu'}>
              <PanelItem
                type={'submenu'}
                name={subItem().label}
                chip={subItem().sublabel}
                toolTip={subItem().toolTip}
                level={[...props.level ?? [], subItem().commandId]}
                commandId={subItem().commandId}
              >
                <PanelRenderer
                  items={subItem().submenu?.items ?? []}
                  level={[...props.level ?? [], subItem().commandId]}
                  onClick={props.onClick}
                />
              </PanelItem>
            </Match>
            <Match when={subItem().type === 'checkbox'}>
              <PanelItem
                type={'checkbox'}
                name={subItem().label}
                checked={subItem().checked}
                chip={subItem().sublabel}
                toolTip={subItem().toolTip}
                commandId={subItem().commandId}
                onChange={() => props.onClick?.(subItem().commandId)}
              />
            </Match>
            <Match when={subItem().type === 'radio'}>
              <PanelItem
                type={'radio'}
                name={subItem().label}
                checked={subItem().checked}
                chip={subItem().sublabel}
                toolTip={subItem().toolTip}
                commandId={subItem().commandId}
                onChange={() => props.onClick?.(subItem().commandId, radioGroup())}
              />
            </Match>
            <Match when={subItem().type === 'separator'}>
              <hr class={separatorStyle()}/>
            </Match>
          </Switch>
        </Show>
      )}
    </Index>
  );
};

export type TitleBarProps = {
  ipc: RendererContext<InAppMenuConfig>['ipc'];
  isMacOS?: boolean;
  enableController?: boolean;
  initialCollapsed?: boolean;
};
export const TitleBar = (props: TitleBarProps) => {
  const [collapsed, setCollapsed] = createSignal(props.initialCollapsed);
  const [ignoreTransition, setIgnoreTransition] = createSignal(false);
  const [openTarget, setOpenTarget] = createSignal<HTMLElement | null>(null);
  const [menu, setMenu] = createSignal<Menu | null>(null);
  const [mouseY, setMouseY] = createSignal(0);

  const [data, { refetch }] = createResource(async () => await props.ipc.invoke('get-menu') as Promise<Menu | null>);
  const [isMaximized, { refetch: refetchMaximize }] = createResource(async () => await props.ipc.invoke('window-is-maximized') as Promise<boolean>);

  const handleToggleMaximize = async () => {
    if (isMaximized()) {
      await props.ipc.invoke('window-unmaximize');
    } else {
      await props.ipc.invoke('window-maximize');
    }
    await refetchMaximize();
  };
  const handleMinimize = async () => {
    await props.ipc.invoke('window-minimize');
  };
  const handleClose = async () => {
    await props.ipc.invoke('window-close');
  };

  const refreshMenuItem = async (originalMenu: Menu, commandId: number) => {
    const menuItem = (await window.ipcRenderer.invoke(
      'get-menu-by-id',
      commandId,
    )) as MenuItem | null;

    const newMenu = structuredClone(originalMenu);
    const stack = [...newMenu?.items ?? []];
    let now: MenuItem | undefined = stack.pop();
    while (now) {
      const index = now?.submenu?.items?.findIndex((it) => it.commandId === commandId) ?? -1;

      if (index >= 0) {
        if (menuItem) now?.submenu?.items?.splice(index, 1, menuItem);
        else now?.submenu?.items?.splice(index, 1);
      }
      if (now?.submenu) {
        stack.push(...now.submenu.items);
      }

      now = stack.pop();
    }

    return newMenu;
  };

  const handleItemClick = async (commandId: number, radioGroup?: MenuItem[]) => {
    const menuData = menu();
    if (!menuData) return;

    if (Array.isArray(radioGroup)) {
      let newMenu = menuData;
      for await (const item of radioGroup) {
        newMenu = await refreshMenuItem(newMenu, item.commandId);
      }

      setMenu(newMenu);
      return;
    }

    setMenu(await refreshMenuItem(menuData, commandId));
  };

  const listener = (e: MouseEvent) => {
    setMouseY(e.clientY);
  };

  onMount(() => {
    props.ipc.on('close-all-in-app-menu-panel', async () => {
      setIgnoreTransition(true);
      setMenu(null);
      await refetch();
      setMenu(data() ?? null);
      setIgnoreTransition(false);
    });
    props.ipc.on('refresh-in-app-menu', async () => {
      setIgnoreTransition(true);
      await refetch();
      setMenu(data() ?? null);
      setIgnoreTransition(false);
    });
    props.ipc.on('toggle-in-app-menu', () => {
      setCollapsed(!collapsed());
    });

    props.ipc.on('window-maximize', refetchMaximize);
    props.ipc.on('window-unmaximize', refetchMaximize);

    // close menu when the outside of the panel or sub-panel is clicked
    document.body.addEventListener('click', (e) => {
      if (
        e.target instanceof HTMLElement &&
        !(
          e.target.closest('nav[data-ytmd-main-panel]') ||
          e.target.closest('ul[data-ytmd-sub-panel]')
        )
      ) {
        setOpenTarget(null);
      }
    });

    // tracking mouse position
    window.addEventListener('mousemove', listener);
    const ytmusicAppLayout = document.querySelector<HTMLElement>('#layout');
    ytmusicAppLayout?.addEventListener("scroll",()=>{
    const scrollValue = ytmusicAppLayout.scrollTop;
    if (scrollValue > 20){
      ytmusicAppLayout.classList.add("content-scrolled");
    }
    else{
      ytmusicAppLayout.classList.remove("content-scrolled");
    }
    })

  });

  

  createEffect(() => {
    if (!menu() && data()) {
      setMenu(data() ?? null);
    }
  });

  onCleanup(() => {
    window.removeEventListener('mousemove', listener);
  });

  return (
    <nav data-ytmd-main-panel={true} class={titleStyle()} data-macos={props.isMacOS} data-show={mouseY() < 32}>
      <IconButton
        onClick={() => setCollapsed(!collapsed())}
        style={{
          'border-top-left-radius': '4px',
        }}
      >
        <svg width={16} height={16} viewBox={'0 0 24 24'}>
          <path
            d="M3 17h12a1 1 0 0 1 .117 1.993L15 19H3a1 1 0 0 1-.117-1.993L3 17h12H3Zm0-6h18a1 1 0 0 1 .117 1.993L21 13H3a1 1 0 0 1-.117-1.993L3 11h18H3Zm0-6h15a1 1 0 0 1 .117 1.993L18 7H3a1 1 0 0 1-.117-1.993L3 5h15H3Z"
            fill="currentColor"
          />
        </svg>
      </IconButton>
      <TransitionGroup
        enterClass={ignoreTransition() ? animationStyle().fakeTarget : animationStyle().enter}
        enterActiveClass={ignoreTransition() ? animationStyle().fake : animationStyle().enterActive}
        exitToClass={ignoreTransition() ? animationStyle().fakeTarget : animationStyle().exitTo}
        exitActiveClass={ignoreTransition() ? animationStyle().fake : animationStyle().exitActive}
        onBeforeEnter={(element) => {
          if (ignoreTransition()) return;
          const index = Number(element.getAttribute('data-index') ?? 0);

          (element as HTMLElement).style.setProperty('transition-delay', `${(index * 0.025)}s`);
        }}
        onAfterEnter={(element) => {
          (element as HTMLElement).style.removeProperty('transition-delay');
        }}
        onBeforeExit={(element) => {
          if (ignoreTransition()) return;
          const index = Number(element.getAttribute('data-index') ?? 0);
          const length = Number(element.getAttribute('data-length') ?? 1);

          (element as HTMLElement).style.setProperty('transition-delay', `${(length * 0.025) - (index * 0.025)}s`);
        }}
      >
        <Show when={!collapsed()}>
          <Index each={menu()?.items}>
            {(item, index) => {
              const [anchor, setAnchor] = createSignal<HTMLElement | null>(null);

              const handleClick = () => {
                if (openTarget() === anchor()) {
                  setOpenTarget(null);
                } else {
                  setOpenTarget(anchor());
                }
              };

              return (
                <>
                  <MenuButton
                    ref={setAnchor}
                    text={item().label}
                    onClick={handleClick}
                    selected={openTarget() === anchor()}
                    data-index={index}
                    data-length={data()?.items.length}
                  />
                  <Panel
                    open={openTarget() === anchor()}
                    anchor={anchor()}
                    placement={'bottom-start'}
                    offset={{ mainAxis: 8 }}
                  >
                    <PanelRenderer
                      items={item().submenu?.items ?? []}
                      onClick={handleItemClick}
                    />
                  </Panel>
                </>
              );
            }}
          </Index>
        </Show>
      </TransitionGroup>
      <Show when={props.enableController}>
        <div style={{ flex: 1 }}/>
        <WindowController
          isMaximize={isMaximized()}
          onToggleMaximize={handleToggleMaximize}
          onMinimize={handleMinimize}
          onClose={handleClose}
        />
      </Show>
    </nav>
  );
};

