import type { ReactNode } from "react";

import type { SitePayload, MenuItem, MetaPayload } from "@/lib/api";
import { LOCALES, type LocaleCode } from "@/lib/locales";
import type { Translator } from "@/lib/i18n";

import HtmlAttributes from "./HtmlAttributes";
import PageContext from "./PageContext";
import MediaImage from "./ui/MediaImage";
import MobileNav from "./MobileNav";
import SidePanel from "./SidePanel";
import FloatingContact from "./FloatingContact";
import { formLabels } from "./sections";
import CodeSnippets from "./CodeSnippets";

/**
 * Header, main and footer — the markup of partials/header.blade.php and
 * partials/footer.blade.php.
 *
 * `data-page` sits on the outermost wrapper rather than on <body>. All 85
 * occurrences of that attribute in site.css are *descendant* selectors
 * (`body[data-page="project"] .x`) and none style body itself, so scoping them
 * to a wrapper that is body's only child matches an identical element set. The
 * stylesheet was rewritten accordingly, once, with sed.
 *
 * The reason for moving it: Next's App Router only lets the root layout emit
 * <body>, and the root layout cannot see the resolved template of a deep dynamic
 * segment without opting the whole route out of static rendering. Setting it
 * from client JS instead would break the "renders without JavaScript"
 * requirement — 29 rules would not apply for a reader without scripting.
 */
export default function SiteChrome({
  children,
  site,
  locale,
  path,
  dir,
  dataPage,
  meta,
  t,
}: {
  children: ReactNode;
  site: SitePayload | null;
  locale: LocaleCode;
  path: string;
  dir: "rtl" | "ltr";
  dataPage: string;
  meta: MetaPayload;
  t: Translator;
}) {
  const brand = site?.siteName ?? "";

  /*
   * Per-URL features are only paid for when they are in use.
   *
   * Both of these force an uncacheable request on every page view, because a
   * cached response would serve one URL's targeting to another. The counts come
   * from the cached /site payload, so a site with none configured skips them
   * entirely.
   */
  const flags = site?.hasPageContext;
  const snippetsEnabled = flags?.snippets ?? true;
  const contextEnabled = (flags?.popups ?? true) || (flags?.actionBars ?? true);

  return (
    <>
      {/*
        Mirrors lang/dir onto <html>, which only the root layout may render.
        The wrapper below already carries them server-side, so a reader without
        JavaScript still gets a correctly-directioned page; this exists for
        document-level behaviour and for locale switches during client-side
        navigation, where no new document is parsed.
      */}
      <HtmlAttributes lang={site?.htmlLang ?? locale} dir={dir} />

      {/*
        `dir` and `lang` are on the wrapper, not only on <html>, and that is
        deliberate: both are global attributes that apply to their subtree, so
        the Arabic RTL default renders correctly in the server HTML with no
        script involved.
      */}
      <div data-page={dataPage} dir={dir} lang={site?.htmlLang ?? locale}>
        {/*
          Editor-managed tags, resolved during the server render so they fire in
          the same order they did on the Blade site. Fetching them after
          hydration would change when analytics run and break attribution.
        */}
        <CodeSnippets locale={locale} path={path} position="head" enabled={snippetsEnabled} />
        <CodeSnippets locale={locale} path={path} position="bodyStart" enabled={snippetsEnabled} />

        <header className="site-header" id="site-header">
          <a className="skip-link" href="#main">
            {t("ui.skip_to_content")}
          </a>

          <div className="header-inner">
            <a className="site-logo" href={site?.homeUrl ?? "/"} aria-label={brand}>
              {/*
                The dimensions are the box the stylesheet actually paints, not
                the file's own 373x500: the browser derives its aspect ratio from
                these, and 150x42 described a shape the logo has never had.
                `sizes` matches too, so the picked candidate is chosen for a 67px
                slot rather than for the full viewport.
              */}
              {site?.logo ? (
                <MediaImage
                  image={{ ...site.logo, sizes: "67px", width: 67, height: 90 }}
                  alt={brand}
                  eager
                />
              ) : (
                <img src="/assets/logo.png" alt={brand} width={67} height={90} />
              )}
            </a>

            <MobileNav
              nav={site?.menus?.header ?? []}
              canonical={meta.canonical}
              labels={{
                open: t("js.open_menu"),
                navigation: t("ui.main_navigation"),
                contact: t("ui.open_contact"),
              }}
              languages={<LanguageToggles meta={meta} locale={locale} />}
            />
          </div>
        </header>

        <main id="main">{children}</main>

        <SiteFooter site={site} t={t} brand={brand} />

        <SidePanel site={site} t={t} brand={brand} />

        <FloatingContact
          telUrl={site?.contact?.telUrl ?? null}
          whatsappUrl={site?.contact?.whatsappUrl ?? null}
          labels={{
            hide: t("js.hide_contact"),
            interest: t("ui.register_interest"),
            whatsapp: t("ui.whatsapp"),
            phone: t("ui.phone"),
            close: t("js.close_menu"),
          }}
          formLabels={formLabels(t)}
          locale={locale}
        />

        {/*
          Popups and action bars: per-URL and per-request, so they cannot live in
          the cached page payload.
        */}
        <PageContext locale={locale} path={path} enabled={contextEnabled} />

        <CodeSnippets locale={locale} path={path} position="bodyEnd" enabled={snippetsEnabled} />

        <a className="back-to-top" href="#" aria-label={t("ui.back_to_top")}>
          <svg viewBox="0 0 10 41" aria-hidden="true">
            <path className="back-to-top__stem" d="M5 41V9" />
            <path className="back-to-top__head" d="M5 0l5 8.75H0z" />
          </svg>
        </a>
      </div>
    </>
  );
}

