import
{
  FocusContext,
  useFocusable,
} from "@noriginmedia/norigin-spatial-navigation";
import classNames from "classnames";
import
{
  BatteryCharging,
  BatteryFull,
  BatteryLow,
  BatteryMedium,
  BatteryWarning,
  Bell,
  Bluetooth,
  CircleFadingArrowUp,
  Clock,
  Settings,
  Wifi,
  WifiHigh,
  WifiLow,
  WifiZero,
} from "lucide-react";
import { RoundButton } from "./RoundButton";
import { keepPreviousData, useQuery } from "@tanstack/react-query";
import { JSX, RefObject, useContext, useEffect, useRef, useState } from "react";
import { useStickyDataAttr } from "../scripts/utils";
import { twMerge } from "tailwind-merge";
import { TwitchIcon } from "../scripts/brandIcons";
import { rommLoggedInQuery } from "../scripts/queries/romm";
import { twitchLoginVerificationQuery } from "../scripts/queries/settings";
import { AppContext, SystemInfoContext } from "../scripts/contexts";
import { useNavigate, useRouter } from "@tanstack/react-router";
import { oneShot } from "../scripts/audio/audio";
import { hasUpdateQuery } from "../scripts/queries/system";
import { GamePadButtonCode, useShortcuts } from "../scripts/shortcuts";

function HeaderAvatar (data: {
  id: string;
  preview?: string | JSX.Element;
  className?: string;
  active?: boolean;
  locked?: boolean;
  onSelect?: () => void;
})
{

  return (
    <div
      id={data.id}
      onClick={data.onSelect}
      style={{ viewTransitionName: `header-account-${data.id}` }}
      className={twMerge(
        `avatar overflow-visible bg-base-100 indicator border-7 sm:size-8 md:size-14 rounded-full flex items-center justify-center drop-shadow-md`,
        data.className,
      )}
    >
      {typeof data.preview === 'string' ? (
        <div className="overflow rounded-full w-full h-full">
          <picture>
            <img key={"og-image"} src={data.preview}></img>

          </picture>
        </div>
      ) : data.preview}
    </div>
  );
}

export interface HeaderButton
{
  id: string;
  icon: JSX.Element;
  external?: boolean;
  action?: () => void;
  className?: string;
  shortcutLabel?: string;
}

export interface HeaderAccount
{
  id: string;
  preview?: string | JSX.Element;
  className?: string;
  type?: "base" | "primary" | "secondary" | "accent";
  locked?: boolean;
  action?: () => void;
}

function UpdateStatus ()
{
  const handleSelect = () =>
  {
    navigate({ to: '/settings/update' });
  };
  const hasUnread = false;
  const navigate = useNavigate();
  const { ref } = useFocusable({
    focusKey: 'update-bt', onEnterPress: handleSelect
  });
  return <div onClick={handleSelect} ref={ref} className={classNames("tooltip tooltip-bottom tooltip-warning p-2 rounded-full focusable focusable-primary focusable-hover focused:bg-warning cursor-pointer", { "bg-warning text-warning-content ": hasUnread })} data-tip="Update Available">
    <CircleFadingArrowUp className="sm:size-4 md:size-8 text-warning in-focused:text-warning-content" />
  </div>;
}

function NotificationStatus ()
{
  const hasUnread = false;
  return <div className={classNames("p-2 rounded-full focused:bg-base-300", { "bg-warning text-warning-content": hasUnread })}>
    <Bell className="sm:size-4 md:size-8" />
  </div>;
}

