import React, { FormEvent } from "react";
import { DesktopLinkGroups } from "./desktop-link-groups.tsx";
import { MobileLinkGroups } from "./mobile-link-groups.tsx";
import { NavigationProps } from "./types";

import { CallButton } from "@shared/components/call-button";
import { Input } from "@shared/components/input";
import { Link } from "@shared/components/link";
import { MaterialIcon } from "@shared/components/material-icon";
import { NextImage } from "@shared/components/next-image";
import { Text } from "@shared/components/text";
import { Button as ContentfulButton } from "@shared/contentful/blocks/button";
import { cx } from "@shared/utils";

export const Navigation: React.FC<NavigationProps> = props => {
  const {
    primaryNavigationLinks,
    utilityNavigationLinks,
    checkPlansJSX,
    primaryNavigationLogo,
    accountNavigationLinks,
    supportNavigationLinks,
    searchBarIcon,
    invocaPhoneNumberLink,
    invocaPhoneNumberDisplayText,
    callNowCtaText,
    displayCartIcon,
    cartHref,
    cartHasRetention,
    cartIconAriaLabel = "Cart",
    onCallClickDesktop,
    onCallClickMobile,
    onCartClick,
    onSearch = () => {},
    utilityNavActiveIndex,
    primaryNavigationLogoWidth = 76.5,
    primaryNavigationLogoHeight = 24,
    hideMobileCallButton = false,
    displayUtilityNavigation = true,
    displaySearchBar = true,
    displayCallNowCta = true,
    showCallButton = true,
    showCallNowCtaInMainNav = false,
    showMobileSliderMenu = true,
    callNowCtaIcon,
    navigationBackgroundColor,
    navigationLinkColor,
  } = props;

  const logoUrl =
    typeof primaryNavigationLogo === "string"
      ? primaryNavigationLogo
      : primaryNavigationLogo?.url || "";

  // Background token convention matches the legacy ResidentialNavbar:
  // when CMS provides a token like "navy500" we map it to
  // `bg-secondary-navy500`. Raw Tailwind classes (containing a `-`)
  // are passed through untouched. Defaults to `bg-secondary-navy500`
  // to preserve legacy behavior when CMS leaves the field empty.
  const mainNavBgClass = navigationBackgroundColor
    ? navigationBackgroundColor.includes("-") ||
      navigationBackgroundColor.startsWith("bg-")
      ? navigationBackgroundColor
      : `bg-secondary-${navigationBackgroundColor}`
    : "bg-secondary-navy500";

  const callNowCtaIconUrl =
    typeof callNowCtaIcon === "string"
      ? callNowCtaIcon
      : callNowCtaIcon?.url || "";

  // Styled "Call Now" pill used in the main nav rows when CMS opts in via
  // `showCallNowCtaInMainNav` (desktop) or when the mobile slider menu is
  // disabled (`showMobileSliderMenu: false`). Mirrors the legacy
  // ResidentialNavbar styling so existing CMS entries render identically.
  const renderMainNavCallCta = (
    onClick?: (event: React.MouseEvent<HTMLAnchorElement>) => void
  ) => (
    <Link
      href={invocaPhoneNumberLink || "#"}
      onClick={onClick}
      className="bg-secondary-gray100 text-secondary-navy500 inline-flex h-8 items-center rounded-full pl-1 pr-2 no-underline shadow-none"
      aria-label={
        invocaPhoneNumberDisplayText
          ? `Call ${invocaPhoneNumberDisplayText}`
          : "Call now"
      }
    >
      {callNowCtaIconUrl ? (
        <NextImage
          src={callNowCtaIconUrl}
          alt="Call us"
          width={24}
          height={24}
          className="mr-2 self-center rounded-full"
        />
      ) : null}
      <Text as="span" className="text-secondary-navy500 footnote">
        {invocaPhoneNumberDisplayText}
      </Text>
    </Link>
  );

  const hasMobileMenuItems =
    (primaryNavigationLinks?.length ?? 0) > 0 ||
    (supportNavigationLinks?.length ?? 0) > 0 ||
    (accountNavigationLinks?.length ?? 0) > 0;

  return (
    <div className="component-container">
      <nav className={`menu-container z-[1000]`}>
        {displayUtilityNavigation ? (
          <div className="utility-container hidden lg:block lg:border-b lg:px-2">
            <div className="mx-auto flex max-w-120 justify-between">
              <ul className="flex gap-5" aria-label="Utility Navigation">
                {utilityNavigationLinks?.map((links, index) => {
                  return (
                    <li key={`main-menu-items-${index}`}>
                      <ContentfulButton
                        linkClassName={cx(
                          "footnote flex items-center text-text w-full h-11",
                          // If utilityNavActiveIndex is not provided, default to making the second link active (for existing business app). If utilityNavActiveIndex is provided, use it to determine which link is active.
                          typeof utilityNavActiveIndex !== "number"
                            ? index === 1 && "label4"
                            : utilityNavActiveIndex === index && "label4"
                        )}
                        linkVariant="unstyled"
                        {...(Object.fromEntries(
                          Object.entries(links).filter(([_, v]) => v !== null)
                        ) as any)}
                      />
                    </li>
                  );
                })}
              </ul>
              <div className="flex items-center gap-10">
                {displayCallNowCta ? (
                  <CallButton
                    className="border-none"
                    href={invocaPhoneNumberLink}
                    prefix={callNowCtaText}
                    onClick={onCallClickDesktop}
                  >
                    <Text className="body3 text-text">
                      {invocaPhoneNumberDisplayText}
                    </Text>
                  </CallButton>
                ) : null}
                {displayCartIcon ? (
                  <Link
                    href={cartHref || "#"}
                    className="relative inline-flex cursor-pointer"
                    aria-label={cartIconAriaLabel}
                    onClick={onCartClick}
                  >
                    <MaterialIcon name="shopping_cart" />

                    {cartHasRetention && (
                      <span className="absolute -right-2 -top-1 h-2.5 w-2.5 rounded-full bg-icon-brand" />
                    )}
                  </Link>
                ) : null}
                {accountNavigationLinks?.map((links, index) => {
                  return (
                    <DesktopLinkGroups
                      key={`my-account-${index}`}
                      anchorName={`my-account-${index}`}
                      link={links}
                    />
                  );
                })}
              </div>
            </div>
          </div>
        ) : null}
        <div
          className={cx(
            "main-nav-container",
            mainNavBgClass,
            navigationLinkColor
          )}
          aria-label="Main Navigation"
        >
          <div className="mobile-nav-section flex h-14 items-center justify-between border border-b px-5 py-[10px] lg:hidden">
            <div>
              {logoUrl ? (
                <Link href="/" className="flex">
                  <NextImage
                    src={logoUrl}
                    alt="Kinetic business logo"
                    width={primaryNavigationLogoWidth}
                    height={primaryNavigationLogoHeight}
                  />
                </Link>
              ) : null}
            </div>
            <div className="flex items-center gap-6">
              {!showMobileSliderMenu ? (
                showCallButton ? (
                  renderMainNavCallCta(onCallClickMobile)
                ) : null
              ) : (
                <>
                  {showCallButton && !hideMobileCallButton ? (
                    <CallButton
                      href={invocaPhoneNumberLink}
                      onClick={onCallClickMobile}
                    >
                      <Text as="span" className="footnote">
                        {invocaPhoneNumberDisplayText}
                      </Text>
                    </CallButton>
                  ) : null}
                  {displayCartIcon ? (
                    <Link
                      href={cartHref || "#"}
                      className="relative inline-flex cursor-pointer"
                      aria-label={cartIconAriaLabel}
                      onClick={onCartClick}
                    >
                      <MaterialIcon name="shopping_cart" />
                      {cartHasRetention ? (
                        <span className="absolute -right-2 -top-1 h-2.5 w-2.5 rounded-full bg-icon-brand" />
                      ) : null}
                    </Link>
                  ) : null}
                  {hasMobileMenuItems ? <MobileMenu {...props} /> : null}
                </>
              )}
            </div>
          </div>

          <div className="desktop-nav-section hidden lg:block lg:border-b lg:px-2">
            <div className="mx-auto flex h-14 max-w-120 items-center justify-between">
              <div className="flex h-full">
                {logoUrl ? (
                  <Link href="/" className="flex">
                    <NextImage
                      src={logoUrl}
                      alt="Kinetic business logo"
                      width={primaryNavigationLogoWidth}
                      height={primaryNavigationLogoHeight}
                      className="mr-[64px]"
                    />
                  </Link>
                ) : null}

                <div className="flex h-full items-center gap-6">
                  {primaryNavigationLinks?.map((links, index) => {
                    return (
                      <DesktopLinkGroups
                        key={`main-menu-${index}`}
                        anchorName={`main-menu-${index}`}
                        link={links}
                        linkColorClassName={navigationLinkColor}
                      />
                    );
                  })}
                </div>
              </div>
              <div className="flex h-full items-center gap-10">
                {showCallNowCtaInMainNav &&
                !(displayUtilityNavigation && displayCallNowCta)
                  ? renderMainNavCallCta(onCallClickDesktop)
                  : null}
                {displaySearchBar ? (
                  <DesktopSearchInput
                    searchBarIconURL={
                      typeof searchBarIcon === "string"
                        ? searchBarIcon
                        : searchBarIcon?.url || ""
                    }
                    onSearch={onSearch}
                  />
                ) : null}
                {supportNavigationLinks?.map((links, index) => {
                  return (
                    <DesktopLinkGroups
                      key={`support-menu-${index}`}
                      anchorName={`support-menu-${index}`}
                      link={links}
                      linkColorClassName={navigationLinkColor}
                    />
                  );
                })}
              </div>
            </div>
          </div>
        </div>
      </nav>

      {checkPlansJSX && <div className="md:hidden">{checkPlansJSX}</div>}
    </div>
  );
};

