"use client";

import { toastApiError } from "@/lib/toast-api-error";
import * as React from "react";
import { resolveCustomerTenant } from "@/app/customer/_lib/resolve-customer-tenant";
import { useParams, useRouter, useSearchParams } from "next/navigation";
import { Save } from "lucide-react";
import { toast } from "sonner";

import { Button } from "@/components/ui/button";
import { Select, SelectContent, SelectItem, SelectTrigger, SelectValue } from "@/components/ui/select";
import { applyUiPrefsLocally, previewUiPrefsLocally } from "@/lib/preferences/apply-ui-prefs-locally";
import { PREFERENCE_DEFAULTS, type PreferenceValueMap } from "@/lib/preferences/preferences-config";
import { syncPreferenceCookies } from "@/lib/preferences/sync-preference-cookies";
import { usePreferencesStore } from "@/stores/preferences/preferences-provider";

import {
  assetAllocationBankOptions,
  assetAllocationClassOptions,
  assetAllocationCurrencyOptions,
  assetAllocationTypeOptions,
  defaultAssetAllocationFilters,
} from "@/app/customer/[tenant]/reports/asset-allocation/_components/asset-allocation-report/schema";
import {
  DEFAULT_USER_REPORT_SETTINGS,
  type UserReportSettings,
  loadUserReportSettings,
  saveUserReportSettings,
} from "@/lib/report-user-settings";

import { dispatchAumModeChanged } from "@/app/customer/_components/aum-mode-header-badge";
import { loadAumMode, updateAumMode, type AumCalcMode, type AumModeOption } from "../_lib/aum-mode-api";
import {
  loadCommonSettings,
  updateCommonSettings,
  type CommonSettingsCurrencyOption,
} from "../_lib/common-settings-api";
import {
  loadDashboardWidgetSettings,
  updateDashboardWidgetSettings,
} from "../_lib/dashboard-widgets-api";
import {
  loadUiPrefsClient,
  resetUiPrefsClient,
  updateUiPrefsClient,
} from "../_lib/ui-prefs-api";
import { isAllowedDashboardWidget } from "@/app/customer/_lib/dashboard-widget-allowlist";
import type {
  DashboardSettingsWidget,
  DashboardWidgetIsin,
} from "../_lib/dashboard-widgets-server-api";
import { SettingsPanelAppearance } from "./settings-panel-appearance";
import { SettingsPanelAssetAllocation } from "./settings-panel-asset-allocation";
import { SettingsPanelAssetAnalytics } from "./settings-panel-asset-analytics";
import { SettingsPanelAssetDefinition } from "./settings-panel-asset-definition";
import { SettingsPanelBenchmark } from "./settings-panel-benchmark";
import { SettingsPanelCommon } from "./settings-panel-common";
import { SettingsPanelDashboard } from "./settings-panel-dashboard";
import { SettingsPanelDrift } from "./settings-panel-drift";
import { SettingsPanelGeneral } from "./settings-panel-general";
import { SettingsPanelReportBanks } from "./settings-panel-report-banks";
import {
  DEFAULT_SETTINGS_SECTION,
  SETTINGS_SECTIONS,
  type SettingsSectionId,
  getSettingsSection,
  isSettingsSectionId,
} from "./settings-sections";
import {
  canAccessSettingsSection,
  filterAllowedSettingsSections,
  firstAllowedSettingsSectionId,
} from "../_lib/settings-section-permissions";

const subscribeToHydration = () => () => {};
const getClientHydrationSnapshot = () => true;
const getServerHydrationSnapshot = () => false;
const SELF_MANAGED_SECTIONS: SettingsSectionId[] = [
  "asset-definition",
  "drift",
  "report-banks",
  "benchmark",
];