function ClockStatus ()
{
  const navigate = useNavigate();
  const app = useContext(AppContext);
  const refClock = useRef<HTMLSpanElement>(null);
  const activeTaskProgress = app.activeTaskProgress;
  const handleTaskClick = () =>
  {
    navigate({ to: '/settings/tasks' });
  };
  const { ref, focusKey } = useFocusable({ focusKey: 'tasks-indicator', focusable: !!activeTaskProgress, onEnterPress: handleTaskClick });
  useEffect(() =>
  {
    function update ()
    {
      if (refClock.current)
      {
        refClock.current.textContent = new Date().toLocaleTimeString([], { hour: '2-digit', minute: '2-digit' });
      }
    }

    // Update immediately
    update();

    // Wait until next minute boundary
    const now = new Date();
    const msUntilNextMinute =
      (60 - now.getSeconds()) * 1000 - now.getMilliseconds();

    const timeout = setTimeout(() =>
    {
      update();

      // Then update every minute
      const interval = setInterval(update, 60_000);
      return () => clearInterval(interval);
    }, msUntilNextMinute);

    return () => clearTimeout(timeout);
  }, []);

  useShortcuts(focusKey, () => [{
    label: "Downloads", button: GamePadButtonCode.A, action (e)
    {
      handleTaskClick();
    },
  }]);

  return <div ref={ref} className="flex gap-3 sm:text-xs md:text-2xl items-center">
    <span ref={refClock}></span>
    {activeTaskProgress ? <div onClick={handleTaskClick} className={twMerge("radial-progress bg-primary text-primary-content border-primary border-4 in-focused:ring-7 in-focused:ring-primary in-focused:bg-base-content in-focused:text-base-200 in-focused:border-base-content", activeTaskProgress ? "cursor-pointer" : "")} style={{ "--value": activeTaskProgress, "--size": "2rem", "--thickness": "0.3rem" }} role="progressbar"></div> : <Clock className="sm:size-4 md:size-8" />}</div>;
}

function BluetoothStatus ()
{
  const systemContext = useContext(SystemInfoContext);

  return systemContext?.bluetoothDevices.find(b => b.connected) && <div>
    <Bluetooth className="w-6 h-6" />
  </div>;
}

function WiFiStatus ()
{
  const systemContext = useContext(SystemInfoContext);

  return systemContext && systemContext.wifiConnections.length > 0 ? <div>
    {systemContext.wifiConnections.map(w =>
    {
      const className = "w-10 h-10";
      let icon = <Wifi className={className} />;
      if (w.signalLevel >= -60)
        icon = <Wifi className={className} />;
      else if (w.signalLevel >= -70)
        icon = <WifiHigh className={className} />;
      else if (w.signalLevel >= -80)
        icon = <WifiLow className={className} />;
      else if (w.signalLevel >= -90)
        icon = <WifiZero className={className} />;

      return <div className="tooltip tooltip-bottom" data-tip={w.signalLevel}>
        {icon}
      </div>;
    })}

  </div> : undefined;
}

function BatteryStatus ()
{
  const systemContext = useContext(SystemInfoContext);

  const batteryClassName = "md:size-10 sm:size-6";
  let batteryIcon = <BatteryFull className={batteryClassName} />;
  if (systemContext)
  {
    if (systemContext.battery.isCharging || systemContext.battery.acConnected)
    {
      batteryIcon = <BatteryCharging className={batteryClassName} />;
    } else if (systemContext.battery.percent)
    {
      if (systemContext.battery.percent < 5)
      {
        batteryIcon = <BatteryWarning className={batteryClassName} />;
      }
      else if (systemContext.battery.percent < 15)
      {
        batteryIcon = <BatteryLow className={batteryClassName} />;
      } else if (systemContext.battery.percent < 50)
      {
        batteryIcon = <BatteryMedium className={batteryClassName} />;
      }
    }
  }
  return !!systemContext?.battery.hasBattery && <div className="flex gap-2 items-center">
    {batteryIcon}
    <span className="font-semibold">{systemContext.battery?.percent} %</span>
  </div>;
}

export function HeaderAccounts (data: { accounts?: HeaderAccount[]; })
{
  const rommUser = useQuery({ ...rommLoggedInQuery, placeholderData: keepPreviousData });
  const twitchStatus = useQuery({
    ...twitchLoginVerificationQuery,
    refetchOnWindowFocus: false,
    retry: 1,
    placeholderData: keepPreviousData
  });

  const handleSelect = () =>
  {
    router.navigate({ to: '/settings/accounts' });
    oneShot('click');
  };

  const accounts: HeaderAccount[] = [];
  if (data.accounts) accounts.push(...data.accounts);
  if (rommUser.data?.hasLogin || rommUser.isError)
  {
    accounts.push({
      id: 'romm', preview: `https://romm.app/_ipx/q_80/images/blocks/logos/romm.svg`,
      className: rommUser.data?.hasLogin && !rommUser.isError ? undefined : "border-error",
      type: 'secondary'
    });
  }

  if (twitchStatus.data)
  {
    accounts.push({
      id: 'twitch', preview: TwitchIcon,
      type: 'secondary'
    });
  }
  const hasAccounts = accounts.length > 0;
  const router = useRouter();

  const { ref } = useFocusable({
    focusKey: 'accounts',
    onEnterPress: handleSelect,
    focusable: hasAccounts
  });



  return <div onClick={handleSelect} ref={ref} style={{ viewTimelineName: "header-accounts" }} className="avatar-group cursor-pointer -space-x-6 w-fit flex items-center gap-2 drop-shadow-sm overflow-visible rounded-3xl focusable focusable-primary focusable-hover ">
    {accounts?.map(a => <HeaderAvatar
      key={`header-avatar-${a.id}`}
      id={`account-${a.id}`}
      locked={a.locked}
      preview={a.preview}
      className={a.className}
      onSelect={a.action}
    />)}
  </div>;
}

