import { useEffect, useMemo, useRef, useState } from 'react';
import { AgCharts } from 'ag-charts-react';
import type { AgCartesianChartOptions } from 'ag-charts-community';
import { ModuleRegistry } from 'ag-charts-community';
import {
  AnnotationsModule,
  ContextMenuModule,
  CrosshairModule,
  LicenseManager,
  ZoomModule,
} from 'ag-charts-enterprise';
import { AG_CHARTS_LOCALE_ZH_CN } from 'ag-charts-locale';

LicenseManager.setLicenseKey('[v3][RELEASE][0102]_NDg2Njc4MzY3MDgzNw==16d78ca762fb5d2ff740aed081e2af7b');
ModuleRegistry.registerModules([AnnotationsModule, ContextMenuModule, ZoomModule, CrosshairModule]);

const API_BASE_URL = 'http://127.0.0.1:9089/api/v1';

const statisticOptions = [
  { key: 'minValue', label: '最低值', shortLabel: '低' },
  { key: 'maxValue', label: '最高值', shortLabel: '高' },
  { key: 'avgValue', label: '平均值', shortLabel: '均' },
  { key: 'medianValue', label: '中位数', shortLabel: '中' },
  { key: 'dataCount', label: '数据量', shortLabel: '量' },
] as const;

const metricOptions = [
  { key: 'cost', label: '造价（元）' },
  { key: 'buildingArea', label: '建筑面积指标（元/m²）' },
  { key: 'builtArea', label: '建造面积指标（元/m²）' },
  { key: 'usableArea', label: '使用面积指标（元/m²）' },
] as const;

type StatisticKey = (typeof statisticOptions)[number]['key'];
type MetricKey = (typeof metricOptions)[number]['key'];
type GroupKey = 'year';
type ApiBuildingFunctionStat = {
  group_key?: string | number | null;
  group_name?: string | null;
  min_value?: number | null;
  max_value?: number | null;
  avg_value?: number | null;
  median_value?: number | null;
  data_count?: number | null;
};
type ChartDatum = {
  groupName: string;
  minValue: number | null;
  maxValue: number | null;
  avgValue: number | null;
  medianValue: number | null;
  dataCount: number | null;
};

function formatWan(value: number) {
  return `${Math.round(value / 10000).toLocaleString('zh-CN')}万`;
}

function normalizeStat(row: ApiBuildingFunctionStat): ChartDatum {
  return {
    groupName: row.group_name || String(row.group_key ?? '未命名'),
    minValue: row.min_value ?? null,
    maxValue: row.max_value ?? null,
    avgValue: row.avg_value ?? null,
    medianValue: row.median_value ?? null,
    dataCount: row.data_count ?? null,
  };
}