export function SettingsView({ allowedRoutes }: { allowedRoutes: readonly string[] }) {
  const router = useRouter();
  const params = useParams<{ tenant?: string }>();
  const tenant = typeof params.tenant === "string" && params.tenant.trim() ? params.tenant.trim() : resolveCustomerTenant();
  const searchParams = useSearchParams();
  const sectionParam = searchParams.get("section");
  const allowedSections = React.useMemo(
    () => filterAllowedSettingsSections(SETTINGS_SECTIONS, allowedRoutes),
    [allowedRoutes],
  );
  const activeSection: SettingsSectionId = isSettingsSectionId(sectionParam)
    ? sectionParam
    : DEFAULT_SETTINGS_SECTION;

  const hydrated = React.useSyncExternalStore(
    subscribeToHydration,
    getClientHydrationSnapshot,
    getServerHydrationSnapshot,
  );
  const [draft, setDraft] = React.useState<UserReportSettings>(loadUserReportSettings);
  const [aumCalcMode, setAumCalcMode] = React.useState<AumCalcMode>("net");
  const [savedAumCalcMode, setSavedAumCalcMode] = React.useState<AumCalcMode>("net");
  const [aumModeOptions, setAumModeOptions] = React.useState<AumModeOption[]>([]);
  const [aumReadOnly, setAumReadOnly] = React.useState(false);
  const [aumLoading, setAumLoading] = React.useState(true);
  const [aumError, setAumError] = React.useState<string | null>(null);
  const [dashboardWidgets, setDashboardWidgets] = React.useState<DashboardSettingsWidget[]>([]);
  const [selectedWidgetIds, setSelectedWidgetIds] = React.useState<number[]>([]);
  const [widgetSelections, setWidgetSelections] = React.useState<Record<string, DashboardWidgetIsin[]>>({});
  const [dashboardLoaded, setDashboardLoaded] = React.useState(false);
  const [dashboardLoading, setDashboardLoading] = React.useState(false);
  const [dashboardError, setDashboardError] = React.useState<string | null>(null);
  const [dashboardConfigure, setDashboardConfigure] = React.useState<string | null>(() => {
    const configure = searchParams.get("configure");
    if (configure) return configure;
    // Legacy: tab=asset-widgets + #aaw-/#chw-/#diyw-
    if (typeof window !== "undefined") {
      const hash = window.location.hash.replace(/^#/, "");
      if (/^(?:aaw|chw|diyw)-\d+$/i.test(hash)) return hash;
    }
    return null;
  });
  const [commonOffset, setCommonOffset] = React.useState("");
  const [commonDefaultCurrency, setCommonDefaultCurrency] = React.useState("");
  const [commonHasDefaultCurrency, setCommonHasDefaultCurrency] = React.useState(true);
  const [commonCurrencies, setCommonCurrencies] = React.useState<CommonSettingsCurrencyOption[]>([]);
  const [commonLabels, setCommonLabels] = React.useState({
    offset1: "Offset",
    default_currency: "Default Currency",
  });
  const [commonLoaded, setCommonLoaded] = React.useState(false);
  const [commonLoading, setCommonLoading] = React.useState(false);
  const [commonError, setCommonError] = React.useState<string | null>(null);
  const [appearanceDraft, setAppearanceDraft] = React.useState<PreferenceValueMap>({ ...PREFERENCE_DEFAULTS });
  const [appearanceLoaded, setAppearanceLoaded] = React.useState(false);
  const [appearanceLoading, setAppearanceLoading] = React.useState(false);
  const [appearanceError, setAppearanceError] = React.useState<string | null>(null);
  const [isSaving, setIsSaving] = React.useState(false);
  const [isRestoringAppearance, setIsRestoringAppearance] = React.useState(false);

  const setThemeMode = usePreferencesStore((s) => s.setThemeMode);
  const setThemePreset = usePreferencesStore((s) => s.setThemePreset);
  const setFont = usePreferencesStore((s) => s.setFont);
  const setContentLayout = usePreferencesStore((s) => s.setContentLayout);
  const setNavbarStyle = usePreferencesStore((s) => s.setNavbarStyle);
  const setSidebarVariant = usePreferencesStore((s) => s.setSidebarVariant);
  const setSidebarCollapsible = usePreferencesStore((s) => s.setSidebarCollapsible);

  const applyAppearanceToApp = React.useCallback(
    (prefs: PreferenceValueMap) => {
      applyUiPrefsLocally(prefs);
      setThemeMode(prefs.theme_mode);
      setThemePreset(prefs.theme_preset);
      setFont(prefs.font);
      setContentLayout(prefs.content_layout);
      setNavbarStyle(prefs.navbar_style);
      setSidebarVariant(prefs.sidebar_variant);
      setSidebarCollapsible(prefs.sidebar_collapsible);
      void syncPreferenceCookies(prefs);
    },
    [
      setThemeMode,
      setThemePreset,
      setFont,
      setContentLayout,
      setNavbarStyle,
      setSidebarVariant,
      setSidebarCollapsible,
    ],
  );

  const clearDashboardConfigure = React.useCallback(() => {
    setDashboardConfigure(null);
  }, []);

  React.useEffect(() => {
    const configure = searchParams.get("configure");
    if (configure) {
      setDashboardConfigure(configure);
      return;
    }
    const hash = typeof window !== "undefined" ? window.location.hash.replace(/^#/, "") : "";
    if (/^(?:aaw|chw|diyw)-\d+$/i.test(hash)) {
      setDashboardConfigure(hash);
    }
  }, [searchParams]);

  const reloadDashboardWidgets = React.useCallback(async () => {
    setDashboardLoading(true);
    setDashboardError(null);
    try {
      const data = await loadDashboardWidgetSettings(tenant);
      const allowed = data.widgets.filter((widget) =>
        isAllowedDashboardWidget(widget.file_path, widget.name),
      );
      const allowedIds = new Set(allowed.map((widget) => widget.widget_id));
      setDashboardWidgets(allowed);
      setSelectedWidgetIds(data.selected_widget_ids.filter((id) => allowedIds.has(id)));
      setWidgetSelections(
        Object.fromEntries(
          allowed
            .filter((widget) => widget.requires_isin_selection)
            .map((widget) => [String(widget.widget_id), widget.isin_selection]),
        ),
      );
      setDashboardLoaded(true);
    } catch (error) {
      setDashboardError(
        error instanceof Error ? error.message : "Dashboard settings could not be loaded.",
      );
    } finally {
      setDashboardLoading(false);
    }
  }, [tenant]);

  React.useEffect(() => {
    let cancelled = false;

    async function load() {
      setAumLoading(true);
      setAumError(null);
      try {
        const result = await loadAumMode();
        if (cancelled) return;
        setAumCalcMode(result.aumCalcMode);
        setSavedAumCalcMode(result.aumCalcMode);
        setAumModeOptions(result.modeOptions);
        setAumReadOnly(result.isReadOnly);
      } catch (error) {
        if (cancelled) return;
        setAumError(error instanceof Error ? error.message : "AUM mode settings could not be loaded.");
      } finally {
        if (!cancelled) setAumLoading(false);
      }
    }

    void load();
    return () => {
      cancelled = true;
    };
  }, []);

  React.useEffect(() => {
    if (activeSection !== "common" || commonLoaded) return;
    let cancelled = false;

    async function load() {
      setCommonLoading(true);
      setCommonError(null);
      try {
        const data = await loadCommonSettings();
        if (cancelled) return;
        setCommonOffset(data.offset1);
        setCommonDefaultCurrency(data.defaultCurrency);
        setCommonHasDefaultCurrency(data.hasDefaultCurrency);
        setCommonCurrencies(data.currencies);
        setCommonLabels(data.labels);
        setCommonLoaded(true);
      } catch (error) {
        if (!cancelled) {
          setCommonError(error instanceof Error ? error.message : "Common settings could not be loaded.");
        }
      } finally {
        if (!cancelled) setCommonLoading(false);
      }
    }

    void load();
    return () => {
      cancelled = true;
    };
  }, [activeSection, commonLoaded]);

  React.useEffect(() => {
    if (activeSection !== "appearance" || appearanceLoaded) return;
    let cancelled = false;

    async function load() {
      setAppearanceLoading(true);
      setAppearanceError(null);
      try {
        const prefs = await loadUiPrefsClient();
        if (cancelled) return;
        setAppearanceDraft(prefs);
        setAppearanceLoaded(true);
      } catch (error) {
        if (!cancelled) {
          setAppearanceError(
            error instanceof Error ? error.message : "Appearance settings could not be loaded.",
          );
        }
      } finally {
        if (!cancelled) setAppearanceLoading(false);
      }
    }

    void load();
    return () => {
      cancelled = true;
    };
  }, [activeSection, appearanceLoaded]);

  React.useEffect(() => {
    if (activeSection !== "dashboard" || dashboardLoaded) return;
    let cancelled = false;

    async function load() {
      setDashboardLoading(true);
      setDashboardError(null);
      try {
        const data = await loadDashboardWidgetSettings(tenant);
        if (cancelled) return;
        const allowed = data.widgets.filter((widget) =>
          isAllowedDashboardWidget(widget.file_path, widget.name),
        );
        const allowedIds = new Set(allowed.map((widget) => widget.widget_id));
        setDashboardWidgets(allowed);
        setSelectedWidgetIds(
          data.selected_widget_ids.filter((id) => allowedIds.has(id)),
        );
        setWidgetSelections(
          Object.fromEntries(
            allowed
              .filter((widget) => widget.requires_isin_selection)
              .map((widget) => [String(widget.widget_id), widget.isin_selection]),
          ),
        );
        setDashboardLoaded(true);
      } catch (error) {
        if (!cancelled) {
          setDashboardError(error instanceof Error ? error.message : "Dashboard settings could not be loaded.");
        }
      } finally {
        if (!cancelled) setDashboardLoading(false);
      }
    }

    void load();
    return () => {
      cancelled = true;
    };
  }, [activeSection, dashboardLoaded, tenant]);

  const handleRestoreAppearance = async () => {
    setIsRestoringAppearance(true);
    try {
      const prefs = await resetUiPrefsClient();
      setAppearanceDraft(prefs);
      applyAppearanceToApp(prefs);
      toast.success("Appearance defaults restored");
    } catch (error) {
      toastApiError(error, "Unable to restore appearance defaults.");
    } finally {
      setIsRestoringAppearance(false);
    }
  };

  const handleSave = async () => {
    if (activeSection === "appearance") {
      setIsSaving(true);
      try {
        const prefs = await updateUiPrefsClient(appearanceDraft);
        setAppearanceDraft(prefs);
        applyAppearanceToApp(prefs);
        toast.success("Appearance settings saved");
      } catch (error) {
        toastApiError(error, "Unable to save appearance settings.");
      } finally {
        setIsSaving(false);
      }
      return;
    }

    if (activeSection === "common") {
      if (!commonOffset.trim()) {
        toast.error("Offset is required.");
        return;
      }
      if (commonHasDefaultCurrency && !commonDefaultCurrency.trim()) {
        toast.error("Default Currency is required.");
        return;
      }
      setIsSaving(true);
      try {
        const data = await updateCommonSettings({
          offset1: commonOffset.trim(),
          defaultCurrency: commonDefaultCurrency,
        });
        setCommonOffset(data.offset1);
        setCommonDefaultCurrency(data.defaultCurrency);
        setCommonHasDefaultCurrency(data.hasDefaultCurrency);
        setCommonCurrencies(data.currencies);
        setCommonLabels(data.labels);
        toast.success("Your form has been successfully saved!");
      } catch (error) {
        toastApiError(error, "Unable to save common settings.");
      } finally {
        setIsSaving(false);
      }
      return;
    }

    if (activeSection === "dashboard") {
      setIsSaving(true);
      try {
        const data = await updateDashboardWidgetSettings(tenant, selectedWidgetIds, widgetSelections);
        const allowed = data.widgets.filter((widget) =>
          isAllowedDashboardWidget(widget.file_path, widget.name),
        );
        const allowedIds = new Set(allowed.map((widget) => widget.widget_id));
        setDashboardWidgets(allowed);
        setSelectedWidgetIds(
          data.selected_widget_ids.filter((id) => allowedIds.has(id)),
        );
        setWidgetSelections(
          Object.fromEntries(
            allowed
              .filter((widget) => widget.requires_isin_selection)
              .map((widget) => [String(widget.widget_id), widget.isin_selection]),
          ),
        );
        toast.success("Dashboard settings saved");
      } catch (error) {
        toastApiError(error, "Unable to save dashboard settings.");
      } finally {
        setIsSaving(false);
      }
      return;
    }

    const next: UserReportSettings = {
      defaultAnalyticsTicker: draft.defaultAnalyticsTicker || DEFAULT_USER_REPORT_SETTINGS.defaultAnalyticsTicker,
      assetAllocation: {
        ...draft.assetAllocation,
        banks:
          draft.assetAllocation.banks.length === 0
            ? [...assetAllocationBankOptions]
            : draft.assetAllocation.banks,
        currencies:
          draft.assetAllocation.currencies.length === 0
            ? [...assetAllocationCurrencyOptions]
            : draft.assetAllocation.currencies,
        assetClasses:
          draft.assetAllocation.assetClasses.length === 0
            ? [...assetAllocationClassOptions]
            : draft.assetAllocation.assetClasses,
        assetTypes:
          draft.assetAllocation.assetTypes.length === 0
            ? [...assetAllocationTypeOptions]
            : draft.assetAllocation.assetTypes,
      },
    };
    saveUserReportSettings(next);
    setDraft(next);

    if (aumCalcMode !== savedAumCalcMode && !aumReadOnly) {
      setIsSaving(true);
      try {
        const result = await updateAumMode(aumCalcMode);
        setAumCalcMode(result.aumCalcMode);
        setSavedAumCalcMode(result.aumCalcMode);
        setAumModeOptions(result.modeOptions);
        setAumReadOnly(result.isReadOnly);
        dispatchAumModeChanged(result.aumCalcMode);
        toast.success("Settings saved");
      } catch (error) {
        toastApiError(error, "Unable to save AUM calculation mode.");
      } finally {
        setIsSaving(false);
      }
      return;
    }

    toast.success("Settings saved");
  };

  const section = getSettingsSection(activeSection);
  const sectionHref = (id: SettingsSectionId) => `/customer/${tenant}/settings?section=${id}`;
  const canViewActiveSection = canAccessSettingsSection(activeSection, allowedRoutes);

  React.useEffect(() => {
    if (!canAccessSettingsSection(activeSection, allowedRoutes)) {
      const fallback = firstAllowedSettingsSectionId(allowedRoutes);
      if (fallback) {
        router.replace(sectionHref(fallback), { scroll: false });
      }
    }
  }, [activeSection, allowedRoutes, router, tenant]);

  if (!hydrated) {
    return (
      <div className="flex min-h-48 items-center justify-center text-muted-foreground text-sm">Loading settings…</div>
    );
  }

  return (
    <div className="flex min-w-0 flex-col">
      <div className="border-b px-4 py-3 lg:hidden">
        <Select
          value={activeSection}
          onValueChange={(value) => router.replace(sectionHref(value as SettingsSectionId), { scroll: false })}
        >
          <SelectTrigger className="h-9 w-full max-w-sm bg-background">
            <SelectValue />
          </SelectTrigger>
          <SelectContent>
            {allowedSections.map((item) => (
              <SelectItem key={item.id} value={item.id}>
                {item.label}
              </SelectItem>
            ))}
          </SelectContent>
        </Select>
      </div>

      <div className="flex-1 overflow-y-auto px-4 py-5 sm:px-6 sm:py-6">
        <header className="mb-6 border-b border-border/60 pb-5">
          <h1 className="font-semibold text-2xl tracking-tight">{section.label}</h1>
          <p className="mt-1.5 max-w-2xl text-muted-foreground text-sm leading-relaxed">{section.description}</p>
        </header>

        {canViewActiveSection ? null : (
          <p className="text-muted-foreground text-sm">You do not have permission to view this settings section.</p>
        )}

        {canViewActiveSection && activeSection === "general" ? (
          <SettingsPanelGeneral
            aumCalcMode={aumCalcMode}
            modeOptions={aumModeOptions}
            isReadOnly={aumReadOnly}
            isLoading={aumLoading}
            errorMessage={aumError}
            onAumModeChange={setAumCalcMode}
          />
        ) : null}
        {canViewActiveSection && activeSection === "common" ? (
          <SettingsPanelCommon
            offset1={commonOffset}
            defaultCurrency={commonDefaultCurrency}
            hasDefaultCurrency={commonHasDefaultCurrency}
            currencies={commonCurrencies}
            labels={commonLabels}
            isLoading={commonLoading}
            errorMessage={commonError}
            onOffsetChange={setCommonOffset}
            onDefaultCurrencyChange={setCommonDefaultCurrency}
          />
        ) : null}
        {canViewActiveSection && activeSection === "appearance" ? (
          <div className="space-y-5">
            <SettingsPanelAppearance
              draft={appearanceDraft}
              isLoading={appearanceLoading}
              errorMessage={appearanceError}
              onChange={(patch) => {
                setAppearanceDraft((prev) => {
                  const next = { ...prev, ...patch };
                  // Preview only — cookies/DB update on Save / Restore Defaults.
                  previewUiPrefsLocally(next);
                  return next;
                });
              }}
            />
            <Button
              type="button"
              variant="outline"
              disabled={isRestoringAppearance || appearanceLoading || isSaving}
              onClick={() => void handleRestoreAppearance()}
            >
              {isRestoringAppearance ? "Restoring…" : "Restore Defaults"}
            </Button>
          </div>
        ) : null}
        {canViewActiveSection && activeSection === "dashboard" ? (
          <SettingsPanelDashboard
            tenant={tenant}
            widgets={dashboardWidgets}
            selectedWidgetIds={selectedWidgetIds}
            widgetSelections={widgetSelections}
            isLoading={dashboardLoading}
            errorMessage={dashboardError}
            initialConfigure={dashboardConfigure}
            onSelectedWidgetIdsChange={setSelectedWidgetIds}
            onWidgetSelectionsChange={setWidgetSelections}
            onWidgetsChanged={() => void reloadDashboardWidgets()}
            onConfigureConsumed={clearDashboardConfigure}
          />
        ) : null}
        {canViewActiveSection && activeSection === "asset-definition" ? (
          <SettingsPanelAssetDefinition tenant={tenant} />
        ) : null}
        {canViewActiveSection && activeSection === "drift" ? <SettingsPanelDrift tenant={tenant} /> : null}
        {canViewActiveSection && activeSection === "report-banks" ? (
          <SettingsPanelReportBanks tenant={tenant} />
        ) : null}
        {canViewActiveSection && activeSection === "benchmark" ? (
          <SettingsPanelBenchmark tenant={tenant} />
        ) : null}
        {canViewActiveSection && activeSection === "asset-analytics" ? (
          <SettingsPanelAssetAnalytics
            draft={draft}
            tenant={tenant}
            onChange={(patch) => setDraft((prev) => ({ ...prev, ...patch }))}
          />
        ) : null}
        {canViewActiveSection && activeSection === "asset-allocation" ? (
          <SettingsPanelAssetAllocation
            draft={draft}
            tenant={tenant}
            onAllocationChange={(assetAllocation) => setDraft((prev) => ({ ...prev, assetAllocation }))}
            onReset={() =>
              setDraft((prev) => ({
                ...prev,
                assetAllocation: defaultAssetAllocationFilters,
              }))
            }
          />
        ) : null}
      </div>

      <footer className="flex shrink-0 flex-wrap items-center justify-end gap-3 border-t px-4 py-4 sm:px-6">
        <p className="mr-auto hidden text-muted-foreground text-xs sm:block">
          {activeSection === "general"
            ? "AUM mode is saved for this tenant and applies to report totals"
            : activeSection === "common"
              ? "Offset and default currency are saved for this user account"
            : activeSection === "appearance"
              ? "Theme and layout preferences are saved for your account"
            : activeSection === "dashboard"
              ? "Widget choices are saved for this dashboard account. Use Configure for widget-specific options."
            : SELF_MANAGED_SECTIONS.includes(activeSection)
              ? "Use the actions inside this section to save changes"
            : "Report defaults are saved in this browser"}
        </p>
        {!SELF_MANAGED_SECTIONS.includes(activeSection) ? (
          <Button
            onClick={() => void handleSave()}
            disabled={
              isSaving ||
              isRestoringAppearance ||
              (activeSection === "general" && aumLoading) ||
              (activeSection === "common" && commonLoading) ||
              (activeSection === "appearance" && appearanceLoading) ||
              (activeSection === "dashboard" && dashboardLoading)
            }
            className="gap-2"
          >
            <Save className="size-4" />
            {isSaving ? "Saving…" : "Save changes"}
          </Button>
        ) : null}
      </footer>
    </div>
  );
}
