// 社交 BI v2 Shell：深色侧栏（视图导航）+ 顶栏全局筛选（日期/App/区域/粒度），
// 视图组件通过 useSocialBi() 消费统一的筛选状态与数据派生结果。

import { createContext, useCallback, useContext, useEffect, useMemo, useRef, useState } from "react";
import AccountTreeOutlined from "@mui/icons-material/AccountTreeOutlined";
import GroupsOutlined from "@mui/icons-material/GroupsOutlined";
import InsightsOutlined from "@mui/icons-material/InsightsOutlined";
import PublicOutlined from "@mui/icons-material/PublicOutlined";
import RefreshOutlined from "@mui/icons-material/RefreshOutlined";
import RepeatOutlined from "@mui/icons-material/RepeatOutlined";
import TableChartOutlined from "@mui/icons-material/TableChartOutlined";
import Autocomplete from "@mui/material/Autocomplete";
import TextField from "@mui/material/TextField";
import {
  ALL,
  DATE_PRESETS,
  GRANULARITIES,
  createDefaultFilters,
  createDefaultTableState,
  rangeLabel,
  readStateFromURL,
  toggleMultiValue,
  writeStateToURL
} from "./state.js";
import { TimeRangeFilter } from "@/shared/ui/TimeRangeFilter.jsx";
import { AppIdentity } from "@/shared/ui/AppIdentity.jsx";
import { SOCIAL_BI_FUNNEL_APP_CODES, useSocialBiData } from "./useSocialBiData.js";
import { OverviewView } from "./views/OverviewView.jsx";
import { RegionsView } from "./views/RegionsView.jsx";
import { TeamKpiView } from "./views/TeamKpiView.jsx";
import { RetentionView } from "./views/RetentionView.jsx";
import { DataTableView } from "./views/DataTableView.jsx";
import { FunnelView } from "./views/FunnelView.jsx";
import "../styles/social-v2.css";

const VIEWS = [
  { component: OverviewView, icon: InsightsOutlined, key: "overview", label: "经营概览" },
  { component: RegionsView, icon: PublicOutlined, key: "regions", label: "地区洞察" },
  { component: TeamKpiView, icon: GroupsOutlined, key: "team", label: "运营中心" },
  { component: RetentionView, icon: RepeatOutlined, key: "retention", label: "留存质量" },
  { component: DataTableView, icon: TableChartOutlined, key: "table", label: "数据明细" },
  { component: FunnelView, icon: AccountTreeOutlined, key: "funnel", label: "埋点漏斗" }
];

const SocialBiContext = createContext(null);
const EMPTY_OPERATORS = [];

export function useSocialBi() {
  const context = useContext(SocialBiContext);
  if (!context) {
    throw new Error("useSocialBi must be used inside SocialBiApp");
  }
  return context;
}

// Social BI 的统计结果只携带 app_code/app_name；Logo 从 master 目录按 app_code 回填，保证所有视图使用同一份品牌事实。
export function SocialAppIdentity({ app, appCode, appName, className = "", size = "small" }) {
  const context = useSocialBi();
  const resolvedCode = String(app?.app_code || app?.appCode || appCode || "").trim().toLowerCase();
  const catalogApp = (context.master?.apps || []).find((item) => String(item.app_code || item.appCode || "").trim().toLowerCase() === resolvedCode);
  return <AppIdentity app={catalogApp || app} appCode={resolvedCode} appName={appName} className={className} size={size} />;
}