export function HeaderStatusBar (data: { buttons?: HeaderButton[]; buttonElements?: JSX.Element[] | JSX.Element; })
{
  const { ref, focusKey } = useFocusable({ focusKey: 'header-status-bar' });
  const { data: update } = useQuery(hasUpdateQuery);
  return <div ref={ref} className="flex items-center sm:gap-1 md:gap-2 text drop-shadow-sm">
    <FocusContext value={focusKey}>
      <div className="flex gap-2 items-center" style={{ viewTransitionName: 'status-bar-icons' }}>
        <ClockStatus />
        <WiFiStatus />
        <BluetoothStatus />
        <NotificationStatus />
        {!!update && update.hasUpdate >= 1 && <UpdateStatus />}
        <BatteryStatus />
      </div>
      {!!data.buttons && <div className="divider divider-horizontal mx-0"></div>}
      <div className="flex gap-2">
        {data.buttonElements}
        {data.buttons?.map(b => <RoundButton
          key={b.id}
          shortcutLabel={b.shortcutLabel}
          className={twMerge("header-icon sm:size-10 md:size-14", b.className)}
          id={b.id}
          external={b.external}
          cssStyle={{ viewTransitionName: `header-button-${b.id}` }}
          onAction={b.action}
        >{b.icon}</RoundButton>)}
      </div>
    </FocusContext>
  </div>;
}

interface HeaderUIParams
{
  buttons?: HeaderButton[];
  accounts?: HeaderAccount[];
  buttonElements?: JSX.Element[] | JSX.Element;
  title?: JSX.Element;
  preferredChildFocusKey?: string;
  focusable?: boolean;
}

export function HeaderUI (data: HeaderUIParams)
{
  const { ref, focusKey } = useFocusable({ focusKey: "header-elements", focusable: data.focusable, preferredChildFocusKey: data.preferredChildFocusKey });
  const router = useRouter();
  const goToSettings = () =>
  {
    router.navigate({ to: '/settings/accounts' });
  };
  return (

    <header
      ref={ref}
      className="flex items-center justify-between text-base-content"
      style={{ viewTimelineName: 'header' }}
    >
      <FocusContext value={focusKey}>
        <HeaderAccounts key={"header-accounts"} accounts={data.accounts} />
        {data.title}
        <HeaderStatusBar
          key={"header-status-bar"}
          buttonElements={data.buttonElements}
          buttons={[
            ...data.buttons ?? [],
            {
              icon: <Settings />,
              id: "header-settings-btn",
              action: goToSettings,
              external: true,
              shortcutLabel: "Settings"
            }
          ]} />

      </FocusContext>
    </header >
  );
}

export function StickyHeaderUI (data: { ref: RefObject<any>; className?: string; children?: any; } & HeaderUIParams)
{
  const [isStuck, setIsStuck] = useState(false);
  const headerRef = useRef(null);
  const sentinelRef = useRef(null);
  useStickyDataAttr(headerRef, sentinelRef, data.ref, setIsStuck);

  return <>
    <div ref={sentinelRef} className="h-0" />
    <div ref={headerRef} className={twMerge('sticky not-mobile:data-stuck:backdrop-blur-xl transition-all top-0 px-2 p-2 not-data-stuck:bg-base-200 mobile:bg-base-300 z-15', data.className)}>
      <HeaderUI focusable={!isStuck} {...data} />
      {data.children}
    </div>
  </>;
}