import { useEffect, useMemo } from "react";
import { useSearchParams } from "react-router-dom";
import type {
  AdminSectionContribution,
  AdminSectionsUiCapability,
  ApiSettings,
  AuthInfo,
  FilesConnectorsUiCapability,
  MailProfilesUiCapability,
  OrganizationFunctionPickerUiCapability
} from "@govoplan/core-webui";
import { fetchMe } from "@govoplan/core-webui";
import { Card } from "@govoplan/core-webui";
import { ModuleSubnav, type ModuleSubnavGroup } from "@govoplan/core-webui";
import { adminReadScopes, hasAnyScope, hasScope } from "@govoplan/core-webui";
import SystemUsersPanel from "./SystemUsersPanel";
import TenantSettingsPanel from "./TenantSettingsPanel";
import SystemRolesPanel from "./SystemRolesPanel";
import TenantsPanel from "./TenantsPanel";
import UsersPanel from "./UsersPanel";
import GroupsPanel from "./GroupsPanel";
import RolesPanel from "./RolesPanel";
import ExternalFunctionRoleMappingsPanel from "./ExternalFunctionRoleMappingsPanel";
import ApiKeysPanel from "./ApiKeysPanel";
import FileConnectorsPanel from "./FileConnectorsPanel";
import MailProfilesPanel from "./MailProfilesPanel";
import { usePlatformUiCapabilities, usePlatformUiCapability } from "@govoplan/core-webui";

type AdminSection = string;
type OrderedAdminNavItem = { id: AdminSection; label: string; order: number };

const handledAdminSectionIds = new Set<string>([
  "overview",
  "system-settings",
  "system-configuration-changes",
  "system-configuration-packages",
  "system-modules",
  "system-tenants",
  "system-roles",
  "system-role-templates",
  "system-groups",
  "system-users",
  "system-file-connectors",
  "system-mail-servers",
  "tenant-settings",
  "tenant-roles",
  "tenant-function-role-mappings",
  "tenant-groups",
  "tenant-users",
  "tenant-file-connectors",
  "tenant-mail-servers",
  "tenant-api-keys",
  "tenant-group-file-connectors",
  "tenant-group-mail-servers",
  "tenant-user-file-connectors",
  "tenant-user-mail-servers"
]);