export function SocialBiApp() {
  const initial = useMemo(() => readStateFromURL(), []);
  const [filters, setFilters] = useState(initial.filters);
  const [tableState, setTableState] = useState(() => initial.table || createDefaultTableState());
  const [viewKey, setViewKey] = useState(() => (VIEWS.some((view) => view.key === initial.view) ? initial.view : "overview"));
  const data = useSocialBiData(filters, {
    includeFunnel: viewKey === "funnel",
    includeKpi: viewKey === "team"
  });

  useEffect(() => {
    writeStateToURL(filters, viewKey, tableState);
  }, [filters, tableState, viewKey]);

  const updateFilter = useCallback((key, value) => {
    setFilters((current) => ({ ...current, [key]: value }));
  }, []);

  const resetFilters = useCallback(() => {
    setFilters(createDefaultFilters());
  }, []);

  const updateTableState = useCallback((patch) => {
    setTableState((current) => ({ ...current, ...patch }));
  }, []);

  const openRequirementSection = useCallback((requirementSection) => {
    // 下钻必须同时设置明细模式和业务分组，否则 DataTableView 会按默认值落回“运营宽表 / 充值”。
    setTableState({ mode: "requirements", requirementSection });
    setViewKey("table");
  }, []);

  const contextValue = useMemo(
    () => ({ ...data, filters, openRequirementSection, resetFilters, setViewKey, tableState, updateFilter, updateTableState, viewKey }),
    [data, filters, openRequirementSection, resetFilters, tableState, updateFilter, updateTableState, viewKey]
  );

  const ActiveView = (VIEWS.find((view) => view.key === viewKey) || VIEWS[0]).component;

  return (
    <SocialBiContext.Provider value={contextValue}>
      <div className="sbi-shell">
        <Sidebar data={data} onViewChange={setViewKey} viewKey={viewKey} />
        <div className="sbi-main">
          <TopBar data={data} filters={filters} updateFilter={updateFilter} viewKey={viewKey} />
          {data.errors.length ? (
            <div className="sbi-error-banner" role="alert">
              {data.errors.map((message, index) => (
                <span key={`${index}-${message}`}>{message}</span>
              ))}
            </div>
          ) : null}
          <main className="sbi-view" aria-label="Social BI 数据中心">
            <ActiveView />
          </main>
        </div>
      </div>
    </SocialBiContext.Provider>
  );
}

function Sidebar({ data, onViewChange, viewKey }) {
  const access = data.master?.access;
  const scopeLabel = !data.master ? "" : access?.all ? "全量数据范围" : `负责 ${access?.scopes?.length || 0} 个 App/区域`;
  return (
    <aside className="sbi-sidebar" aria-label="Social BI 导航">
      <div className="sbi-brand">
        <span className="sbi-brand-mark">HY</span>
        <div className="sbi-brand-copy">
          <strong>运营数据总览</strong>
        </div>
      </div>
      <nav className="sbi-nav" role="tablist" aria-label="数据视图">
        {VIEWS.map((view) => {
          const Icon = view.icon;
          const isActive = viewKey === view.key;
          return (
            <button
              aria-selected={isActive}
              className={isActive ? "sbi-nav-item is-active" : "sbi-nav-item"}
              key={view.key}
              onClick={() => onViewChange(view.key)}
              role="tab"
              type="button"
            >
              <Icon fontSize="small" />
              <span>{view.label}</span>
            </button>
          );
        })}
      </nav>
      {scopeLabel ? (
        <div className="sbi-scope-badge" title="数据按你的负责范围裁剪，可在用户管理里调整">
          <span className="sbi-scope-dot" />
          {scopeLabel}
        </div>
      ) : null}
    </aside>
  );
}

function TopBar({ data, filters, updateFilter, viewKey }) {
  return (
    <header className="sbi-topbar">
      <div className="sbi-topbar-row">
        <DatePresetControl filters={filters} updateFilter={updateFilter} />
        <GranularityControl filters={filters} updateFilter={updateFilter} />
        <button className="sbi-refresh" onClick={data.refresh} title="刷新数据" type="button">
          <RefreshOutlined fontSize="small" />
        </button>
      </div>
      <div className="sbi-topbar-row">
        <AppChips data={data} filters={filters} updateFilter={updateFilter} viewKey={viewKey} />
        <RegionSelect data={data} filters={filters} updateFilter={updateFilter} />
        {viewKey === "team" ? <OperatorSelect data={data} filters={filters} updateFilter={updateFilter} /> : null}
        <span className="sbi-range-label">{rangeLabel(data.range)}</span>
        {data.isLoading ? <span className="sbi-loading-dot" aria-label="加载中" /> : null}
      </div>
    </header>
  );
}

function operatorIdentityLabel(operator) {
  if (String(operator?.user_id) === ALL) {
    return "全部运营人员";
  }
  return operator?.name || operator?.account || `#${operator?.user_id}`;
}

function filterOperatorOptions(options, { inputValue }) {
  const keyword = String(inputValue || "").trim().toLowerCase();
  if (!keyword) {
    return options;
  }
  return options.filter((operator) =>
    [operatorIdentityLabel(operator), operator.account, operator.team, operator.user_id]
      .filter(Boolean)
      .join(" ")
      .toLowerCase()
      .includes(keyword)
  );
}