const MobileMenu = (props: NavigationProps) => {
  const {
    primaryNavigationLinks,
    utilityNavigationLinks,
    supportNavigationLinks,
    accountNavigationLinks,
    showCallButton,
    displayCallNowCta,
    displaySearchBar,
  } = props;
  const [isOpen, setIsOpen] = React.useState(false);

  React.useEffect(() => {
    if (typeof window === "undefined") return;

    if (isOpen) document.body.style.overflowY = "hidden";
    else document.body.style.overflowY = "unset";

    const element = document.getElementById("drawer-items");
    if (!element) return;

    const focusableEls = element.querySelectorAll(".focus-item");
    const firstFocusableEl = focusableEls[0];
    const lastFocusableEl = focusableEls[focusableEls.length - 1];

    const handleKeyDown = (e: {
      key: string;
      keyCode: number;
      shiftKey: any;
      preventDefault: () => void;
    }) => {
      const isTabPressed = e.key === "Tab" || e.keyCode === 9;

      if (!isTabPressed) return;

      if (e.shiftKey) {
        if (document.activeElement === firstFocusableEl) {
          (lastFocusableEl as HTMLButtonElement).focus?.();
          e.preventDefault();
        }
      } else {
        if (document.activeElement === lastFocusableEl) {
          (firstFocusableEl as HTMLButtonElement).focus?.();
          e.preventDefault();
        }
      }
    };

    window.addEventListener("keydown", handleKeyDown);

    return () => {
      document.body.style.overflowY = "unset";
      window.removeEventListener("keydown", handleKeyDown);
    };
  }, [isOpen]);

  const closeMenu = () => {
    setIsOpen(false);
  };

  return (
    <div>
      <ContentfulButton
        showButtonAs="unstyled"
        buttonClassName="flex"
        onClick={() => setIsOpen(true)}
      >
        <MaterialIcon name="menu" />
      </ContentfulButton>
      {isOpen ? (
        <div className="fixed bottom-0 left-0 right-0 top-0 z-[90] h-full w-full bg-scrim-bg-modal"></div>
      ) : null}

      <div
        className={cx(
          "fixed bottom-0 right-0 top-0",
          "z-[100] h-full bg-bg px-0 py-4 text-text",
          "transition-all duration-300 ease-in-out",
          "block",
          isOpen ? "right-0" : "-right-96"
        )}
        id="mobile-menu-overlay"
      >
        <div id="drawer-items" className="flex h-full flex-col gap-3">
          <div
            className={cx(
              "flex items-center px-4",
              showCallButton !== false || displayCallNowCta !== false
                ? "justify-between"
                : "justify-end"
            )}
          >
            {showCallButton !== false || displayCallNowCta !== false ? (
              <div>
                <CallButton
                  className="border-none"
                  href={props.invocaPhoneNumberLink}
                  onClick={props.onCallClickMobile}
                >
                  {props.invocaPhoneNumberDisplayText}
                </CallButton>
              </div>
            ) : null}
            <div>
              <ContentfulButton
                showButtonAs="unstyled"
                buttonClassName="focus-item flex"
                onClick={closeMenu}
              >
                <MaterialIcon name="close" />
              </ContentfulButton>
            </div>
          </div>
          {displaySearchBar !== false ? (
            <MobileSearchInput
              closeMenu={closeMenu}
              isMenuOpen={isOpen}
              searchBarIconURL={
                typeof props.searchBarIcon === "string"
                  ? props.searchBarIcon
                  : props.searchBarIcon?.url || ""
              }
              onSearch={props.onSearch || (() => {})}
            />
          ) : null}
          <div
            className="flex-grow overflow-y-auto"
            onClick={event => {
              // Close the drawer when a link (anchor) is clicked.
              // Group-toggle buttons render as <button> and won't match,
              // so they continue to expand/collapse normally.
              // Required for Pages Router where MobileMenu persists across
              // client-side navigations and its local `isOpen` state would
              // otherwise stay true on the new route.
              const target = event.target as HTMLElement | null;
              if (target?.closest("a")) {
                closeMenu();
              }
            }}
          >
            <ul className="mt-2 flex flex-col gap-2">
              {[
                ...(primaryNavigationLinks || []),
                ...(supportNavigationLinks || []),
                ...(accountNavigationLinks || []),
              ].map((links, index) => (
                <li key={`main-menu-items-${index}`}>
                  <MobileLinkGroups link={links} />
                </li>
              ))}
            </ul>

            <ul className="mt-2 flex gap-5 bg-bg-fill-info px-4">
              {utilityNavigationLinks?.map((link, index) => {
                return (
                  <li key={`utility-menu-items-${index}`}>
                    <ContentfulButton
                      key={`utility-submenu-link-btn-${link.anchorId}`}
                      {...(Object.fromEntries(
                        Object.entries(link).filter(([_, v]) => v !== null)
                      ) as any)}
                      linkClassName={cx(
                        "footnote flex items-center w-full h-11 text-text-link",
                        typeof props.utilityNavActiveIndex !== "number"
                          ? index === 1 && "label4"
                          : props.utilityNavActiveIndex === index && "label4"
                      )}
                      linkVariant="unstyled"
                    />
                  </li>
                );
              })}
            </ul>
          </div>
        </div>
      </div>
    </div>
  );
};