function App() {
  const workspaceRef = useRef<HTMLElement>(null);
  const chartFrameRef = useRef<HTMLDivElement>(null);
  const [statisticKey, setStatisticKey] = useState<StatisticKey>('avgValue');
  const [metricKey, setMetricKey] = useState<MetricKey>('cost');
  const [groupKey, setGroupKey] = useState<GroupKey>('year');
  const [statisticMenuOpen, setStatisticMenuOpen] = useState(false);
  const [metricMenuOpen, setMetricMenuOpen] = useState(false);
  const [chartData, setChartData] = useState<ChartDatum[]>([]);
  const [loading, setLoading] = useState(true);
  const [loadError, setLoadError] = useState<string | null>(null);

  const selectedStatistic = statisticOptions.find((option) => option.key === statisticKey) ?? statisticOptions[0];
  const selectedMetric = metricOptions.find((option) => option.key === metricKey) ?? metricOptions[0];

  useEffect(() => {
    const controller = new AbortController();

    async function loadStats() {
      setLoading(true);
      setLoadError(null);
      try {
        const search = new URLSearchParams({
          groupBy: groupKey,
          metric: metricKey,
        });
        const response = await fetch(`${API_BASE_URL}/zw/getBuildingFunctionCostStats?${search.toString()}`, {
          signal: controller.signal,
        });
        if (!response.ok) {
          throw new Error(`HTTP ${response.status}`);
        }
        const payload = (await response.json()) as { data?: ApiBuildingFunctionStat[] };
        setChartData((payload.data ?? []).map(normalizeStat).slice(0, 36));
      } catch (error) {
        if (controller.signal.aborted) return;
        setLoadError(error instanceof Error ? error.message : '接口请求失败');
        setChartData([]);
      } finally {
        if (!controller.signal.aborted) {
          setLoading(false);
        }
      }
    }

    void loadStats();

    return () => {
      controller.abort();
    };
  }, [groupKey, metricKey]);

  useEffect(() => {
    const frame = chartFrameRef.current;
    const fullscreenTarget = workspaceRef.current;
    if (!frame || !fullscreenTarget) return;

    const getFullscreenButton = () => frame.querySelector<HTMLButtonElement>('.chart-fullscreen-button');
    const getStatisticButton = () => frame.querySelector<HTMLElement>('.ag-charts-myButton-statistic')?.closest<HTMLButtonElement>('.ag-charts-toolbar__button');

    const syncToolbarButtons = () => {
      const button = getFullscreenButton();
      if (button) {
        let icon = button.querySelector<HTMLElement>('.ag-charts-myButton-fullScreen');
        if (!icon) {
          button.innerHTML = '<i class="anticon anticon-arrow-salt ag-charts-myButton-fullScreen ag-charts-diy-button"></i>';
          icon = button.querySelector<HTMLElement>('.ag-charts-myButton-fullScreen');
        }

        const isFullscreen = document.fullscreenElement === fullscreenTarget;
        button.classList.toggle('ag-charts-toolbar__button--active', isFullscreen);
        icon?.classList.toggle('anticon-arrow-salt', !isFullscreen);
        icon?.classList.toggle('anticon-shrink', isFullscreen);
      }

      const statisticButton = getStatisticButton();
      if (statisticButton) {
        statisticButton.classList.add('chart-statistic-button');
      }
    };

    const toggleFullscreen = () => {
      if (document.fullscreenElement === fullscreenTarget) {
        void document.exitFullscreen();
      } else {
        void fullscreenTarget.requestFullscreen();
      }
    };

    const handleKeyDown = (event: KeyboardEvent) => {
      if (event.key !== 'F11') return;

      event.preventDefault();
      event.stopPropagation();
      toggleFullscreen();
    };

    const handleFullscreenChange = () => {
      syncToolbarButtons();
    };

    const handleToolbarClick = (event: MouseEvent) => {
      const target = event.target as Element | null;
      const button = target?.closest<HTMLButtonElement>(
        '.chart-fullscreen-button, .chart-statistic-button',
      );
      if (!button || !frame.contains(button)) return;

      event.preventDefault();
      event.stopPropagation();
      if (button.classList.contains('chart-statistic-button')) {
        setMetricMenuOpen(false);
        setStatisticMenuOpen((open) => !open);
      } else {
        toggleFullscreen();
      }
    };

    const handleToolbarKeyDown = (event: KeyboardEvent) => {
      if (event.key !== ' ' && event.key !== 'Enter') return;

      const target = event.target as Element | null;
      const button = target?.closest<HTMLButtonElement>(
        '.chart-fullscreen-button, .chart-statistic-button',
      );
      if (!button || !frame.contains(button)) return;

      event.preventDefault();
      event.stopPropagation();
      if (button.classList.contains('chart-statistic-button')) {
        setMetricMenuOpen(false);
        setStatisticMenuOpen((open) => !open);
      } else {
        toggleFullscreen();
      }
    };

    const suppressBrowserContextMenu = (event: MouseEvent) => {
      event.preventDefault();
    };

    const observer = new MutationObserver(syncToolbarButtons);
    document.addEventListener('keydown', handleKeyDown, true);
    document.addEventListener('fullscreenchange', handleFullscreenChange);
    document.addEventListener('contextmenu', suppressBrowserContextMenu);
    frame.addEventListener('contextmenu', suppressBrowserContextMenu);
    frame.addEventListener('click', handleToolbarClick, true);
    frame.addEventListener('keydown', handleToolbarKeyDown, true);
    observer.observe(frame, { childList: true, subtree: true });
    syncToolbarButtons();

    return () => {
      document.removeEventListener('keydown', handleKeyDown, true);
      document.removeEventListener('fullscreenchange', handleFullscreenChange);
      document.removeEventListener('contextmenu', suppressBrowserContextMenu);
      frame.removeEventListener('contextmenu', suppressBrowserContextMenu);
      frame.removeEventListener('click', handleToolbarClick, true);
      frame.removeEventListener('keydown', handleToolbarKeyDown, true);
      observer.disconnect();
    };
  }, []);

  const chartOptions = useMemo<AgCartesianChartOptions>(() => {
    const isCount = statisticKey === 'dataCount';
    const visibleData = chartData.map((datum) => ({
      groupName: datum.groupName,
      amount: datum[statisticKey],
    }));

    return {
      theme: {
        palette: {
          fills: ['#006f9b', '#ff7faa', '#00994d', '#ff8833', '#00a0dd'],
          strokes: ['#003f58', '#934962', '#004a25', '#914d1d', '#006288'],
        },
        params: {
          foregroundColor: '#262a33',
          backgroundColor: '#fff1e5',
          accentColor: '#0d7680',
          fontFamily: '"Microsoft YaHei", "PingFang SC", "Segoe UI", Arial, sans-serif',
          fontSize: 14,
          tooltipBackgroundColor: '#fff7ef',
          tooltipTextColor: '#262a33',
        },
      },
      locale: {
        localeText: AG_CHARTS_LOCALE_ZH_CN,
      },
      background: {
        fill: 'transparent',
      },
      padding: {
        top: 16,
        right: 16,
        bottom: 18,
        left: 24,
      },
      data: visibleData,
      zoom: {
        enabled: true,
        anchorPointX: 'pointer',
        anchorPointY: 'pointer',
        buttons: {
          enabled: true,
          visible: 'hover',
          buttons: [
            { icon: 'zoom-out', value: 'zoom-out', section: 'zoom', tooltip: '缩小' },
            { icon: 'zoom-in', value: 'zoom-in', section: 'zoom', tooltip: '放大' },
            { icon: 'pan-left', value: 'pan-left', section: 'pan', tooltip: '左移' },
            { icon: 'pan-right', value: 'pan-right', section: 'pan', tooltip: '右移' },
            { icon: 'reset', value: 'reset', section: 'reset', tooltip: '重置' },
          ],
        },
      },
      contextMenu: {
        enabled: true,
        items: ['defaults'],
      },
      annotations: {
        enabled: true,
        toolbar: {
          buttons: ([
            {
              value: 'statistic-select',
              tooltip: '切换统计指标',
              label: `<span class="ag-charts-myButton-statistic ag-charts-diy-button">${selectedStatistic.shortLabel}</span>`,
            },
            {
              icon: 'trend-line-drawing',
              value: 'line-menu',
              tooltip: 'Line Tool',
            },
            {
              icon: 'text-annotation',
              value: 'text-menu',
              tooltip: 'Text Tool',
            },
            {
              icon: 'arrow-drawing',
              value: 'shape-menu',
              tooltip: 'Shape Tool',
            },
            {
              icon: 'fibonacci-retracement-drawing',
              value: 'fibonacci-menu',
              tooltip: 'Fibonacci Tool',
            },
            {
              icon: 'delete',
              value: 'clear',
              tooltip: 'Clear annotations',
            },
          ] as unknown as NonNullable<NonNullable<AgCartesianChartOptions['annotations']>['toolbar']>['buttons']),
        },
      },
      series: [
        {
          type: 'line',
          xKey: 'groupName',
          yKey: 'amount',
          yName: `${selectedMetric.label} ${selectedStatistic.label}`,
          stroke: '#0078a8',
          strokeWidth: 2,
          marker: {
            enabled: true,
            fill: '#0078a8',
            stroke: '#0078a8',
            size: 5,
          },
          interpolation: {
            type: 'smooth',
          },
        },
      ],
      axes: {
        x: {
          type: 'category',
          position: 'bottom',
          line: {
            enabled: true,
            stroke: '#c8b9a7',
          },
          tick: {
            enabled: false,
          },
          label: {
            color: '#1f2933',
            fontSize: 12,
          },
          crosshair: {
            snap: false,
          },
        },
        y: {
          type: 'number',
          position: 'left',
          title: {
            text: '',
          },
          label: {
            color: '#1f2933',
            fontSize: 12,
            formatter: ({ value }) =>
              !isCount
                ? formatWan(Number(value))
                : Number(value).toLocaleString('zh-CN', {
                    minimumFractionDigits: 0,
                    maximumFractionDigits: 0,
                  }),
          },
          line: {
            enabled: false,
          },
          tick: {
            enabled: false,
          },
          gridLine: {
            enabled: true,
            style: [
              {
                stroke: '#e5d9ca',
                lineDash: [0],
              },
            ],
          },
          crosshair: {
            snap: false,
          },
        },
      },
      legend: {
        enabled: false,
      },
      tooltip: {
        enabled: true,
      },
    };
  }, [chartData, selectedMetric.label, selectedStatistic.label, statisticKey]);

  return (
    <main className="dashboard-shell">
      <div className="watermark-layer" aria-hidden="true">
        {Array.from({ length: 18 }).map((_, index) => (
          <span key={index}>众为数字化管理平台</span>
        ))}
      </div>

      <section className="workspace" aria-label="年度费用模板" ref={workspaceRef}>
        <section className="chart-area" aria-label="年度总费用图表">
          <div className="chart-frame" ref={chartFrameRef}>
            {statisticMenuOpen ? (
              <div className="statistic-switcher-menu" role="menu" aria-label="切换统计指标">
                {statisticOptions.map((option) => (
                  <button
                    className="statistic-switcher-menu-item"
                    type="button"
                    role="menuitem"
                    key={option.key}
                    aria-current={option.key === statisticKey}
                    onClick={() => {
                      setStatisticKey(option.key);
                      setStatisticMenuOpen(false);
                    }}
                  >
                    {option.label}
                  </button>
                ))}
              </div>
            ) : null}
            <div className="metric-switcher">
              <button
                className="metric-switcher-button"
                type="button"
                title="切换纵坐标指标"
                aria-expanded={metricMenuOpen}
                aria-haspopup="menu"
                aria-label={`纵坐标：${selectedMetric.label}`}
                onClick={() => {
                  setStatisticMenuOpen(false);
                  setMetricMenuOpen((open) => !open);
                }}
              >
                {selectedMetric.label}
              </button>
              {metricMenuOpen ? (
                <div className="metric-switcher-menu" role="menu" aria-label="切换纵坐标指标">
                  {metricOptions.map((option) => (
                    <button
                      className="metric-switcher-menu-item"
                      type="button"
                      role="menuitem"
                      key={option.key}
                      aria-current={option.key === metricKey}
                      onClick={() => {
                        setMetricKey(option.key);
                        setMetricMenuOpen(false);
                      }}
                    >
                      {option.label}
                    </button>
                  ))}
                </div>
              ) : null}
            </div>
            {loading || loadError ? <div className="chart-status">{loading ? '加载中' : loadError}</div> : null}
            <button className="chart-fullscreen-button ag-charts-toolbar__button" type="button" title="全屏(F11)">
              <i className="anticon anticon-arrow-salt ag-charts-myButton-fullScreen ag-charts-diy-button" />
            </button>
            <AgCharts options={chartOptions} />
          </div>
        </section>

        <aside className="right-placeholder" aria-label="右侧预留区域" />
      </section>
    </main>
  );
}

export default App;