/**
 * The language switcher targets this page's counterpart, not the other
 * language's home.
 *
 * Built from `meta.alternates` — the same PageMeta the canonical and hreflang
 * come from. When no counterpart exists the link still works but is marked with
 * `--home`, so a visitor is never silently dumped somewhere else.
 */
function LanguageToggles({ meta, locale }: { meta: MetaPayload; locale: LocaleCode }) {
  return (
    <>
      {(Object.keys(LOCALES) as LocaleCode[])
        .filter((code) => code !== locale)
        .map((code) => {
          const available = Boolean(meta.alternates[code]);
          const config = LOCALES[code];

          return (
            <a
              key={code}
              className={`lang-toggle${available ? "" : " lang-toggle--home"}`}
              href={meta.alternates[code] ?? (code === "ar" ? "/" : `/${code}`)}
              hrefLang={config.hreflang}
              lang={config.hreflang}
              aria-label={config.native}
            >
              {config.short}
            </a>
          );
        })}
    </>
  );
}

function SiteFooter({
  site,
  t,
  brand,
}: {
  site: SitePayload | null;
  t: Translator;
  brand: string;
}) {
  const contact = site?.contact ?? ({} as any);
  const address = contact.addressStreet || contact.addressLocality || "";
  const columns = [site?.menus?.footerPrimary ?? [], site?.menus?.footerSecondary ?? []].filter(
    (column) => column.length > 0,
  );

  return (
    <footer className="site-footer" id="site-footer">
      <div className="footer-pattern">
        <div className="footer-shell">
          <div className="footer-main">
            <section className="footer-col footer-contact">
              <h3>{t("ui.contact_us_title")}</h3>
              <p className="footer-contact__intro">{t("ui.contact_intro")}</p>

              {contact.phoneDisplay ? (
                <p>
                  <a href={contact.telUrl ?? undefined} dir="ltr">
                    {contact.phoneDisplay}
                  </a>
                </p>
              ) : null}

              {/* The number is spelled out beside the label, as the design has
                  it — the label alone said nothing about which number it
                  opened. */}
              {contact.whatsappUrl ? (
                <p>
                  <a href={contact.whatsappUrl} target="_blank" rel="noopener noreferrer">
                    {t("ui.whatsapp")}:<span dir="ltr">{contact.phoneDisplay}</span>
                  </a>
                </p>
              ) : null}

              {contact.email ? (
                <>
                  <p>{t("ui.email_intro")}</p>
                  <p>
                    <a href={`mailto:${contact.email}`} dir="ltr">
                      {contact.email}
                    </a>
                  </p>
                </>
              ) : null}

              <Socials site={site} label={t("ui.social_media")} />
            </section>

            {columns.length > 0 ? (
              <section className="footer-col footer-links-col">
                <h4>{t("ui.important_links")}</h4>
                <div className="footer-links">
                  {columns.map((column, index) => (
                    <ul key={index}>
                      {column.map((item, i) => (
                        <li key={i}>
                          <a
                            href={item.url ?? undefined}
                            target={item.target !== "_self" ? item.target ?? undefined : undefined}
                            rel={item.target !== "_self" ? "noopener" : undefined}
                          >
                            {item.label}
                          </a>
                        </li>
                      ))}
                    </ul>
                  ))}
                </div>
              </section>
            ) : null}

            <section className="footer-col footer-office">
              <h4>{t("ui.main_office")}</h4>
              {address ? (
                <p>
                  {contact.mapLink ? (
                    <a href={contact.mapLink} target="_blank" rel="noopener noreferrer">
                      {address}
                    </a>
                  ) : (
                    address
                  )}
                </p>
              ) : null}
              {site?.subsidiariesUrl ? (
                <a className="btn btn--fill" href={site.subsidiariesUrl}>
                  {t("ui.subsidiaries")}
                </a>
              ) : null}
            </section>
          </div>
        </div>
      </div>

      <div className="footer-bottom">
        <div className="footer-shell footer-bottom__inner">
          {site?.parentCompany?.url ? (
            <a
              className="footer-brand"
              href={site.parentCompany.url}
              target="_blank"
              rel="noopener noreferrer"
            >
              <img
                src="/assets/footer-holding-logo.png"
                alt={site.parentCompany.name ?? ""}
                width={120}
                height={40}
                loading="lazy"
              />
            </a>
          ) : null}
          <div className="footer-copyright">
            © {new Date().getFullYear()} <strong>{brand}</strong>، {t("ui.all_rights_reserved")}
          </div>
        </div>
      </div>
    </footer>
  );
}

function Socials({ site, label }: { site: SitePayload | null; label: string }) {
  const profiles = site?.socials ?? [];

  if (profiles.length === 0) {
    return null;
  }

  return (
    <div className="socials" aria-label={label}>
      {profiles.map((profile) => (
        <a
          key={profile.key}
          href={profile.url}
          target="_blank"
          rel="noopener noreferrer"
          aria-label={profile.label}
        >
          <svg viewBox={profile.viewBox} aria-hidden="true">
            <path d={profile.path} />
          </svg>
        </a>
      ))}
    </div>
  );
}

export type { MenuItem };