export default function AdminPage({
  settings,
  auth,
  onAuthChange
}: {
  settings: ApiSettings;
  auth: AuthInfo;
  onAuthChange: (auth: AuthInfo | null, accessToken?: string) => void;
}) {
  const mailProfilesUi = usePlatformUiCapability<MailProfilesUiCapability>("mail.profiles");
  const fileConnectorsUi = usePlatformUiCapability<FilesConnectorsUiCapability>("files.connectors");
  const organizationFunctionPicker = usePlatformUiCapability<OrganizationFunctionPickerUiCapability>("organizations.functionPicker");
  const adminSectionCapabilities = usePlatformUiCapabilities<AdminSectionsUiCapability>("admin.sections");
  const mailProfilesAvailable = Boolean(mailProfilesUi);
  const fileConnectorsAvailable = Boolean(fileConnectorsUi);
  const contributedSections = useMemo(
    () =>
      adminSectionCapabilities
        .flatMap((capability) => capability.sections)
        .sort((left, right) => (left.order ?? 100) - (right.order ?? 100)),
    [adminSectionCapabilities]
  );
  const contributionById = useMemo(() => {
    const mapped = new Map<string, AdminSectionContribution>();
    for (const section of contributedSections) {
      if (!mapped.has(section.id)) mapped.set(section.id, section);
    }
    return mapped;
  }, [contributedSections]);

  const available = useMemo(() => {
    const sections = new Set<AdminSection>();
    for (const section of contributedSections) {
      if (canUseContributedSection(auth, section)) sections.add(section.id);
    }
    if (hasScope(auth, "system:settings:read")) {
      if (mailProfilesAvailable) sections.add("system-mail-servers");
    }
    if (hasScope(auth, "system:tenants:read")) sections.add("system-tenants");
    if (hasAnyScope(auth, ["system:accounts:read", "system:access:read"])) sections.add("system-users");
    if (hasAnyScope(auth, ["system:roles:read", "system:access:read"])) sections.add("system-roles");
    if (hasScope(auth, "admin:users:read")) sections.add("tenant-users");
    if (hasScope(auth, "admin:groups:read")) sections.add("tenant-groups");
    if (hasScope(auth, "admin:roles:read")) sections.add("tenant-roles");
    if (organizationFunctionPicker && hasAnyScope(auth, ["admin:roles:read", "access:function:read", "access:role:read"])) sections.add("tenant-function-role-mappings");
    if (hasScope(auth, "admin:api_keys:read")) sections.add("tenant-api-keys");
    if (mailProfilesAvailable && hasAnyScope(auth, ["mail_servers:read", "admin:policies:read"])) {
      sections.add("tenant-mail-servers");
      if (hasScope(auth, "admin:users:read")) sections.add("tenant-user-mail-servers");
      if (hasScope(auth, "admin:groups:read")) sections.add("tenant-group-mail-servers");
    }
    if (fileConnectorsAvailable && hasAnyScope(auth, ["files:file:admin", "admin:settings:read"])) {
      if (hasScope(auth, "admin:users:read")) sections.add("tenant-user-file-connectors");
      if (hasScope(auth, "admin:groups:read")) sections.add("tenant-group-file-connectors");
    }
    if (hasScope(auth, "admin:settings:read")) sections.add("tenant-settings");
    return sections;
  }, [auth, contributedSections, fileConnectorsAvailable, mailProfilesAvailable, organizationFunctionPicker]);
  const [searchParams, setSearchParams] = useSearchParams();
  const requestedSection = searchParams.get("section") as AdminSection | null;
  const fallbackSection = available.has("overview") ? "overview" : (Array.from(available)[0] ?? "overview");
  const active: AdminSection = requestedSection && available.has(requestedSection) ? requestedSection : fallbackSection;

  function selectSection(section: AdminSection) {
    const next = new URLSearchParams(searchParams);
    if (section === "overview") next.delete("section");
    else next.set("section", section);
    setSearchParams(next, { replace: true });
  }

  useEffect(() => {
    if (requestedSection && !available.has(requestedSection)) selectSection(fallbackSection);
  }, [requestedSection, available, fallbackSection]);

  async function refreshAuth() {
    onAuthChange(await fetchMe(settings));
  }

  useEffect(() => {
    void refreshAuth().catch(() => undefined);
  }, [settings.accessToken, settings.apiBaseUrl]);

  if (!hasAnyScope(auth, adminReadScopes)) {
    return (
      <div className="content-pad">
        <Card title="i18n:govoplan-access.administration_unavailable.b86d4cb5">
          <p>i18n:govoplan-access.your_current_roles_do_not_grant_administrative_a.6eafee69</p>
        </Card>
      </div>
    );
  }

  const adminSubnav: ModuleSubnavGroup<AdminSection>[] = [
    {
      title: "ADMINISTRATION",
      items: asSubnavItems(
        sortNavItems([
          ...contributedNavItems(contributedSections, available, "ROOT"),
          visibleNavItem(available, "system-modules", "i18n:govoplan-access.modules.04e9462c", 10),
          visibleNavItem(available, "system-configuration-packages", "i18n:govoplan-access.packages.0a999012", 20),
          visibleNavItem(available, "system-settings", "i18n:govoplan-access.maintenance.94de303b", 30),
          visibleNavItem(available, "system-configuration-changes", "i18n:govoplan-access.changes.8aa57de6", 40),
          ...contributedNavItems(contributedSections, available, "ADMINISTRATION", handledAdminSectionIds)
        ])
      )
    },
    {
      title: "GLOBAL",
      items: asSubnavItems(
        sortNavItems([
          visibleNavItem(available, "system-tenants", "i18n:govoplan-access.tenants.1f7ae776", 10),
          visibleNavItem(available, "system-roles", "i18n:govoplan-access.system_roles.a9461aa6", 20),
          visibleNavItem(available, "system-role-templates", "i18n:govoplan-access.tenant_role_templates", 30),
          visibleNavItem(available, "system-groups", "i18n:govoplan-access.group_templates", 40),
          visibleNavItem(available, "system-users", "i18n:govoplan-access.users.57f2b181", 50),
          visibleNavItem(available, "system-file-connectors", "i18n:govoplan-access.file_connections.1e362326", 60),
          visibleNavItem(available, "system-mail-servers", "i18n:govoplan-access.mail_servers.d627326a", 70),
          ...contributedNavItems(contributedSections, available, "GLOBAL", handledAdminSectionIds),
          ...contributedNavItems(contributedSections, available, "SYSTEM", handledAdminSectionIds)
        ])
      )
    },
    {
      title: "TENANT",
      items: asSubnavItems(
        sortNavItems([
          visibleNavItem(available, "tenant-roles", "i18n:govoplan-access.roles.47dcc27d", 10),
          visibleNavItem(available, "tenant-function-role-mappings", "i18n:govoplan-access.function_role_mappings.2b64e9c3", 20),
          visibleNavItem(available, "tenant-groups", "i18n:govoplan-access.groups.ae9629f4", 30),
          visibleNavItem(available, "tenant-users", "i18n:govoplan-access.users.57f2b181", 40),
          visibleNavItem(available, "tenant-file-connectors", "i18n:govoplan-access.file_connections.1e362326", 50),
          visibleNavItem(available, "tenant-mail-servers", "i18n:govoplan-access.mail_servers.d627326a", 60),
          visibleNavItem(available, "tenant-api-keys", "i18n:govoplan-access.api_keys.94fcf3c2", 70),
          visibleNavItem(available, "tenant-settings", "i18n:govoplan-access.general.9239ee2c", 90),
          ...contributedNavItems(contributedSections, available, "TENANT", handledAdminSectionIds)
        ])
      )
    },
    {
      title: "GROUP",
      items: asSubnavItems(
        sortNavItems([
          visibleNavItem(available, "tenant-group-file-connectors", "i18n:govoplan-access.file_connections.1e362326", 10),
          visibleNavItem(available, "tenant-group-mail-servers", "i18n:govoplan-access.mail_servers.d627326a", 20),
          ...contributedNavItems(contributedSections, available, "GROUP", handledAdminSectionIds)
        ])
      )
    },
    {
      title: "USER",
      items: asSubnavItems(
        sortNavItems([
          visibleNavItem(available, "tenant-user-file-connectors", "i18n:govoplan-access.file_connections.1e362326", 10),
          visibleNavItem(available, "tenant-user-mail-servers", "i18n:govoplan-access.mail_servers.d627326a", 20),
          ...contributedNavItems(contributedSections, available, "USER", handledAdminSectionIds)
        ])
      )
    }
  ].filter((group) => group.items.length > 0);
  const contributedSection = contributionById.get(active);
  const contributionContext = { settings, auth, onAuthChange, refreshAuth, availableSections: available, selectSection };

  return (
    <div className="workspace module-workspace">
      <ModuleSubnav active={active} groups={adminSubnav} onSelect={selectSection} />
      <section className="workspace-content">
        <div className="content-pad workspace-data-page">
          {contributedSection && contributedSection.render(contributionContext)}
          {!contributedSection && active === "system-mail-servers" && (
            <MailProfilesPanel settings={settings} scopeType="system" canWriteProfiles={hasScope(auth, "system:settings:write")} canManageCredentials={hasScope(auth, "system:settings:write")} canWritePolicy={hasScope(auth, "system:settings:write")} />
          )}
          {!contributedSection && active === "system-tenants" && (
            <TenantsPanel settings={settings} auth={auth} canCreate={hasScope(auth, "system:tenants:create")} canUpdate={hasScope(auth, "system:tenants:update")} canSuspend={hasScope(auth, "system:tenants:suspend")} onAuthRefresh={refreshAuth} />
          )}
          {!contributedSection && active === "system-users" && (
            <SystemUsersPanel
              settings={settings}
              canCreate={hasScope(auth, "system:accounts:create")}
              canUpdate={hasScope(auth, "system:accounts:update")}
              canSuspend={hasScope(auth, "system:accounts:suspend")}
              canAssignRoles={hasAnyScope(auth, ["system:roles:assign", "system:access:assign"])}
              canManageMemberships={hasScope(auth, "system:accounts:update") && hasScope(auth, "system:access:assign")}
              onAuthRefresh={refreshAuth}
            />
          )}
          {!contributedSection && active === "system-roles" && <SystemRolesPanel settings={settings} canWrite={hasScope(auth, "system:roles:write")} onAuthRefresh={refreshAuth} />}
          {!contributedSection && active === "tenant-users" && <UsersPanel settings={settings} auth={auth} canCreate={hasScope(auth, "admin:users:create")} canUpdate={hasScope(auth, "admin:users:update")} canSuspend={hasScope(auth, "admin:users:suspend")} canManageGroups={hasScope(auth, "admin:groups:manage_members")} canAssignRoles={hasScope(auth, "admin:roles:assign")} onAuthRefresh={refreshAuth} />}
          {!contributedSection && active === "tenant-groups" && <GroupsPanel settings={settings} auth={auth} canDefine={hasScope(auth, "admin:groups:write")} canManageMembers={hasScope(auth, "admin:groups:manage_members")} canAssignRoles={hasScope(auth, "admin:roles:assign")} onAuthRefresh={refreshAuth} />}
          {!contributedSection && active === "tenant-roles" && <RolesPanel settings={settings} auth={auth} canDefine={hasScope(auth, "admin:roles:write")} onAuthRefresh={refreshAuth} />}
          {!contributedSection && active === "tenant-function-role-mappings" && organizationFunctionPicker && <ExternalFunctionRoleMappingsPanel settings={settings} auth={auth} functionPicker={organizationFunctionPicker} canWrite={hasAnyScope(auth, ["admin:roles:write", "access:function:write", "access:role:assign"])} onAuthRefresh={refreshAuth} />}
          {!contributedSection && active === "tenant-api-keys" && <ApiKeysPanel settings={settings} auth={auth} canCreate={hasScope(auth, "admin:api_keys:create")} canRevoke={hasScope(auth, "admin:api_keys:revoke")} />}
          {!contributedSection && active === "tenant-mail-servers" && <MailProfilesPanel settings={settings} scopeType="tenant" canWriteProfiles={hasScope(auth, "mail_servers:write")} canManageCredentials={hasScope(auth, "mail_servers:manage_credentials")} canWritePolicy={hasScope(auth, "admin:policies:write")} />}
          {!contributedSection && active === "tenant-user-mail-servers" && <MailProfilesPanel settings={settings} scopeType="user" canWriteProfiles={hasScope(auth, "mail_servers:write")} canManageCredentials={hasScope(auth, "mail_servers:manage_credentials")} canWritePolicy={hasAnyScope(auth, ["admin:policies:write", "mail_servers:write"])} />}
          {!contributedSection && active === "tenant-group-mail-servers" && <MailProfilesPanel settings={settings} scopeType="group" canWriteProfiles={hasScope(auth, "mail_servers:write")} canManageCredentials={hasScope(auth, "mail_servers:manage_credentials")} canWritePolicy={hasAnyScope(auth, ["admin:policies:write", "mail_servers:write"])} />}
          {!contributedSection && active === "tenant-user-file-connectors" && <FileConnectorsPanel settings={settings} scopeType="user" canWrite={hasAnyScope(auth, ["files:file:admin", "admin:settings:write"])} />}
          {!contributedSection && active === "tenant-group-file-connectors" && <FileConnectorsPanel settings={settings} scopeType="group" canWrite={hasAnyScope(auth, ["files:file:admin", "admin:settings:write"])} />}
          {!contributedSection && active === "tenant-settings" && <TenantSettingsPanel settings={settings} canWrite={hasScope(auth, "admin:settings:write")} onAuthRefresh={refreshAuth} />}
        </div>
      </section>
    </div>
  );
}