const MobileSearchInput = (props: {
  closeMenu: () => void;
  onSearch: (query: string) => void;
  isMenuOpen: boolean;
  searchBarIconURL: string;
}) => {
  const { closeMenu, onSearch, isMenuOpen, searchBarIconURL } = props;
  const [searchValue, setSearchValue] = React.useState("");
  const searchInputRef = React.useRef<HTMLInputElement>(null);

  const redirectToSearchResults = (e: FormEvent<HTMLFormElement> | any) => {
    closeMenu();
    e.preventDefault();
    onSearch(searchValue);
  };

  React.useEffect(() => {
    if (!isMenuOpen) {
      setSearchValue("");
    }
  }, [isMenuOpen]);

  return (
    <form
      name="searchForm"
      className="flex border-b border-t transition-colors focus-within:border-border-focus"
      onSubmit={redirectToSearchResults}
    >
      <NextImage
        src={searchBarIconURL}
        width={32}
        height={32}
        className="ml-2"
        alt="Search icon"
        role="button"
        onClick={redirectToSearchResults}
      />
      <div className="flex-grow">
        <Input
          ref={searchInputRef}
          className={"body3 h-[34px] rounded-none px-3 text-text"}
          name="search"
          placeholder="Search..."
          value={searchValue}
          onChange={e => setSearchValue(e.target.value)}
          autoComplete="off"
          containerClassName="h-[46px] px-4 pl-0 rounded-none flex-grow border-none"
        />
      </div>
    </form>
  );
};

const DesktopSearchInput = (props: {
  searchBarIconURL: string;
  onSearch: (query: string) => void;
}) => {
  const { searchBarIconURL, onSearch } = props;
  const [searchValue, setSearchValue] = React.useState("");
  const searchInputRef = React.useRef<HTMLInputElement>(null);

  const redirectToSearchResults = (e: FormEvent<HTMLFormElement> | any) => {
    e.preventDefault();
    onSearch(searchValue);
  };

  return (
    <form
      name="searchForm"
      className="flex h-9 w-60 rounded-input-xl border px-1 transition-colors focus-within:border-border-focus"
      onSubmit={redirectToSearchResults}
    >
      {/* Search Icon */}
      <NextImage
        src={searchBarIconURL}
        width={32}
        height={32}
        alt="Search icon"
        role="button"
        onClick={redirectToSearchResults} />
      {/* Input */}
      <Input
        ref={searchInputRef}
        type="text"
        name="search"
        placeholder="Search..."
        value={searchValue}
        onChange={e => setSearchValue(e.target.value)}
        className={"body3 rounded-full px-3 text-text"}
        containerClassName="px-0 h-full border-none rounded-full"
        autoComplete="off"
      />
    </form>
  );
};