function OperatorSelect({ data, filters, updateFilter }) {
  const operators = data.master?.operators || EMPTY_OPERATORS;
  const options = useMemo(() => [{ name: "全部运营人员", user_id: ALL }, ...operators], [operators]);
  const selected = options.find((operator) => String(operator.user_id) === String(filters.operator)) || options[0];

  useEffect(() => {
    if (!data.master || filters.operator === ALL) {
      return;
    }
    // 人员离职或数据权限收回后，旧分享链接里的 ID 会失效；回退到全部，避免页面显示一个无法解释的空筛选。
    if (!operators.some((operator) => String(operator.user_id) === String(filters.operator))) {
      updateFilter("operator", ALL);
    }
  }, [data.master, filters.operator, operators, updateFilter]);

  return (
    <Autocomplete
      className="sbi-operator-filter"
      disableClearable
      disablePortal
      filterOptions={filterOperatorOptions}
      getOptionLabel={operatorIdentityLabel}
      isOptionEqualToValue={(option, value) => String(option.user_id) === String(value.user_id)}
      noOptionsText="无匹配运营人员"
      options={options}
      size="small"
      value={selected}
      onChange={(_, operator) => updateFilter("operator", String(operator?.user_id || ALL))}
      renderOption={(props, operator) => {
        const { key, ...optionProps } = props;
        const details = [operator.account, operator.team].filter(Boolean).join(" · ");
        return (
          <li {...optionProps} className={`${optionProps.className || ""} sbi-operator-option`} key={key || operator.user_id}>
            <strong>{operatorIdentityLabel(operator)}</strong>
            {details ? <small>{details}</small> : null}
          </li>
        );
      }}
      renderInput={(params) => (
        <TextField
          {...params}
          label="运营人员"
          slotProps={{
            ...params.slotProps,
            htmlInput: {
              ...params.slotProps?.htmlInput,
              "aria-label": "运营人员筛选"
            }
          }}
        />
      )}
    />
  );
}

function DatePresetControl({ filters, updateFilter }) {
  return (
    <div className="sbi-date-presets" role="radiogroup" aria-label="日期区间">
      {DATE_PRESETS.map((preset) => (
        <button
          aria-checked={filters.preset === preset.key}
          className={filters.preset === preset.key ? "is-active" : ""}
          key={preset.key}
          onClick={() => updateFilter("preset", preset.key)}
          role="radio"
          type="button"
        >
          {preset.label}
        </button>
      ))}
      {filters.preset === "custom" ? (
        <TimeRangeFilter
          className="sbi-custom-range"
          label="自定义区间"
          value={{ endMs: dayTextToEndMs(filters.customEnd), startMs: dayTextToStartMs(filters.customStart) }}
          withTime={false}
          onChange={(range) => {
            updateFilter("customStart", msToDayText(range.startMs));
            updateFilter("customEnd", msToDayText(range.endMs));
          }}
        />
      ) : null}
    </div>
  );
}

// 自定义区间在筛选状态里以天字符串（YYYY-MM-DD）存储，选择器以本地时区毫秒交互，这里做双向换算。
function parseDayText(value) {
  const match = /^(\d{4})-(\d{2})-(\d{2})$/.exec(String(value || ""));
  return match ? { day: Number(match[3]), month: Number(match[2]), year: Number(match[1]) } : null;
}

function dayTextToStartMs(dayText) {
  const parts = parseDayText(dayText);
  return parts ? new Date(parts.year, parts.month - 1, parts.day, 0, 0, 0, 0).getTime() : "";
}

function dayTextToEndMs(dayText) {
  const parts = parseDayText(dayText);
  return parts ? new Date(parts.year, parts.month - 1, parts.day, 23, 59, 59, 999).getTime() : "";
}

function msToDayText(ms) {
  if (!ms) {
    return "";
  }
  const date = new Date(Number(ms));
  const pad = (value) => String(value).padStart(2, "0");
  return `${date.getFullYear()}-${pad(date.getMonth() + 1)}-${pad(date.getDate())}`;
}