function canUseContributedSection(auth: AuthInfo, section: AdminSectionContribution): boolean {
  if (section.allOf?.length && !section.allOf.every((scope) => hasScope(auth, scope))) return false;
  if (section.anyOf?.length && !hasAnyScope(auth, section.anyOf)) return false;
  return true;
}

function contributedNavItems(
  sections: AdminSectionContribution[],
  available: ReadonlySet<string>,
  group: string,
  excludedIds: ReadonlySet<string> = new Set()
): OrderedAdminNavItem[] {
  return sections
    .filter((section) => (section.group ?? "SYSTEM") === group && available.has(section.id) && !excludedIds.has(section.id))
    .map((section) => ({ id: section.id, label: section.label, order: section.order ?? 100 }));
}

function visibleNavItem(available: ReadonlySet<string>, id: AdminSection, label: string, order: number): OrderedAdminNavItem | null {
  return available.has(id) ? { id, label, order } : null;
}

function sortNavItems(items: Array<OrderedAdminNavItem | null>): OrderedAdminNavItem[] {
  return items.filter((item): item is OrderedAdminNavItem => item !== null).sort((left, right) => left.order - right.order);
}

function asSubnavItems(items: OrderedAdminNavItem[]) {
  return items.map(({ id, label }) => ({ id, label }));
}
