import { Inbox, X } from "lucide-react";
import { useMemo, useState } from "react";
import { createPortal } from "react-dom";
import type { Client } from "../../entities/client/types";
import { PUBLIC_POOL_CLIENT, isPublicPoolClientId } from "../../entities/public-pool/constants";
import type { MeResponse, ProfileOption } from "../../shared/api/mockApi";
import { initials } from "../../shared/lib/format";
import { NodeDcProfileMenu, NodeDcSelect, type NodeDcSelectOption } from "../../shared/nodedc-ui";

export type LauncherAdminMode = "admin" | "platform";
export type LauncherNotificationKind = "nodedc" | "operational-core" | "engine";
export type LauncherNotificationStatus = "unread" | "read" | "archived";

export interface LauncherNotificationItem {
  id: string;
  kind: LauncherNotificationKind;
  title: string;
  description: string;
  meta?: string;
  displayStatus?: string;
  status: LauncherNotificationStatus;
  createdAt: string;
  updatedAt?: string | null;
  actionKind?: "engine-role-request";
  requestId?: string;
  requestedServiceRole?: "viewer" | "member" | null;
}

type EngineRoleActionValue = "choose" | "viewer" | "member";

const engineRoleActionOptions: Array<NodeDcSelectOption<EngineRoleActionValue>> = [
  { value: "choose", label: "Изменить роль" },
  { value: "viewer", label: "Гость" },
  { value: "member", label: "Участник" },
];