function GranularityControl({ filters, updateFilter }) {
  return (
    <div className="sbi-granularity" role="radiogroup" aria-label="趋势粒度">
      {GRANULARITIES.map((item) => (
        <button
          aria-checked={filters.granularity === item.key}
          className={filters.granularity === item.key ? "is-active" : ""}
          key={item.key}
          onClick={() => updateFilter("granularity", item.key)}
          role="radio"
          type="button"
        >
          {item.label}
        </button>
      ))}
    </div>
  );
}

function AppChips({ data, filters, updateFilter, viewKey }) {
  const apps = viewKey === "funnel"
    ? (data.master?.apps || []).filter((app) => SOCIAL_BI_FUNNEL_APP_CODES.includes(app.app_code))
    : data.master?.apps || [];
  const allCodes = apps.map((app) => app.app_code);
  const hasSelectedVisibleApp = filters.apps.some((appCode) => allCodes.includes(appCode));
  const isAll = filters.apps.includes(ALL) || (viewKey === "funnel" && !hasSelectedVisibleApp);
  return (
    <div className="sbi-app-chips" role="group" aria-label="App 筛选">
      <button
        aria-pressed={isAll}
        className={isAll ? "sbi-chip is-active" : "sbi-chip"}
        onClick={() => updateFilter("apps", [ALL])}
        type="button"
      >
        {viewKey === "funnel" ? "全部漏斗 App" : "全部 App"}
      </button>
      {apps.map((app) => {
        const selected = !isAll && filters.apps.includes(app.app_code);
        return (
          <button
            aria-pressed={selected}
            className={selected ? "sbi-chip is-active" : "sbi-chip"}
            key={app.app_code}
            onClick={() => updateFilter("apps", toggleMultiValue(filters.apps, app.app_code, allCodes))}
            type="button"
          >
            <AppIdentity app={app} size="small" />
          </button>
        );
      })}
    </div>
  );
}

function RegionSelect({ data, filters, updateFilter }) {
  const [isOpen, setIsOpen] = useState(false);
  const containerRef = useRef(null);
  const apps = data.master?.apps || [];
  const regions = data.master?.regions || [];
  const groups = apps
    .map((app) => ({
      app,
      regions: regions.filter((region) => region.app_code === app.app_code)
    }))
    .filter((group) => group.regions.length);

  useEffect(() => {
    const handlePointerDown = (event) => {
      if (!containerRef.current?.contains(event.target)) {
        setIsOpen(false);
      }
    };
    document.addEventListener("pointerdown", handlePointerDown);
    return () => document.removeEventListener("pointerdown", handlePointerDown);
  }, []);

  const selectedCount = filters.regions.includes(ALL) ? 0 : filters.regions.length;
  return (
    <div className="sbi-region-select" ref={containerRef}>
      <button aria-expanded={isOpen} className="sbi-region-trigger" onClick={() => setIsOpen((open) => !open)} type="button">
        地区：{selectedCount ? `已选 ${selectedCount} 项` : "全部"}
      </button>
      {isOpen ? (
        <div className="sbi-region-menu" role="listbox" aria-label="地区筛选">
          <button
            className={filters.regions.includes(ALL) ? "sbi-region-option is-active" : "sbi-region-option"}
            onClick={() => updateFilter("regions", [ALL])}
            type="button"
          >
            全部地区
          </button>
          {groups.map((group) => (
            <div className="sbi-region-group" key={group.app.app_code}>
              <button
                className={
                  filters.regions.includes(`app:${group.app.app_code}`) ? "sbi-region-option is-group is-active" : "sbi-region-option is-group"
                }
                onClick={() => updateFilter("regions", toggleMultiValue(filters.regions, `app:${group.app.app_code}`))}
                type="button"
              >
                <AppIdentity app={group.app} size="small" />
                <span>全部区域</span>
              </button>
              {group.regions.map((region) => {
                const value = `${region.app_code}:${region.region_id}`;
                return (
                  <button
                    className={filters.regions.includes(value) ? "sbi-region-option is-active" : "sbi-region-option"}
                    key={value}
                    onClick={() => updateFilter("regions", toggleMultiValue(filters.regions, value))}
                    type="button"
                  >
                    {region.region_name || region.region_code}
                  </button>
                );
              })}
            </div>
          ))}
          {!groups.length ? <p className="sbi-region-empty">暂无区域目录</p> : null}
        </div>
      ) : null}
    </div>
  );
}