export function TopBar({
  me,
  clients,
  profileOptions,
  activeProfileId,
  activeClientId,
  adminOpen,
  adminMode,
  onProfileChange,
  onClientChange,
  onOpenAdmin,
  onOpenPlatform,
  onOpenShowcase,
  onOpenProfileSettings,
  onLogout,
  brandLinkUrl = "/",
  notifications = [],
  onMarkNotificationsRead,
  onResolveEngineRoleRequest,
}: {
  me: MeResponse;
  clients: Client[];
  profileOptions: ProfileOption[];
  activeProfileId: string;
  activeClientId: string;
  adminOpen: boolean;
  adminMode: LauncherAdminMode;
  onProfileChange: (userId: string) => void;
  onClientChange: (clientId: string) => void;
  onOpenAdmin: () => void;
  onOpenPlatform: () => void;
  onOpenShowcase: () => void;
  onOpenProfileSettings: () => void;
  onLogout?: () => void;
  brandLinkUrl?: string;
  notifications?: LauncherNotificationItem[];
  onMarkNotificationsRead?: () => void | Promise<unknown>;
  onResolveEngineRoleRequest?: (requestId: string, action: "approve" | "reject", serviceRole?: "viewer" | "member", deliveryId?: string) => void | Promise<unknown>;
}) {
  const [notificationsOpen, setNotificationsOpen] = useState(false);
  const [notificationFilter, setNotificationFilter] = useState<LauncherNotificationKind | "all">("all");
  const [notificationsOnlyNew, setNotificationsOnlyNew] = useState(false);
  const [resolvingNotificationIds, setResolvingNotificationIds] = useState<Record<string, boolean>>({});
  const availableClientIds = new Set(me.memberships.map((membership) => membership.clientId));
  const clientsWithPublicPool = [
    ...clients,
    availableClientIds.has(PUBLIC_POOL_CLIENT.id) && !clients.some((client) => isPublicPoolClientId(client.id)) ? PUBLIC_POOL_CLIENT : null,
  ].filter((client): client is Client => Boolean(client));
  const availableClients = clientsWithPublicPool.filter((client) => availableClientIds.has(client.id));
  const activeClient = availableClients.find((client) => client.id === activeClientId);
  const clientOptions = availableClients.map((client) => ({
    value: client.id,
    label: client.name,
    description: client.legalName ?? undefined,
  }));
  const canOpenPlatform = me.launcherRole === "root_admin";
  const showLauncherNavigation = me.permissions.canOpenAdmin || canOpenPlatform;
  const unreadCount = notifications.filter((notification) => notification.status === "unread").length;
  const visibleNotifications = useMemo(
    () => notifications.filter((notification) => {
      if (notificationsOnlyNew && notification.status !== "unread") return false;
      return notificationFilter === "all" || notification.kind === notificationFilter;
    }),
    [notificationFilter, notifications, notificationsOnlyNew]
  );

  function markNotificationsSeen() {
    if (unreadCount <= 0) return;
    void Promise.resolve(onMarkNotificationsRead?.());
  }

  function closeNotifications() {
    markNotificationsSeen();
    setNotificationsOpen(false);
  }

  function resolveEngineRoleNotification(requestId: string, action: "approve" | "reject", serviceRole?: "viewer" | "member", deliveryId?: string) {
    if (!onResolveEngineRoleRequest || resolvingNotificationIds[requestId]) return;
    setResolvingNotificationIds((current) => ({ ...current, [requestId]: true }));
    Promise.resolve(onResolveEngineRoleRequest(requestId, action, serviceRole, deliveryId))
      .finally(() => {
        setResolvingNotificationIds((current) => {
          const { [requestId]: _done, ...rest } = current;
          return rest;
        });
      });
  }

  const notificationsModal = notificationsOpen && typeof document !== "undefined"
    ? createPortal(
        <div className="nodedc-notifications-overlay" onMouseDown={closeNotifications}>
          <section className="nodedc-notifications-modal" aria-modal="true" role="dialog" onMouseDown={(event) => event.stopPropagation()}>
            <div className="nodedc-notifications-head">
              <div>
                <h2>Уведомления</h2>
                <span>NODE DC</span>
              </div>
              <div className="nodedc-notifications-head__actions">
                <button
                  className="nodedc-notifications-only-new"
                  type="button"
                  data-active={notificationsOnlyNew ? "true" : "false"}
                  onClick={() => setNotificationsOnlyNew((current) => !current)}
                >
                  Только новые
                </button>
                <button className="nodedc-notifications-close" type="button" aria-label="Закрыть" onClick={closeNotifications}>
                  <X size={18} strokeWidth={1.8} />
                </button>
              </div>
            </div>

            <div className="nodedc-notifications-tabs" role="tablist" aria-label="Фильтр уведомлений">
              <NotificationFilterButton active={notificationFilter === "all"} onClick={() => setNotificationFilter("all")}>
                Все
              </NotificationFilterButton>
              <NotificationFilterButton active={notificationFilter === "nodedc"} onClick={() => setNotificationFilter("nodedc")}>
                NODE.DC
              </NotificationFilterButton>
              <NotificationFilterButton active={notificationFilter === "operational-core"} onClick={() => setNotificationFilter("operational-core")}>
                Operational Core
              </NotificationFilterButton>
              <NotificationFilterButton active={notificationFilter === "engine"} onClick={() => setNotificationFilter("engine")}>
                Engine
              </NotificationFilterButton>
            </div>

            <div className="nodedc-notifications-list">
              {visibleNotifications.length === 0 ? (
                <div className="nodedc-notifications-empty">
                  <strong>Уведомлений нет</strong>
                  <span>История заявок NODE.DC, Operational Core и Engine появится здесь.</span>
                </div>
              ) : (
                visibleNotifications.map((notification) => {
                  const unread = notification.status === "unread";
                  return (
                  <article className="nodedc-notification-card" data-status={unread ? "new" : notification.status} key={notification.id}>
                    <div className="nodedc-notification-card__content">
                      <div className="nodedc-notification-card__kicker">{notificationKindLabel(notification.kind)}</div>
                      <div className="nodedc-notification-card__title">{notification.title}</div>
                      <div className="nodedc-notification-card__description">{notification.description}</div>
                      <div className="nodedc-notification-card__foot">
                        <span>{notification.displayStatus || notificationStatusLabel(notification.status)}</span>
                        {notification.meta ? <span>{notification.meta}</span> : null}
                      </div>
                    </div>
                    {notification.actionKind === "engine-role-request" &&
                    notification.requestId &&
                    notification.status === "unread" &&
                    onResolveEngineRoleRequest ? (
                      <div className="nodedc-notification-card__actions">
                        {(() => {
                          const requestBusy = Boolean(resolvingNotificationIds[notification.requestId]);
                          return (
                            <>
                        <button
                          className="nodedc-notification-card__action-button"
                          type="button"
                                  disabled={requestBusy}
                                  onClick={() => resolveEngineRoleNotification(notification.requestId!, "reject", undefined, notification.id)}
                        >
                          Отклонить
                        </button>
                                <NodeDcSelect<EngineRoleActionValue>
                                  className="nodedc-notification-card__role-select-wrap"
                                  triggerClassName="nodedc-notification-card__role-select"
                                  menuClassName="nodedc-notification-card__role-menu"
                                  value="choose"
                                  options={engineRoleActionOptions}
                                  label="Изменить роль Engine"
                                  minMenuWidth={166}
                                  disabled={requestBusy}
                                  onChange={(value) => {
                                    if (value === "viewer" || value === "member") {
                                      resolveEngineRoleNotification(notification.requestId!, "approve", value, notification.id);
                                    }
                                  }}
                                />
                              </>
                            );
                          })()}
                      </div>
                    ) : null}
                  </article>
                  );
                })
              )}
            </div>
          </section>
        </div>,
        document.body
      )
    : null;

  return (
    <header className="nodedc-expanded-toolbar-shell">
      <div className="nodedc-expanded-toolbar">
        <div className="nodedc-expanded-toolbar-top">
          <div className="nodedc-expanded-toolbar-left">
            <a href={brandLinkUrl} className="nodedc-expanded-brand-link" aria-label="NODE.DC">
              <img src="/nodedc-logo.svg" alt="NODE DC" className="nodedc-expanded-brand-logo" />
            </a>
          </div>

          <div className="nodedc-expanded-toolbar-center">
            {showLauncherNavigation ? (
              <>
                <NodeDcSelect
                  value={activeClientId}
                  options={clientOptions}
                  label="Выбрать клиента"
                  searchable
                  minMenuWidth={248}
                  onChange={(clientId) => onClientChange(clientId)}
                  trigger={({ open, toggle, setTriggerRef }) => (
                    <button
                      ref={setTriggerRef}
                      className="nodedc-expanded-workspace-button"
                      title={activeClient?.name ?? "Клиент"}
                      type="button"
                      aria-label="Выбрать клиента"
                      aria-expanded={open}
                      onClick={toggle}
                    >
                      {activeClient?.avatarUrl ? <img src={activeClient.avatarUrl} alt="" className="nodedc-expanded-workspace-avatar" /> : null}
                    </button>
                  )}
                />

                <nav className="nodedc-expanded-nav-group" aria-label="Навигация лаунчера">
                  <button className="nodedc-expanded-nav-button" type="button" data-active={!adminOpen} onClick={onOpenShowcase}>
                    <span>Витрина</span>
                  </button>

                  {me.permissions.canOpenAdmin ? (
                    <button
                      className="nodedc-expanded-nav-button"
                      type="button"
                      data-active={adminOpen && adminMode === "admin"}
                      onClick={onOpenAdmin}
                    >
                      <span>Администрирование</span>
                    </button>
                  ) : null}

                  {canOpenPlatform ? (
                    <button
                      className="nodedc-expanded-nav-button"
                      type="button"
                      data-active={adminOpen && adminMode === "platform"}
                      onClick={onOpenPlatform}
                    >
                      <span>Платформа</span>
                    </button>
                  ) : null}
                </nav>
              </>
            ) : null}
          </div>

          <div className="nodedc-expanded-toolbar-right">
            <div className="nodedc-expanded-user-group">
              <button
                className="nodedc-toolbar-icon-button nodedc-expanded-notification-button"
                data-active={unreadCount > 0 ? "true" : "false"}
                type="button"
                aria-label="Уведомления"
                onClick={() => setNotificationsOpen(true)}
              >
                <span className="nodedc-toolbar-icon-active-dot">
                  <Inbox size={20} strokeWidth={1.7} />
                </span>
                {unreadCount > 0 ? <span className="nodedc-notification-badge">{unreadCount > 9 ? "9+" : unreadCount}</span> : null}
              </button>
              <NodeDcProfileMenu
                user={me.user}
                onSettings={onOpenProfileSettings}
                onLogout={onLogout}
                trigger={({ open, toggle, setTriggerRef }) => (
                  <div
                    ref={setTriggerRef}
                    className="nodedc-expanded-profile-trigger"
                    title={`${me.user.name} · ${me.user.email}`}
                    role="button"
                    tabIndex={0}
                    aria-label="Профиль пользователя"
                    aria-expanded={open}
                    onClick={toggle}
                    onKeyDown={(event) => {
                      if (event.key === "Enter" || event.key === " ") {
                        event.preventDefault();
                        toggle();
                      }
                    }}
                  >
                    <span className="nodedc-expanded-nav-button" data-active="false">
                      <span>Профиль</span>
                    </span>
                    <span className="nodedc-expanded-user-avatar-button" aria-hidden="true">
                      {me.user.avatarUrl ? (
                        <img className="nodedc-expanded-user-avatar" src={me.user.avatarUrl} alt="" style={{ objectFit: "cover" }} />
                      ) : (
                        <span className="nodedc-expanded-user-avatar">{initials(me.user.name)}</span>
                      )}
                    </span>
                  </div>
                )}
              />
            </div>
            {notificationsModal}
          </div>
        </div>
      </div>
    </header>
  );
}

function NotificationFilterButton({
  active,
  children,
  onClick,
}: {
  active: boolean;
  children: string;
  onClick: () => void;
}) {
  return (
    <button className="nodedc-notifications-tab" data-active={active ? "true" : "false"} type="button" onClick={onClick}>
      {children}
    </button>
  );
}

function notificationKindLabel(kind: LauncherNotificationKind): string {
  const labels: Record<LauncherNotificationKind, string> = {
    nodedc: "NODE.DC",
    "operational-core": "Operational Core",
    engine: "NODE.DC Engine",
  };

  return labels[kind];
}

function notificationStatusLabel(status: LauncherNotificationStatus): string {
  const labels: Record<LauncherNotificationStatus, string> = {
    unread: "Входящее",
    read: "Прочитано",
    archived: "В архиве",
  };

  return labels[status];
}
